KeyCloak im K3S Kubernetes Cluster aufsetzen

KeyCloak mit WebAuthn

Ziel dieser Reihe soll es werden Anwendungen über WebAuthn zu schützen. Dazu wird ein K3S Cluster mit K3D aufgesetzt. Diese soll über .cluster.local erreichbar sein.

  • Im Ersten Teil beschäftige ich mich mit der Installation einer KeyCloak Instanz in einem K3S Cluster.

  • Im zweiten Teil wird die Demoanwendung (Gitea) deployt

  • Im dritte Teil geht es um die Konfiguration von KeyCloak, sodass die Anwendung von WebAuthn gescchützt wird

K3D Setup

Um den Cluster aufzusetzen werde ich K3D verwenden.

K3D installieren

Die Installation habe ich für Manjaro/Arch Linux bereits in dem Artikel K3D Cluster ausfsetzen beschrieben. Anmerkung: Die aktuelle Version kann nun mit yay bereits aus AUR gezogen werden.

K3D Cluster erstellen

Für diese Reihe erstelle ich einen kleinen Demo Cluster mit 2 Knoten und öffne den Port 8080 für den LoadBalancer. D.h. der NginX Reverse Proxy muss später auf den Host und Port 8080 verweisen, so dass die Anfragen vom KeyCloak dann beantwortet werden können.

k3d cluster create demo -a2 -p 8080:80@loadbalancer -p 8443:443@loadbalancer

Achtung: Die Syntax von K3D hat sich seit Version 3.0.0 geändert und folgt nun den anderen K8S Anwendungen, in dem es Nomen und Verb als Parameter verlangt. Bsp: aus k3d create cluster wurde nun k3d cluster create.

Namespace

Wie immer sollte mna einen eigenen Namespace für die Trennung der Anwendung verwenden. Diesen legen wir zuerst mit:

k create namespace keycloak

an.

Hinweis: K ist bei mir immer ein Alias für kubectl.

Self Signed Certificate ausstellen

Installation Cert-Manager

Die Installation von Cert-Manager wird hier beschrieben.

Selbst Signiertes Zertifikat ausstellen

Zunächst müssen wir ein Manifest erstellen, das einen Issuer und ein Certificate beschreibt. Die Domain wird hier auf *.clouster.local festgelegt.

apiVersion: cert-manager.io/v1alpha2 
kind: Issuer
metadata:
   name: selfsigned-issuer
spec:
   selfSigned: {}

---

apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
   name: first-tls
spec:
   secretName: first-tls
   dnsNames:
   - "*.cluster.local"
   issuerRef:
     name: selfsigned-issuer

Jetzt muss das Manifest angewendet werden und der Cert-Manager erstellt für uns das selbst signierte Zertifikat, welches wir in dem Ingress später referenzieren werden.

k apply -n keycloak -f keycloak-cert.yaml

Überprüfung der Ausstellung

Ein paar Schnelltests geben auskunft über die erfolgreiche Erstellung der Zertifikate:

# Zertifikat überprüfen
k -n keycloak get certificate
# Secret überprüfen
k -n keycloak get secret first-tls

Nun zum Abschluss noch mit OpenSSL überprüfen…

openssl x509 -in <(kubectl -n keycloak get secret first-tls -o jsonpath='{.data.tls\.crt}' | base64 -d) -text -noout

…in der Ausgabe erhält man dann die Informationen…

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            2e:df:ae:86:5c:27:f9:25:bf:77:ca:d1:7a:3a:48:c6
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: 
        Validity
            Not Before: Sep  2 08:14:52 2020 GMT
            Not After : Dec  1 08:14:52 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:c5:e0:f9:be:a6:b9:41:cb:38:e9:11:57:0a:1b:
                    b5:2b:c2:7e:78:87:5f:43:dc:22:c3:7d:8b:a7:f3:
                    c0:d4:f9:bc:75:4e:96:93:66:17:67:f7:e2:02:96:
                    37:19:90:64:6f:fa:c3:1f:c5:21:80:de:e0:aa:76:
                    12:d6:24:a0:f2:7b:37:14:34:a8:eb:9c:1a:17:b0:
                    4f:d8:a4:9b:3a:51:fe:18:30:3e:81:f5:20:01:85:
                    c1:af:61:cf:2e:30:fd:42:3c:00:c0:28:f9:60:37:
                    84:80:84:85:54:33:6c:0f:cb:c2:7e:5f:50:ee:82:
                    a1:4a:35:c3:5b:fe:8a:47:21:75:c5:0e:03:08:f2:
                    2d:fa:98:e8:d6:16:d6:fb:af:97:d8:86:3a:c6:84:
                    63:5d:bd:f1:1b:72:0f:73:f5:09:33:26:aa:bc:8f:
                    8c:9b:fa:a6:11:53:19:69:33:bc:68:47:c3:74:6a:
                    70:86:c5:19:93:83:cc:9e:07:11:0d:6e:9f:f8:5b:
                    67:d7:d8:ef:ca:37:4e:7c:1b:a2:f5:ee:70:eb:55:
                    2f:86:45:02:b4:4d:6d:9a:1b:20:3b:c4:d5:db:f3:
                    66:8c:22:e1:da:94:c4:e6:20:9f:c4:ff:79:b9:26:
                    b6:ae:d0:8f:f2:45:d5:7d:eb:88:7f:39:36:7d:ef:
                    f6:85
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Alternative Name: critical
                DNS:*.cluster.local
    Signature Algorithm: sha256WithRSAEncryption
         39:b5:cf:d7:08:b1:9d:07:44:ef:79:f3:13:46:11:f9:07:96:
         f3:db:cb:8d:5e:df:14:5f:2f:74:ff:4a:c8:58:af:57:fa:35:
         fb:19:1e:73:af:f5:d2:eb:ec:b9:d1:60:f5:28:c1:39:ba:a1:
         0c:4e:0d:3c:10:83:ba:0f:ef:4f:7a:1c:68:25:3a:3c:bf:de:
         04:24:f0:ca:15:34:6d:66:8f:3b:69:96:fe:b8:03:54:98:a6:
         fe:b8:0f:d4:6f:1b:7a:87:6a:5a:c6:57:ff:62:ee:0f:24:ff:
         e9:e8:e9:b5:4d:ca:ec:27:7c:03:7b:63:2e:ff:4d:3a:c8:5e:
         d8:b4:f5:8a:e8:0c:2c:62:f1:00:c6:4d:fe:cf:45:e2:5b:74:
         55:0a:fe:f7:5a:b4:c0:5a:2c:04:4c:ae:b2:5a:d3:d7:26:ca:
         63:2c:69:2b:81:cd:6e:39:c4:66:5f:67:47:2d:f4:ea:eb:9b:
         31:17:5d:4c:5b:77:26:d4:a4:4c:f1:52:ae:92:84:e9:f4:01:
         7e:f1:f5:cf:1d:54:a5:8c:6b:58:b2:35:b3:44:0d:81:b6:da:
         4e:0b:02:fe:21:21:75:59:53:15:17:67:7e:37:00:59:00:11:
         67:47:4e:5f:0b:1d:c4:1e:4b:5c:d2:80:57:7f:2b:58:01:ba:
         83:fc:c9:ce   

Download Kubernetes Manifest

Wir laden das Manifest keycloak.yaml mit wget runter und modifizieren die Defaultwerte für den Namespace und setzen ein neues Passwort. Der Namespace wird auf den zuvor erstellten Namespace keycloak gesetzt. Das Passwort wird auf 123 gesetzt.

wget -q -O - https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/latest/kubernetes-examples/keycloak.yaml | sed "s/namespace: default/namespace: keycloak/" > keycloak.yaml

Achtung: Username und Passwort sind hier admin. Wer es sicherer mag, der sollte das YAML bearbeiten und die Werte ersetzen.

k apply -n keycloak -f keycloak.yaml   

Das hochfahre der Pods kan mit

watch kubectl -n keycloak get pods

überwacht werden.

Ingress

Da K3S in der Defaulteinstellung Traefik als Ingress Controller verwendet, nutze ich hier nicht die von KeyCloak Team bereitgestelltes Kubernetes Manifest für Ingress.

HTTPS Anfragen für die FQDN keycloak.cluster.local an den Cluster werden werden so an den Service keycloak an Port 8443 weitergeleitet.

apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}

---

apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: first-tls
spec:
  secretName: first-tls
  dnsNames:
  - "*.cluster.local"
#  - "*.keyclaok"
  issuerRef:
    name: selfsigned-issuer

Hosts Datei Vorbereiten

Damit das Ganze funtkioniert, muss der FQDN keycloak.cluster.local in die /etc/hosts Datei eingetragen werden:

192.168.2.XXX keycloak.cluster.local

Erster Test mit CURL

curl -k https://keycloak.cluster.local:8443
<!--
  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
  ~ and other contributors as indicated by the @author tags.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
    <meta http-equiv="refresh" content="0; url=/auth/" />
    <meta name="robots" content="noindex, nofollow">
    <script type="text/javascript">
        window.location.href = "/auth/"
    </script>
</head>
<body>
    If you are not redirected automatically, follow this <a href='/auth'>link</a>.
</body>
</html>

Aufruf mit dem Browser

Nun kann nach dem ersten erfolgreichen Test der KeyCloak über https://keycloak.cluster.local:8443/auth/ bzw. die Admin-Console über https://keycloak.cluster.local:8443/auth/admin/master/console/ aufgerufen werden. Die Credentials für die Admin-Console sind im Kubernetes Manifest (siehe oben) festgelegt worden.

Standard ist hier Username admin und Passwort admin.