diff --git a/apps/authentik/authentik.yaml b/apps/authentik/authentik.yaml index 4d54a87..1e8ee80 100644 --- a/apps/authentik/authentik.yaml +++ b/apps/authentik/authentik.yaml @@ -1,448 +1,453 @@ -# Authentik OIDC backend -# ArgoCD-managed. BlueJay Lab. -# -# Stack: -# - PostgreSQL 16 StatefulSet (single replica, Longhorn RWO 5Gi) -# - Redis 7 Deployment (no persistence — session/cache only) -# - Authentik server + worker Deployments (image ghcr.io/goauthentik/server:2024.12.3) -# - Media PVC shared between server + worker (Longhorn RWO 2Gi) -# - Certificate via step-ca-acme ClusterIssuer -# - Traefik IngressRoute at id.iamworkin.lan -# -# Secrets come from 1Password item "authentik-credentials" (IAmWorkin vault, id y6i74ch22q5wvm7znquq4nhhcu) -# via the OnePasswordItem CRD, materialized into k8s Secret authentik/authentik-credentials. -# -# Why the discovery URL is /application/o/pimanager/ : Authentik issues per-application OIDC providers. -# The pimanager OIDC application/provider is created after the cluster pods are healthy (manual or -# via API once the bootstrap token is available — see Notes substrate). - ---- -apiVersion: v1 -kind: Namespace -metadata: - name: authentik - labels: - app.kubernetes.io/part-of: bluejay-infra - ---- -# 1Password operator pulls the authentik-credentials item into a k8s Secret of the same name. -# Field labels in 1P become Secret keys: AUTHENTIK_SECRET_KEY, POSTGRES_PASSWORD, REDIS_PASSWORD, -# BOOTSTRAP_ADMIN_PASSWORD, BOOTSTRAP_ADMIN_TOKEN, BOOTSTRAP_ADMIN_EMAIL. -apiVersion: onepassword.com/v1 -kind: OnePasswordItem -metadata: - name: authentik-credentials - namespace: authentik -spec: - itemPath: "vaults/IAmWorkin/items/authentik-credentials" - ---- -# Shared media volume for server + worker pods. -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: authentik-media - namespace: authentik -spec: - storageClassName: longhorn - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 2Gi - ---- -# PostgreSQL 16 StatefulSet — Authentik's primary store. -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: authentik-postgres - namespace: authentik - labels: - app: authentik-postgres - argocd.argoproj.io/instance: infra-authentik -spec: - persistentVolumeClaimRetentionPolicy: - whenDeleted: Retain - whenScaled: Retain - podManagementPolicy: OrderedReady - serviceName: authentik-postgres - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - app: authentik-postgres - template: - metadata: - labels: - app: authentik-postgres - spec: - containers: - - name: postgres - image: postgres:16-alpine - ports: - - containerPort: 5432 - name: postgres - env: - - name: POSTGRES_USER - value: authentik - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: authentik-credentials - key: POSTGRES_PASSWORD - - name: POSTGRES_DB - value: authentik - - name: POSTGRES_INITDB_ARGS - value: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" - - name: PGDATA - value: /var/lib/postgresql/data/pgdata - readinessProbe: - exec: - command: ["pg_isready", "-U", "authentik"] - initialDelaySeconds: 5 - periodSeconds: 5 - livenessProbe: - exec: - command: ["pg_isready", "-U", "authentik"] - initialDelaySeconds: 30 - periodSeconds: 30 - resources: - requests: { cpu: 100m, memory: 256Mi } - limits: { cpu: 1000m, memory: 1Gi } - volumeMounts: - - name: pgdata - mountPath: /var/lib/postgresql/data - volumeClaimTemplates: - - metadata: - name: pgdata - spec: - storageClassName: longhorn - accessModes: [ReadWriteOnce] - volumeMode: Filesystem - resources: - requests: - storage: 5Gi - ---- -apiVersion: v1 -kind: Service -metadata: - name: authentik-postgres - namespace: authentik -spec: - clusterIP: None - selector: - app: authentik-postgres - ports: - - name: postgres - port: 5432 - targetPort: 5432 - ---- -# Redis 7 — session storage + Celery broker. No persistence needed (cache). -apiVersion: apps/v1 -kind: Deployment -metadata: - name: authentik-redis - namespace: authentik - labels: - app: authentik-redis - argocd.argoproj.io/instance: infra-authentik -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app: authentik-redis - template: - metadata: - labels: - app: authentik-redis - spec: - containers: - - name: redis - image: redis:7-alpine - args: - - "--save" - - "" - - "--appendonly" - - "no" - - "--requirepass" - - "$(REDIS_PASSWORD)" - env: - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: authentik-credentials - key: REDIS_PASSWORD - ports: - - containerPort: 6379 - name: redis - readinessProbe: - tcpSocket: { port: 6379 } - initialDelaySeconds: 5 - periodSeconds: 5 - livenessProbe: - tcpSocket: { port: 6379 } - initialDelaySeconds: 30 - periodSeconds: 30 - resources: - requests: { cpu: 50m, memory: 64Mi } - limits: { cpu: 500m, memory: 256Mi } - ---- -apiVersion: v1 -kind: Service -metadata: - name: authentik-redis - namespace: authentik -spec: - selector: - app: authentik-redis - ports: - - name: redis - port: 6379 - targetPort: 6379 - ---- -# Authentik server Deployment — HTTP frontend on :9000. -apiVersion: apps/v1 -kind: Deployment -metadata: - name: authentik-server - namespace: authentik - labels: - app: authentik-server - argocd.argoproj.io/instance: infra-authentik -spec: - replicas: 1 - strategy: - type: Recreate # shares /media RWO PVC with worker - selector: - matchLabels: - app: authentik-server - template: - metadata: - labels: - app: authentik-server - spec: - securityContext: - # Authentik image runs as uid 1000 "authentik" but the Longhorn PVC mounts - # root:root by default. fsGroup recursively chgrp + chmod g+rwx so the - # non-root container can mkdir /media/public during the tenant_files migration. - fsGroup: 1000 - containers: - - name: server - image: ghcr.io/goauthentik/server:2024.12.3 - args: ["server"] - ports: - - containerPort: 9000 - name: http - - containerPort: 9443 - name: https - env: - - name: AUTHENTIK_SECRET_KEY - valueFrom: - secretKeyRef: - name: authentik-credentials - key: AUTHENTIK_SECRET_KEY - - name: AUTHENTIK_REDIS__HOST - value: authentik-redis - - name: AUTHENTIK_REDIS__PASSWORD - valueFrom: - secretKeyRef: - name: authentik-credentials - key: REDIS_PASSWORD - - name: AUTHENTIK_POSTGRESQL__HOST - value: authentik-postgres - - name: AUTHENTIK_POSTGRESQL__NAME - value: authentik - - name: AUTHENTIK_POSTGRESQL__USER - value: authentik - - name: AUTHENTIK_POSTGRESQL__PASSWORD - valueFrom: - secretKeyRef: - name: authentik-credentials - key: POSTGRES_PASSWORD - - name: AUTHENTIK_BOOTSTRAP_PASSWORD - valueFrom: - secretKeyRef: - name: authentik-credentials - key: BOOTSTRAP_ADMIN_PASSWORD - - name: AUTHENTIK_BOOTSTRAP_TOKEN - valueFrom: - secretKeyRef: - name: authentik-credentials - key: BOOTSTRAP_ADMIN_TOKEN - - name: AUTHENTIK_BOOTSTRAP_EMAIL - valueFrom: - secretKeyRef: - name: authentik-credentials - key: BOOTSTRAP_ADMIN_EMAIL - - name: AUTHENTIK_DISABLE_UPDATE_CHECK - value: "true" - - name: AUTHENTIK_ERROR_REPORTING__ENABLED - value: "false" - - name: AUTHENTIK_LOG_LEVEL - value: info - # First-boot Authentik can take 3+ min on the migration phase - # (waiting on DB lock while worker also runs migrations). Initial - # delays are generous so kubelet doesn't kill the pod mid-migration; - # periodSeconds keeps post-startup probing responsive. - readinessProbe: - httpGet: - path: /-/health/ready/ - port: 9000 - initialDelaySeconds: 60 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 12 - livenessProbe: - httpGet: - path: /-/health/live/ - port: 9000 - initialDelaySeconds: 300 - periodSeconds: 30 - timeoutSeconds: 10 - failureThreshold: 3 - startupProbe: - httpGet: - path: /-/health/live/ - port: 9000 - initialDelaySeconds: 30 - periodSeconds: 15 - timeoutSeconds: 10 - failureThreshold: 40 # 30s + 40*15s = 10.5 min budget - resources: - requests: { cpu: 150m, memory: 512Mi } - limits: { cpu: 1500m, memory: 1Gi } - volumeMounts: - - name: media - mountPath: /media - volumes: - - name: media - persistentVolumeClaim: - claimName: authentik-media - ---- -# Authentik worker Deployment — runs Celery background tasks. -apiVersion: apps/v1 -kind: Deployment -metadata: - name: authentik-worker - namespace: authentik - labels: - app: authentik-worker - argocd.argoproj.io/instance: infra-authentik -spec: - replicas: 1 - strategy: - type: Recreate # shares /media RWO PVC with server - selector: - matchLabels: - app: authentik-worker - template: - metadata: - labels: - app: authentik-worker - spec: - securityContext: - # Same as server pod — non-root uid 1000 needs PVC group write. - fsGroup: 1000 - containers: - - name: worker - image: ghcr.io/goauthentik/server:2024.12.3 - args: ["worker"] - env: - - name: AUTHENTIK_SECRET_KEY - valueFrom: - secretKeyRef: - name: authentik-credentials - key: AUTHENTIK_SECRET_KEY - - name: AUTHENTIK_REDIS__HOST - value: authentik-redis - - name: AUTHENTIK_REDIS__PASSWORD - valueFrom: - secretKeyRef: - name: authentik-credentials - key: REDIS_PASSWORD - - name: AUTHENTIK_POSTGRESQL__HOST - value: authentik-postgres - - name: AUTHENTIK_POSTGRESQL__NAME - value: authentik - - name: AUTHENTIK_POSTGRESQL__USER - value: authentik - - name: AUTHENTIK_POSTGRESQL__PASSWORD - valueFrom: - secretKeyRef: - name: authentik-credentials - key: POSTGRES_PASSWORD - - name: AUTHENTIK_DISABLE_UPDATE_CHECK - value: "true" - - name: AUTHENTIK_ERROR_REPORTING__ENABLED - value: "false" - - name: AUTHENTIK_LOG_LEVEL - value: info - resources: - requests: { cpu: 100m, memory: 256Mi } - limits: { cpu: 1000m, memory: 768Mi } - volumeMounts: - - name: media - mountPath: /media - volumes: - - name: media - persistentVolumeClaim: - claimName: authentik-media - ---- -apiVersion: v1 -kind: Service -metadata: - name: authentik-server - namespace: authentik -spec: - selector: - app: authentik-server - ports: - - name: http - port: 9000 - targetPort: 9000 - - name: https - port: 9443 - targetPort: 9443 - ---- -# step-ca leaf certificate for id.iamworkin.lan. -# step-ca container resolver uses pfSense Unbound, so the public A record for id.iamworkin.lan -# MUST exist before this Certificate is applied (cert-manager HTTP-01 will silently 2h-backoff -# otherwise). Added 2026-05-25 via scripts/pfsense-add-id-host.py. -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: authentik-tls - namespace: authentik -spec: - secretName: authentik-tls - dnsNames: - - id.iamworkin.lan - issuerRef: - name: step-ca-acme - kind: ClusterIssuer - ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: authentik - namespace: authentik -spec: - entryPoints: [websecure] - routes: - - match: Host(`id.iamworkin.lan`) - kind: Rule - services: - - name: authentik-server - port: 9000 - tls: - secretName: authentik-tls +# Authentik OIDC backend +# ArgoCD-managed. BlueJay Lab. +# +# Stack: +# - PostgreSQL 16 StatefulSet (single replica, Longhorn RWO 5Gi) +# - Redis 7 Deployment (no persistence — session/cache only) +# - Authentik server + worker Deployments (image ghcr.io/goauthentik/server:2024.12.3) +# - Media PVC shared between server + worker (Longhorn RWO 2Gi) +# - Certificate via step-ca-acme ClusterIssuer +# - Traefik IngressRoute at id.iamworkin.lan +# +# Secrets come from 1Password item "authentik-credentials" (IAmWorkin vault, id y6i74ch22q5wvm7znquq4nhhcu) +# via the OnePasswordItem CRD, materialized into k8s Secret authentik/authentik-credentials. +# +# Why the discovery URL is /application/o/pimanager/ : Authentik issues per-application OIDC providers. +# The pimanager OIDC application/provider is created after the cluster pods are healthy (manual or +# via API once the bootstrap token is available — see Notes substrate). + +--- +apiVersion: v1 +kind: Namespace +metadata: + name: authentik + labels: + app.kubernetes.io/part-of: bluejay-infra + +--- +# 1Password operator pulls the authentik-credentials item into a k8s Secret of the same name. +# Field labels in 1P become Secret keys: AUTHENTIK_SECRET_KEY, POSTGRES_PASSWORD, REDIS_PASSWORD, +# BOOTSTRAP_ADMIN_PASSWORD, BOOTSTRAP_ADMIN_TOKEN, BOOTSTRAP_ADMIN_EMAIL. +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: authentik-credentials + namespace: authentik +spec: + itemPath: "vaults/IAmWorkin/items/authentik-credentials" + +--- +# Shared media volume for server + worker pods. +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: authentik-media + namespace: authentik +spec: + storageClassName: longhorn + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 2Gi + +--- +# PostgreSQL 16 StatefulSet — Authentik's primary store. +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: authentik-postgres + namespace: authentik + labels: + app: authentik-postgres + argocd.argoproj.io/instance: infra-authentik +spec: + persistentVolumeClaimRetentionPolicy: + whenDeleted: Retain + whenScaled: Retain + podManagementPolicy: OrderedReady + serviceName: authentik-postgres + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: authentik-postgres + template: + metadata: + labels: + app: authentik-postgres + spec: + containers: + - name: postgres + image: postgres:16-alpine + ports: + - containerPort: 5432 + name: postgres + env: + - name: POSTGRES_USER + value: authentik + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: authentik-credentials + key: POSTGRES_PASSWORD + - name: POSTGRES_DB + value: authentik + - name: POSTGRES_INITDB_ARGS + value: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + readinessProbe: + exec: + command: ["pg_isready", "-U", "authentik"] + initialDelaySeconds: 5 + periodSeconds: 5 + livenessProbe: + exec: + command: ["pg_isready", "-U", "authentik"] + initialDelaySeconds: 30 + periodSeconds: 30 + resources: + requests: { cpu: 100m, memory: 256Mi } + limits: { cpu: 1000m, memory: 1Gi } + volumeMounts: + - name: pgdata + mountPath: /var/lib/postgresql/data + volumeClaimTemplates: + # apiVersion/kind included deliberately: this STS was created via ArgoCD ServerSideApply, + # so the live object carries PVC TypeMeta inside volumeClaimTemplates; omitting it here + # leaves the app eternally OutOfSync even though kubectl SSA dry-run shows no change. + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: pgdata + spec: + storageClassName: longhorn + accessModes: [ReadWriteOnce] + volumeMode: Filesystem + resources: + requests: + storage: 5Gi + +--- +apiVersion: v1 +kind: Service +metadata: + name: authentik-postgres + namespace: authentik +spec: + clusterIP: None + selector: + app: authentik-postgres + ports: + - name: postgres + port: 5432 + targetPort: 5432 + +--- +# Redis 7 — session storage + Celery broker. No persistence needed (cache). +apiVersion: apps/v1 +kind: Deployment +metadata: + name: authentik-redis + namespace: authentik + labels: + app: authentik-redis + argocd.argoproj.io/instance: infra-authentik +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: authentik-redis + template: + metadata: + labels: + app: authentik-redis + spec: + containers: + - name: redis + image: redis:7-alpine + args: + - "--save" + - "" + - "--appendonly" + - "no" + - "--requirepass" + - "$(REDIS_PASSWORD)" + env: + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: authentik-credentials + key: REDIS_PASSWORD + ports: + - containerPort: 6379 + name: redis + readinessProbe: + tcpSocket: { port: 6379 } + initialDelaySeconds: 5 + periodSeconds: 5 + livenessProbe: + tcpSocket: { port: 6379 } + initialDelaySeconds: 30 + periodSeconds: 30 + resources: + requests: { cpu: 50m, memory: 64Mi } + limits: { cpu: 500m, memory: 256Mi } + +--- +apiVersion: v1 +kind: Service +metadata: + name: authentik-redis + namespace: authentik +spec: + selector: + app: authentik-redis + ports: + - name: redis + port: 6379 + targetPort: 6379 + +--- +# Authentik server Deployment — HTTP frontend on :9000. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: authentik-server + namespace: authentik + labels: + app: authentik-server + argocd.argoproj.io/instance: infra-authentik +spec: + replicas: 1 + strategy: + type: Recreate # shares /media RWO PVC with worker + selector: + matchLabels: + app: authentik-server + template: + metadata: + labels: + app: authentik-server + spec: + securityContext: + # Authentik image runs as uid 1000 "authentik" but the Longhorn PVC mounts + # root:root by default. fsGroup recursively chgrp + chmod g+rwx so the + # non-root container can mkdir /media/public during the tenant_files migration. + fsGroup: 1000 + containers: + - name: server + image: ghcr.io/goauthentik/server:2024.12.3 + args: ["server"] + ports: + - containerPort: 9000 + name: http + - containerPort: 9443 + name: https + env: + - name: AUTHENTIK_SECRET_KEY + valueFrom: + secretKeyRef: + name: authentik-credentials + key: AUTHENTIK_SECRET_KEY + - name: AUTHENTIK_REDIS__HOST + value: authentik-redis + - name: AUTHENTIK_REDIS__PASSWORD + valueFrom: + secretKeyRef: + name: authentik-credentials + key: REDIS_PASSWORD + - name: AUTHENTIK_POSTGRESQL__HOST + value: authentik-postgres + - name: AUTHENTIK_POSTGRESQL__NAME + value: authentik + - name: AUTHENTIK_POSTGRESQL__USER + value: authentik + - name: AUTHENTIK_POSTGRESQL__PASSWORD + valueFrom: + secretKeyRef: + name: authentik-credentials + key: POSTGRES_PASSWORD + - name: AUTHENTIK_BOOTSTRAP_PASSWORD + valueFrom: + secretKeyRef: + name: authentik-credentials + key: BOOTSTRAP_ADMIN_PASSWORD + - name: AUTHENTIK_BOOTSTRAP_TOKEN + valueFrom: + secretKeyRef: + name: authentik-credentials + key: BOOTSTRAP_ADMIN_TOKEN + - name: AUTHENTIK_BOOTSTRAP_EMAIL + valueFrom: + secretKeyRef: + name: authentik-credentials + key: BOOTSTRAP_ADMIN_EMAIL + - name: AUTHENTIK_DISABLE_UPDATE_CHECK + value: "true" + - name: AUTHENTIK_ERROR_REPORTING__ENABLED + value: "false" + - name: AUTHENTIK_LOG_LEVEL + value: info + # First-boot Authentik can take 3+ min on the migration phase + # (waiting on DB lock while worker also runs migrations). Initial + # delays are generous so kubelet doesn't kill the pod mid-migration; + # periodSeconds keeps post-startup probing responsive. + readinessProbe: + httpGet: + path: /-/health/ready/ + port: 9000 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 12 + livenessProbe: + httpGet: + path: /-/health/live/ + port: 9000 + initialDelaySeconds: 300 + periodSeconds: 30 + timeoutSeconds: 10 + failureThreshold: 3 + startupProbe: + httpGet: + path: /-/health/live/ + port: 9000 + initialDelaySeconds: 30 + periodSeconds: 15 + timeoutSeconds: 10 + failureThreshold: 40 # 30s + 40*15s = 10.5 min budget + resources: + requests: { cpu: 150m, memory: 512Mi } + limits: { cpu: 1500m, memory: 1Gi } + volumeMounts: + - name: media + mountPath: /media + volumes: + - name: media + persistentVolumeClaim: + claimName: authentik-media + +--- +# Authentik worker Deployment — runs Celery background tasks. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: authentik-worker + namespace: authentik + labels: + app: authentik-worker + argocd.argoproj.io/instance: infra-authentik +spec: + replicas: 1 + strategy: + type: Recreate # shares /media RWO PVC with server + selector: + matchLabels: + app: authentik-worker + template: + metadata: + labels: + app: authentik-worker + spec: + securityContext: + # Same as server pod — non-root uid 1000 needs PVC group write. + fsGroup: 1000 + containers: + - name: worker + image: ghcr.io/goauthentik/server:2024.12.3 + args: ["worker"] + env: + - name: AUTHENTIK_SECRET_KEY + valueFrom: + secretKeyRef: + name: authentik-credentials + key: AUTHENTIK_SECRET_KEY + - name: AUTHENTIK_REDIS__HOST + value: authentik-redis + - name: AUTHENTIK_REDIS__PASSWORD + valueFrom: + secretKeyRef: + name: authentik-credentials + key: REDIS_PASSWORD + - name: AUTHENTIK_POSTGRESQL__HOST + value: authentik-postgres + - name: AUTHENTIK_POSTGRESQL__NAME + value: authentik + - name: AUTHENTIK_POSTGRESQL__USER + value: authentik + - name: AUTHENTIK_POSTGRESQL__PASSWORD + valueFrom: + secretKeyRef: + name: authentik-credentials + key: POSTGRES_PASSWORD + - name: AUTHENTIK_DISABLE_UPDATE_CHECK + value: "true" + - name: AUTHENTIK_ERROR_REPORTING__ENABLED + value: "false" + - name: AUTHENTIK_LOG_LEVEL + value: info + resources: + requests: { cpu: 100m, memory: 256Mi } + limits: { cpu: 1000m, memory: 768Mi } + volumeMounts: + - name: media + mountPath: /media + volumes: + - name: media + persistentVolumeClaim: + claimName: authentik-media + +--- +apiVersion: v1 +kind: Service +metadata: + name: authentik-server + namespace: authentik +spec: + selector: + app: authentik-server + ports: + - name: http + port: 9000 + targetPort: 9000 + - name: https + port: 9443 + targetPort: 9443 + +--- +# step-ca leaf certificate for id.iamworkin.lan. +# step-ca container resolver uses pfSense Unbound, so the public A record for id.iamworkin.lan +# MUST exist before this Certificate is applied (cert-manager HTTP-01 will silently 2h-backoff +# otherwise). Added 2026-05-25 via scripts/pfsense-add-id-host.py. +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: authentik-tls + namespace: authentik +spec: + secretName: authentik-tls + dnsNames: + - id.iamworkin.lan + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: authentik + namespace: authentik +spec: + entryPoints: [websecure] + routes: + - match: Host(`id.iamworkin.lan`) + kind: Rule + services: + - name: authentik-server + port: 9000 + tls: + secretName: authentik-tls