Dienste im Kubernetes Cluster mit Keycloak und OAuth schützen

Ziel des Artikels ist es, die notwendigen Schritte zum Absichern eines Dienstes im Kubernetes Clusters mittels OAuth zu dokumentieren.

Keycloak installieren

Als Identity Provider kommt Keycloak zum Einsatz.

Basierend https://www.openshift.com/blog/adding-authentication-to-your-kubernetes-web-applications-with-keycloak

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
helm repo add codecentric https://codecentric.github.io/helm-charts
curl https://raw.githubusercontent.com/codecentric/helm-charts/master/charts/keycloak/values.yaml -o values.yaml
patch <<EOF
--- values.yaml.sav 2020-04-23 07:29:12.280000000 +0200
+++ values.yaml 2020-04-23 07:34:18.212000000 +0200
@@ -240,12 +240,12 @@ keycloak:
## Ingress configuration.
## ref: https://kubernetes.io/docs/user-guide/ingress/
ingress:
- enabled: false
+ enabled: true
path: /

- annotations: {}
- # kubernetes.io/ingress.class: nginx
- # kubernetes.io/tls-acme: "true"
+ annotations:
+ kubernetes.io/ingress.class: nginx
+ kubernetes.io/tls-acme: "true"
# ingress.kubernetes.io/affinity: cookie

labels: {}
@@ -253,13 +253,13 @@ keycloak:

## List of hosts for the ingress
hosts:
- - keycloak.example.com
+ - xxx.mydomain.com

## TLS configuration
- tls: []
- # - hosts:
- # - keycloak.example.com
- # secretName: tls-keycloak
+ tls:
+ - hosts:
+ - xxx.mydomain.com
+ secretName: tls-keycloak

## OpenShift route configuration.
## ref: https://docs.openshift.com/container-platform/3.11/architecture/networking/routes.html
@@ -287,10 +287,10 @@ keycloak:
## Persistence configuration
persistence:
# If true, the Postgres chart is deployed
- deployPostgres: false
+ deployPostgres: true

# The database vendor. Can be either "postgres", "mysql", "mariadb", or "h2"
- dbVendor: h2
+ dbVendor: postgres

## The following values only apply if "deployPostgres" is set to "false"
dbName: keycloak
EOF
kubectl create namespace keycloak
helm upgrade -i -n keycloak keycloak codecentric/keycloak -f values.yaml

Keycloak konfigurieren

Basierend auf https://kubernetes.github.io/ingress-nginx/examples/auth/oauth-external-auth/ und https://oauth2-proxy.github.io/oauth2-proxy/auth-configuration#keycloak-auth-provider

  • Neuen Realm anlegen, z.B. local
  • Neuen Client anlegen, z.B. k8s-ingress
    • Access Type auf confidential
    • Valid redirect URL auf https://*
    • Credentials -> Secret notieren
    • Neuen Mapper anlegen per Create:
      • Name groups
      • Mapper Type Group Membership
      • Token Claim Name groups
  • Neue Gruppe anlegen, z.B. admin
  • Neuen User anlegen
    • Email eintragen
    • Email bestätigen
    • Gruppe beitreten
    • bei Bedarf OTP aktivieren
    • Credentials setzen

Dienst anpassen und schützen

Am Beispiel Kubernetes Dashboard:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
cat <<EOF > enable-oauth.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/use-port-in-redirects: "true"
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"
name: dashboard
namespace: kube-dashboard
spec:
tls:
- hosts:
- xxx.mydomain.com
secretName: xxx.mydomain.com-tls
rules:
- host: xxx.mydomain.com
http:
paths:
- backend:
serviceName: kubernetes-dashboard
servicePort: 8443
path: /
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: oauth2-proxy
namespace: kube-dashboard
spec:
rules:
- host: xxx.mydomain.com
http:
paths:
- backend:
serviceName: oauth2-proxy
servicePort: 4180
path: /oauth2
tls:
- hosts:
- xxx.mydomain.com
secretName: xxx.mydomain.com-tls
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: oauth2-proxy
name: oauth2-proxy
namespace: kube-dashboard
spec:
replicas: 1
selector:
matchLabels:
k8s-app: oauth2-proxy
template:
metadata:
labels:
k8s-app: oauth2-proxy
spec:
containers:
- args:
- --provider=keycloak
- --client-id=k8s-ingress
- --client-secret=5e656d5b-xxxx-xxxx-8845-xxxxxxxxxxxx
- --login-url=https://keycloak.mydomain.com/auth/realms/local/protocol/openid-connect/auth
- --redeem-url=https://keycloak.mydomain.com/auth/realms/local/protocol/openid-connect/token
- --validate-url=https://keycloak.mydomain.com/auth/realms/local/protocol/openid-connect/userinfo
- --keycloak-group=/admin
- --email-domain=*
- --http-address=0.0.0.0:4180
# Register a new application
# https://github.com/settings/applications/new
env:
# docker run -ti --rm python:3-alpine python -c 'import secrets,base64; print(base64.b64encode(base64.b64encode(secrets.token_bytes(16))));'
- name: OAUTH2_PROXY_COOKIE_SECRET
value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
image: quay.io/pusher/oauth2_proxy:latest
imagePullPolicy: Always
name: oauth2-proxy
ports:
- containerPort: 4180
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: oauth2-proxy
name: oauth2-proxy
namespace: kube-dashboard
spec:
ports:
- name: http
port: 4180
protocol: TCP
targetPort: 4180
selector:
k8s-app: oauth2-proxy
EOF