Dienste im Kubernetes Cluster mit Keycloak und OAuth schützen

Dienste im Kubernetes Cluster mit Keycloak und OAuth schützen
Inhaltsverzeichnis

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

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:

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