# PV apiVersion: v1 kind: PersistentVolume metadata: name: pv-auth spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: local-ssd-hetzner local: path: /mnt/local-ssd/auth nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - hetzner-2 --- # k8s/auth/keycloak/secret.yaml apiVersion: v1 kind: Secret metadata: { name: keycloak-admin, namespace: db } type: Opaque stringData: { KEYCLOAK_ADMIN: "admin", KEYCLOAK_ADMIN_PASSWORD: "admin" } --- # k8s/auth/keycloak/pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: { name: keycloak-data, namespace: db } spec: accessModes: ["ReadWriteOnce"] storageClassName: local-ssd-hetzner resources: { requests: { storage: 10Gi } } --- # k8s/auth/keycloak/deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: { name: keycloak, namespace: db } spec: replicas: 1 selector: { matchLabels: { app: keycloak } } template: metadata: { labels: { app: keycloak } } spec: # Ensure the PV is owned by the Keycloak UID/GID securityContext: fsGroup: 1000 initContainers: - name: fix-permissions image: busybox command: ['sh', '-c', 'chown -R 1000:1000 /opt/keycloak/data && chmod -R 755 /opt/keycloak/data'] volumeMounts: - name: data mountPath: /opt/keycloak/data containers: - name: keycloak image: quay.io/keycloak/keycloak:latest args: ["start","--http-enabled=true","--proxy-headers=xforwarded","--hostname-strict=false"] env: - { name: KEYCLOAK_ADMIN, valueFrom: { secretKeyRef: { name: keycloak-admin, key: KEYCLOAK_ADMIN } } } - { name: KEYCLOAK_ADMIN_PASSWORD, valueFrom: { secretKeyRef: { name: keycloak-admin, key: KEYCLOAK_ADMIN_PASSWORD } } } ports: [{ containerPort: 8080 }] volumeMounts: [{ name: data, mountPath: /opt/keycloak/data }] securityContext: runAsUser: 1000 runAsGroup: 1000 volumes: - name: data persistentVolumeClaim: { claimName: keycloak-data } --- apiVersion: v1 kind: Service metadata: { name: keycloak, namespace: db } spec: { selector: { app: keycloak }, ports: [ { port: 80, targetPort: 8080 } ] } --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: keycloak namespace: db annotations: { cert-manager.io/cluster-issuer: letsencrypt-prod } spec: ingressClassName: nginx tls: [{ hosts: ["auth.betelgeusebytes.io"], secretName: keycloak-tls }] rules: - host: auth.betelgeusebytes.io http: paths: - path: / pathType: Prefix backend: { service: { name: keycloak, port: { number: 80 } } }