diff --git a/keycloak/README.md b/keycloak/README.md new file mode 100644 index 0000000..47399d1 --- /dev/null +++ b/keycloak/README.md @@ -0,0 +1,41 @@ +I recently broke this by deleting the database and restarting it. + +This was actually an accident. + +Anyway, I had a backup but went ahead and rolled forward to test the +terraform-a-new-keycloak idea... and it worked, I think! + +So I had a blank keycloak sitting in kubernetes based on the manifests here. + +I then moved the tfstate away and reterraformed the oidc clients and ldap +configs back into existence. + +HOWEVER: the oidc secrets will be different. To unscrew this up, the secrets +must be restored. This is most easily done by restoring the random password +from the previous state. + +First, we'll delete the existing new secrets. Then we'll restore the others. + +```bash +jq -c '.resources[]' terraform.tfstate.1681525339.backup | \ + jq -r ' + select(.type == "random_password") + | @sh "terraform state rm \(.module).\(.type).\(.name)\"[0]\"" + ' | sh -s +``` + +I screwed my system up on Friday, April 14 at 21:22:19 CDT in the year 2023. + +Now we'll restore the good secrets. + +```bash +jq -c '.resources[]' terraform.tfstate.1681525339.backup | \ + jq -r ' + select(.type == "random_password") + | @sh "terraform import \(.module).\(.type).\(.name)\"[0]\" \(.instances[0].attributes.result)" + ' | sh -s +``` + +At least, I think this worked... I also had to set the epoch to 1 for all of +these (by modifying the state file by hand). + diff --git a/keycloak/admin-user.yaml b/keycloak/admin-user.yaml new file mode 100644 index 0000000..05c03e8 --- /dev/null +++ b/keycloak/admin-user.yaml @@ -0,0 +1,34 @@ +apiVersion: generators.external-secrets.io/v1alpha1 +kind: Password +metadata: + name: keycloak-admin + namespace: keycloak +spec: + length: 63 + digits: 5 + symbols: 5 + symbolCharacters: ",:-_" + noUpper: false + allowRepeat: true +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: "keycloak-admin" + namespace: keycloak +spec: + refreshInterval: "168h" + target: + name: keycloak-admin + template: + type: Opaque + data: + username: "admin" + password: "{{ .password }}" + dataFrom: + - sourceRef: + generatorRef: + apiVersion: generators.external-secrets.io/v1alpha1 + kind: Password + name: "keycloak-admin" + diff --git a/keycloak/copy-admin-password.sh b/keycloak/copy-admin-password.sh new file mode 100644 index 0000000..df713ff --- /dev/null +++ b/keycloak/copy-admin-password.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +kubectl get secret -n keycloak keycloak-admin -o json | jq -r '@base64d "\(.data.password)"' | pbcopy diff --git a/keycloak/db.yaml b/keycloak/db.yaml new file mode 100644 index 0000000..c039ee4 --- /dev/null +++ b/keycloak/db.yaml @@ -0,0 +1,30 @@ +apiVersion: postgres-operator.crunchydata.com/v1beta1 +kind: PostgresCluster +metadata: + name: keycloakdb + namespace: keycloak +spec: + image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.6-2 + postgresVersion: 14 + instances: + - replicas: 1 + dataVolumeClaimSpec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: 1Gi + storageClassName: ssd + backups: + pgbackrest: + image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.41-2 + repos: + - name: repo1 + volume: + volumeClaimSpec: + accessModes: + - "ReadWriteMany" + resources: + requests: + storage: 5Gi + storageClassName: nfs diff --git a/keycloak/keycloak-sts.yaml b/keycloak/keycloak-sts.yaml new file mode 100644 index 0000000..225eff7 --- /dev/null +++ b/keycloak/keycloak-sts.yaml @@ -0,0 +1,168 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app: keycloak + annotations: + reloader.stakater.com/auto: "true" + name: cascade + namespace: keycloak +spec: + podManagementPolicy: OrderedReady + replicas: 1 + selector: + matchLabels: + app: keycloak + serviceName: "keycloak" + template: + metadata: + labels: + app: keycloak + spec: + initContainers: + - name: create-ca-jks + command: ["pembundle2jks", "-o", "/ca-transfer/ca-bundle.jks", "/etc/ssl/certs/ca-bundle.crt"] + image: jamesandariese/pembundle2jks + volumeMounts: + - mountPath: /etc/ssl/certs/ca-bundle.crt + name: ca-bundle + subPath: ca-bundle.crt + - mountPath: /ca-transfer + name: ca-transfer + - name: delete-admin + image: jamesandariese/keycloak-delete-admin + env: + - name: KC_DB + value: postgres + - name: KC_DB_USERNAME + valueFrom: + secretKeyRef: + key: user + name: keycloakdb-pguser-keycloakdb + - name: KC_DB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: keycloakdb-pguser-keycloakdb + - name: KC_DB_URL_DATABASE + value: keycloakdb + - name: KC_DB_URL_HOST + value: keycloakdb-primary.keycloak.svc + containers: + - args: + - start + env: + - name: KC_PROXY + value: none + - name: KC_HEALTH_ENABLED + value: "true" + - name: KEYCLOAK_ADMIN + valueFrom: + secretKeyRef: + key: username + name: keycloak-admin + - name: KEYCLOAK_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: keycloak-admin + - name: KC_HOSTNAME + value: auth.werts.us + - name: KC_HTTP_PORT + value: "8080" + - name: KC_HTTPS_PORT + value: "8443" + - name: KC_HTTPS_CERTIFICATE_FILE + value: /mnt/certificates/tls.crt + - name: KC_HTTPS_CERTIFICATE_KEY_FILE + value: /mnt/certificates/tls.key + - name: KC_HTTPS_TRUST_STORE_FILE + value: /ca-transfer/ca-bundle.jks + - name: KC_HTTPS_TRUST_STORE_PASSWORD + value: changeit + - name: KC_DB + value: postgres + - name: KC_DB_USERNAME + valueFrom: + secretKeyRef: + key: user + name: keycloakdb-pguser-keycloakdb + - name: KC_DB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: keycloakdb-pguser-keycloakdb + - name: KC_DB_URL_DATABASE + value: keycloakdb + - name: KC_DB_URL_HOST + value: keycloakdb-primary.keycloak.svc + image: quay.io/keycloak/keycloak:21.0.0 + imagePullPolicy: Always + livenessProbe: + failureThreshold: 150 + httpGet: + path: /health/live + port: 8443 + scheme: HTTPS + initialDelaySeconds: 20 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + name: keycloak + ports: + - containerPort: 8443 + protocol: TCP + - containerPort: 8080 + protocol: TCP + readinessProbe: + failureThreshold: 250 + httpGet: + path: /health/ready + port: 8443 + scheme: HTTPS + initialDelaySeconds: 20 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /mnt/certificates + name: keycloak-tls-certificates + - mountPath: /etc/ssl/certs/ca-bundle.crt + name: ca-bundle + subPath: ca-bundle.crt + - mountPath: /etc/pki/ca-trust/extracted/java/cacerts + name: ca-transfer + subPath: ca-bundle.jks + - mountPath: /ca-transfer + name: ca-transfer + - mountPath: /opt/keycloak/themes + name: themes + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 + volumes: + - name: keycloak-tls-certificates + secret: + defaultMode: 420 + optional: false + secretName: keycloak-tls + - name: ca-bundle + configMap: + name: ca-bundle + - name: themes + nfs: + path: /volume1/k8s-volumes/keycloak-themes + server: 172.16.18.1 + - name: ca-transfer + emptyDir: + medium: Memory + sizeLimit: 50Mi + updateStrategy: + rollingUpdate: + partition: 0 + type: RollingUpdate diff --git a/keycloak/keycloak-svc.yaml b/keycloak/keycloak-svc.yaml new file mode 100644 index 0000000..8a59bb8 --- /dev/null +++ b/keycloak/keycloak-svc.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: keycloak + name: cascade-service + namespace: keycloak + annotations: + metallb.universe.tf/loadBalancerIPs: 172.16.17.31 +spec: + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - port: 80 + name: http + protocol: TCP + targetPort: 8080 + - port: 443 + name: https + protocol: TCP + targetPort: 8443 + selector: + app: keycloak + type: LoadBalancer