Kubernetes Dashboard mit Keycloak OIDC

=== API-Server konfigurieren ===
vi /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
 containers:
 - command:
 - kube-apiserver
... 
	- --oidc-issuer-url=https://<my.keycloak.server>/realms/<Realm-Name>
 - --oidc-client-id=k8s-cluster
 - --oidc-username-claim=email
 #- --oidc-ca-file=/path/to/oidc-ca.pem
	#- --oidc-username-prefix=-
Hinweis:
Wenn oidc-username-claim NICHT 'email' ist, wird standardmäßig die 'issuer-url' als Präfix vor den Benutzer gestellt (z.B. https://<my.keycloak.server>/realms/<Realm-Name>:<username>).
Um den Präfix zu deaktivieren muss bei oidc-username-prefix der Wert '-' angegeben werden.
=== Load Balancer installieren ===
'# MetalLB installieren / Aktiviert den Service Typ "LoadBalancer" der sonst nur in Cloud Umgebungen verfügbar ist
'# Bildet IPs aus dem Cluster in einen physischen Adressbereich des LANs
==== Ports in der Firewall öffnen ====
Sowohl auf dem Controller als auch den Worker-Nodes
firewall-cmd --permanent --add-port=7472/tcp
firewall-cmd --permanent --add-port=7946/tcp
firewall-cmd --permanent --add-port=7946/udp
firewall-cmd --reload
==== Installieren ====
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml
address_pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
 name: first-pool
 namespace: metallb-system
spec:
 addresses:
 - 192.168.1.240-192.168.1.250
l2_advert.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
 name: example
 namespace: metallb-system
 #- first-pool
IPAddressPools können explizit ausgewählt werden. Ohne Angabe werden alle Pools dem L2Advertisement zugeordnet.
kubectl apply -f address_pool.yaml
kubectl apply -f l2_advert.yaml
=== Reverse Proxy installieren (ingress-nginx) ===
Reverse Proxy um mehrere Domains auf einer IP erreichbar zu machen.
values.yaml
controller:
 config:
 proxy-buffer-size: "8k"
 
 #extraArgs:
 #default-ssl-certificate: "default/my-tls-secret"
Hinweise:
Bei Keycloak kann es vorkommen, dass mehr als 4 kb Daten über den Header gesendet werden.
Wenn der Header zu groß wird, bekommt man einen Fehler (502). 
Deswegen erhöhen wir diesen direkt während der Installation auf 8 kb.
Für TLS benötigen wir ein 'Secret" mit dem "Privat Key" und dem "Public Certificate" für die Domain, die später für das Dashboard genutzt werden soll.
Dieses kann man als Standard, direkt in der Config für Ingress-Nginx hinerlegen oder später im Ingress definieren.
Tipp:
Wenn man bei default-ssl-certificate ein Wildcard-Zertifikat (z.B. *.my-cluster.host) für den Cluster hinterlegt, 
kann für jeden Ingress einfach eine Sub-Domain vergeben, die dann automatisch ein gültiges Zertifikat hat.
Installation starten:
helm upgrade --install ingress-nginx ingress-nginx \
 --repo https://kubernetes.github.io/ingress-nginx \
 --namespace ingress-nginx --create-namespace \
 -f values.yaml
=== OAUTH2 Proxy installieren ===
Authentifizierung gegen Keyclok und Token Weiterleitung an Dashboard
values.yaml
extraArgs:
 provider: keycloak-oidc
 #provider-display-name: OIDC Login
 #http-address: "0.0.0.0:4180"
 #skip-provider-button: true
 #skip-jwt-bearer-tokens: true
 #ssl-insecure-skip-verify: true
 #ssl-upstream-insecure-skip-verify: true
 #pass-access-token: true
 #pass-authorization-header: true
 set-authorization-header: true
 #set-xauthrequest: true
 client-id: XXX # Change XXX to your client_id
 client-secret: XXX # Change XXX to your client_secret
 cookie-secret: XXX # Generate with 'openssl rand -base64 32 | head -c 32 | base64'
 #cookie-secure: false
 #cookie-httponly: false
 cookie-refresh: 4m # Zeit nach der ein neuer Access Token über den Refresh Token bezogen wird
 oidc-issuer-url: "https://<my.keycloak.server>/realms/<Realm-Name>"
 redirect-url: "https://<my.dashboard.url>/oauth2/callback"
 #whitelist-domain: ["*"]
 #allowed-group: ["*"]
 #allowed-role: ["*"]
 #email-domain: ["*"]
Hinweis:
Der Parameter cookie-refresh sollte kleiner als die "Access Token Lifespan" in Keycloak sein ("Realm Settings->Token").
Installation starten:
helm upgrade --install oauth2-proxy oauth2-proxy \
 --repo https://oauth2-proxy.github.io/manifests \
 --namespace kubernetes-dashboard \
 -f values.yaml
===Dem Keycloak Benutzer die Admin Rolle zuweisen===
oidc-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
 name: oidc-user
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: cluster-admin
subjects:
- kind: User
 name: user@keycloak.com
 namespace: kube-system
Hinweis:
Der Benutzername (subjects.name) entspricht dem oidc-username-claim aus der "kube-apiserver.yaml".
kubectl apply -f oidc-role.yaml
===Ingress erstellen===
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 annotations:
 nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
 nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
 nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
 nginx.ingress.kubernetes.io/auth-response-headers: "authorization"
 name: k8s-dashboard
 namespace: kubernetes-dashboard
spec:
 ingressClassName: nginx
 tls:
 - hosts:
 - my.dashboard.url
 rules:
 - host: my.dashboard.url
 http:
 paths:
 - backend:
 service:
 name: kubernetes-dashboard
 port:
 number: 443
 path: /
 pathType: Prefix
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: k8s-dashboard-oauth
 namespace: oauth2-proxy
spec:
 ingressClassName: nginx
 tls:
 - hosts:
 - my.dashboard.url
 rules:
 - host: my.dashboard.url
 http:
 paths:
 - backend:
 service:
 name: oauth2-proxy
 port:
 number: 80
 path: /oauth2
 pathType: Prefix
kubectl apply -f ingress.yaml