Kubernetes Dashboard mit Keycloak OIDC: Unterschied zwischen den Versionen
KKeine Bearbeitungszusammenfassung |
KKeine Bearbeitungszusammenfassung |
||
(27 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
{{Infobox | |||
| Titel = Testumgebung | |||
| Bildname = | |||
| Bildbreite = | |||
| Bildtext = | |||
| Stil = 2 | |||
| Titelfarbe = 6 | |||
| Abschnittsfarbe = | |||
| Farbe = | |||
| Style = | |||
| Feldstyle = | |||
| Feldname1 = OS | Daten1 = AlmaLinux 8.7 | |||
| Feldname2 = Keycloak | Daten2 = 20.0.2 | |||
| Feldname3 = Kubernetes | Daten3 = 1.26.0 | |||
| Feldname4 = MetalLB | Daten4 = 0.13.7 | |||
| Feldname5 = Ingress-Nginx | Daten5 = 1.5.1 | |||
| Feldname6 = OAUTH2-Proxy | Daten6 = 7.4.0 | |||
}} | |||
=== API-Server konfigurieren === | === API-Server konfigurieren === | ||
<syntaxhighlight lang="bash"> | |||
vi /etc/kubernetes/manifests/kube-apiserver.yaml | |||
</syntaxhighlight><syntaxhighlight lang="yaml" line="1"> | |||
spec: | spec: | ||
containers: | containers: | ||
Zeile 19: | Zeile 36: | ||
'''Hinweis:''' | '''Hinweis:''' | ||
''Wenn <code>oidc-username-claim</code> NICHT 'email' ist, wird standardmäßig die 'issuer-url' als | ''Wenn <code>oidc-username-claim</code> '''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 | ''Um den Präfix zu deaktivieren muss bei <code>oidc-username-prefix</code> der Wert '-' angegeben werden.'' | ||
=== Load Balancer installieren === | === Load Balancer installieren === | ||
'# MetalLB installieren / Aktiviert den Service Typ "LoadBalancer" der sonst nur in Cloud Umgebungen verfügbar ist | '# 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 ==== | ==== Ports in der Firewall öffnen ==== | ||
<syntaxhighlight lang="bash"> | Sowohl auf dem Controller als auch den Worker-Nodes<syntaxhighlight lang="bash"> | ||
firewall-cmd --permanent --add-port=7472/tcp | |||
firewall-cmd --permanent --add-port=7946/tcp | firewall-cmd --permanent --add-port=7946/tcp | ||
firewall-cmd --permanent --add-port=7946/udp | firewall-cmd --permanent --add-port=7946/udp | ||
firewall-cmd --reload | firewall-cmd --reload | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Installieren ==== | |||
<syntaxhighlight lang="bash"> | |||
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml | kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml | ||
</syntaxhighlight>address_pool.yaml<syntaxhighlight lang="yaml" line="1"> | </syntaxhighlight> | ||
address_pool.yaml | |||
<syntaxhighlight lang="yaml" line="1"> | |||
apiVersion: metallb.io/v1beta1 | apiVersion: metallb.io/v1beta1 | ||
kind: IPAddressPool | kind: IPAddressPool | ||
Zeile 61: | Zeile 85: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Reverse Proxy installieren === | === Reverse Proxy installieren (ingress-nginx) === | ||
Reverse | Reverse Proxy um mehrere Domains auf einer IP erreichbar zu machen. | ||
values.yaml<syntaxhighlight lang="yaml" line="1"> | values.yaml | ||
<syntaxhighlight lang="yaml" line="1"> | |||
controller: | controller: | ||
config: | config: | ||
proxy-buffer-size: " | proxy-buffer-size: "8k" | ||
</syntaxhighlight>Wenn | |||
#extraArgs: | |||
#default-ssl-certificate: "default/my-tls-secret" | |||
</syntaxhighlight>'''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 <code>default-ssl-certificate</code> 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: | |||
<syntaxhighlight lang="bash"> | |||
helm upgrade --install ingress-nginx ingress-nginx \ | helm upgrade --install ingress-nginx ingress-nginx \ | ||
--repo https://kubernetes.github.io/ingress-nginx \ | --repo https://kubernetes.github.io/ingress-nginx \ | ||
Zeile 76: | Zeile 128: | ||
=== OAUTH2 Proxy installieren === | |||
Authentifizierung gegen Keyclok und Token Weiterleitung an Dashboard | |||
values.yaml | |||
<syntaxhighlight lang="yaml" line="1"> | |||
values.yaml<syntaxhighlight lang="yaml" line="1"> | |||
extraArgs: | extraArgs: | ||
provider: keycloak-oidc | provider: keycloak-oidc | ||
Zeile 102: | Zeile 152: | ||
cookie-refresh: 4m # Zeit nach der ein neuer Access Token über den Refresh Token bezogen wird | 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>" | oidc-issuer-url: "https://<my.keycloak.server>/realms/<Realm-Name>" | ||
redirect-url: "https://<my. | redirect-url: "https://<my.dashboard.url>/oauth2/callback" | ||
#whitelist-domain: ["*"] | #whitelist-domain: ["*"] | ||
#allowed-group: ["*"] | #allowed-group: ["*"] | ||
Zeile 112: | Zeile 162: | ||
''Der Parameter <code>cookie-refresh</code> sollte kleiner als die "Access Token Lifespan" in Keycloak sein ("Realm Settings->Token").'' | ''Der Parameter <code>cookie-refresh</code> sollte kleiner als die "Access Token Lifespan" in Keycloak sein ("Realm Settings->Token").'' | ||
Installation starten: | |||
<syntaxhighlight lang="bash"> | |||
helm upgrade --install oauth2-proxy oauth2-proxy \ | helm upgrade --install oauth2-proxy oauth2-proxy \ | ||
--repo https://oauth2-proxy.github.io/manifests \ | --repo https://oauth2-proxy.github.io/manifests \ | ||
--namespace kubernetes-dashboard \ | --namespace kubernetes-dashboard \ | ||
-f values.yaml | -f values.yaml | ||
</syntaxhighlight>'' | </syntaxhighlight> | ||
===Dem Keycloak Benutzer die Admin Rolle zuweisen=== | |||
oidc-role.yaml | |||
<syntaxhighlight lang="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 | |||
</syntaxhighlight>'''''Hinweis:''''' | |||
''Der Benutzername (subjects.name) entspricht dem'' <code>oidc-username-claim</code> ''aus der "kube-apiserver.yaml".'' | |||
<syntaxhighlight lang="bash"> | |||
kubectl apply -f oidc-role.yaml | |||
</syntaxhighlight> | |||
===Ingress erstellen=== | |||
<syntaxhighlight lang="yaml" line="1"> | |||
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 | |||
</syntaxhighlight><syntaxhighlight lang="bash"> | |||
kubectl apply -f ingress.yaml | |||
</syntaxhighlight> |
Aktuelle Version vom 7. Januar 2023, 23:52 Uhr
Testumgebung | |
---|---|
OS | AlmaLinux 8.7 |
Keycloak | 20.0.2 |
Kubernetes | 1.26.0 |
MetalLB | 0.13.7 |
Ingress-Nginx | 1.5.1 |
OAUTH2-Proxy | 7.4.0 |
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