问题描述
我能够使用 Istio 网关 和 AWS HTTPS 应用程序负载均衡器在 AWS K3S Kubernetes 集群上成功启动 keycloak 服务器。
我可以成功看到Keycloak Home Page: https://keycloak.skycomposer.net/auth/
但是当我点击管理控制台链接时,会显示空白页: https://keycloak.skycomposer.net/auth/admin/master/console/
浏览器检查工具表明: http://keycloak.skycomposer.net/auth/js/keycloak.js?version=rk826 链接返回以下状态:
(blocked:mixed-content)
我在互联网上做了一些研究,原因似乎与从 https 到 http 的重定向有关,istio 网关没有正确处理 和 aws 负载均衡器
这是我的配置文件:
keycloak-config.yaml:
apiVersion: v1
kind: ConfigMap
Metadata:
name: keycloak
data:
KEYCLOAK_USER: admin@keycloak
KEYCLOAK_MGMT_USER: mgmt@keycloak
JAVA_OPTS_APPEND: '-Djboss.http.port=8080'
PROXY_ADDRESS_FORWARDING: 'true'
KEYCLOAK_HOSTNAME: 'keycloak.skycomposer.net'
KEYCLOAK_FRONTEND_URL: 'https://keycloak.skycomposer.net/auth'
KEYCLOAK_LOGLEVEL: INFO
ROOT_LOGLEVEL: INFO
DB_vendOR: H2
keycloak-deployment.yaml:
kind: Deployment
apiVersion: apps/v1
Metadata:
name: keycloak
labels:
app: keycloak
spec:
replicas: 1
selector:
matchLabels:
app: keycloak
template:
Metadata:
labels:
app: keycloak
annotations:
sidecar.istio.io/rewriteAppHTTPProbers: "true"
spec:
containers:
- name: keycloak
image: jboss/keycloak:13.0.1
imagePullPolicy: Always
ports:
- containerPort: 8080
hostPort: 8080
volumeMounts:
- name: keycloak-data
mountPath: /opt/jboss/keycloak/standalone/data
env:
- name: KEYCLOAK_USER
valueFrom:
configMapKeyRef:
name: keycloak
key: KEYCLOAK_USER
- name: KEYCLOAK_MGMT_USER
valueFrom:
configMapKeyRef:
name: keycloak
key: KEYCLOAK_MGMT_USER
- name: JAVA_OPTS_APPEND
valueFrom:
configMapKeyRef:
name: keycloak
key: JAVA_OPTS_APPEND
- name: DB_vendOR
valueFrom:
configMapKeyRef:
name: keycloak
key: DB_vendOR
- name: PROXY_ADDRESS_FORWARDING
valueFrom:
configMapKeyRef:
name: keycloak
key: PROXY_ADDRESS_FORWARDING
- name: KEYCLOAK_HOSTNAME
valueFrom:
configMapKeyRef:
name: keycloak
key: KEYCLOAK_HOSTNAME
- name: KEYCLOAK_FRONTEND_URL
valueFrom:
configMapKeyRef:
name: keycloak
key: KEYCLOAK_FRONTEND_URL
- name: KEYCLOAK_LOGLEVEL
valueFrom:
configMapKeyRef:
name: keycloak
key: KEYCLOAK_LOGLEVEL
- name: ROOT_LOGLEVEL
valueFrom:
configMapKeyRef:
name: keycloak
key: ROOT_LOGLEVEL
- name: KEYCLOAK_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak
key: KEYCLOAK_PASSWORD
- name: KEYCLOAK_MGMT_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak
key: KEYCLOAK_MGMT_PASSWORD
volumes:
- name: keycloak-data
persistentVolumeClaim:
claimName: keycloak-pvc
keycloak-service.yaml:
apiVersion: v1
kind: Service
Metadata:
name: keycloak
spec:
ports:
- protocol: TCP
name: http
port: 80
targetPort: 8080
selector:
app: keycloak
istio-gateway.yaml:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
Metadata:
name: istio-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "keycloak.skycomposer.net"
istio-virtualservice.yaml:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
Metadata:
name: keycloak
spec:
hosts:
- keycloak.skycomposer.net
gateways:
- istio-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
host: keycloak.default.svc.cluster.local
port:
number: 80
我使用 istioctl 成功安装了 istio 1.9.1:
istioctl install \
--set meshConfig.accessLogFile=/dev/stdout \
--skip-confirmation
另外,我用 istio injection 标记了默认命名空间,所以我在默认命名空间中的所有 pod 都有 istio sidecar 容器:
kubectl label namespace default istio-injection=enabled
NAME READY STATUS RESTARTS AGE
whoami-6c4757bbb5-9zkbl 2/2 Running 0 13m
notification-microservice-5dfcf96b95-ll8lm 2/2 Running 0 13m
customermgmt-6b48586868-ddlnw 2/2 Running 0 13m
usermgmt-c5b65964-df2vc 2/2 Running 0 13m
keycloak-d48f9bbbf-tsm5h 2/2 Running 0 13m
resource "aws_lb" "mtc_lb" {
name = "mtc-loadbalancer"
subnets = var.public_subnets
security_groups = [var.public_sg]
idle_timeout = 400
}
resource "aws_lb_target_group" "mtc_tg" {
name = "mtc-lb-tg-${substr(uuid(),3)}"
port = var.tg_port
protocol = var.tg_protocol
vpc_id = var.vpc_id
lifecycle {
create_before_destroy = true
ignore_changes = [name]
}
health_check {
healthy_threshold = var.elb_healthy_threshold
unhealthy_threshold = var.elb_unhealthy_threshold
timeout = var.elb_timeout
interval = var.elb_interval
}
}
resource "aws_lb_listener" "mtc_lb_listener_http" {
load_balancer_arn = aws_lb.mtc_lb.arn
port = 80
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
resource "aws_lb_listener" "mtc_lb_listener" {
load_balancer_arn = aws_lb.mtc_lb.arn
port = 443
protocol = "HTTPS"
depends_on = [aws_lb_target_group.mtc_tg]
certificate_arn = var.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.mtc_tg.arn
}
}
解决方法
调查请求头,我终于找到了问题的原因。
默认情况下,此标头始终为“http”:
X-Forwarded-Proto: http
将值更改为:
X-Forwarded-Proto: https
解决了这个问题。
以下是 Istio Virtual Service 的示例,它将“X-Forwarded-Proto”请求标头设置为“https”请求:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: keycloak
spec:
hosts:
- keycloak.skycomposer.net
gateways:
- istio-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
host: keycloak.default.svc.cluster.local
port:
number: 80
headers:
request:
set:
x-forwarded-proto: https
附言理想的解决方案是在 AWS Application Load Balancer 中设置此值,但我不确定如何使用 aws 负载均衡器的 terraform 配置,所以我决定在 Istio Virtual Service 级别解决它。