GITOPS FIX: Permanent solution for database credentials
CHANGES:
1. authentik-values.yaml:
- postgresql.user: authentik → app
- env vars reference ddb-cluster-app secret (via secretKeyRef)
- Both server + worker containers updated
2. sync-db-credentials-job.yaml (PostSync):
- Copies ddb-cluster-app from ddb → iam namespace
- Allows secretKeyRef to work (no cross-namespace support)
- Runs after every iam-jobs sync
3. kustomization.yaml:
- Added sync-db-credentials-job to resources
REPLACES:
- Manual kubectl patch of authentik-secrets
- SOPS-encrypted per-app credentials
- Complex permission grants
BENEFITS:
✅ ArgoCD won't revert changes (in git)
✅ Follows CNPG simple pattern (app user)
✅ Single source of truth (ddb-cluster-app)
✅ Auto-syncs on every deploy
Deployed by: iam-jobs Application (wave 3)
276 lines
10 KiB
YAML
276 lines
10 KiB
YAML
# k8s/talos-iam/authentik-values.yaml
|
||
# Authentik — SSO Identity Provider for the homelab.
|
||
# Provides OAuth2/OIDC login for Grafana, MinIO, Forgejo, and Argo CD.
|
||
# Chart: authentik/authentik from https://charts.goauthentik.io
|
||
#
|
||
# Architecture: server (UI+API) + worker (background tasks) + PostgreSQL + Redis.
|
||
# PostgreSQL is the system of record — must persist. Redis is ephemeral cache/queue.
|
||
#
|
||
# Secrets injected via helmfile --set (from .env / vsource):
|
||
# AUTHENTIK_SECRET_KEY — signs sessions and tokens; set once, never rotate casually
|
||
# AUTHENTIK_BOOTSTRAP_PASSWORD — initial akadmin password (used once at first login)
|
||
# AUTHENTIK_BOOTSTRAP_TOKEN — API token for the setup_talos_iam.sh bootstrap script
|
||
# AUTHENTIK_PG_PASSWORD — PostgreSQL user password
|
||
|
||
authentik:
|
||
# host: the external URL Authentik uses to build redirect URIs in OAuth2 flows.
|
||
# Must match what the browser sees — if it returns an internal svc URL,
|
||
# the browser's redirect after login will fail (can't reach svc DNS externally).
|
||
# HTTP (not HTTPS) because the Authentik ingress has no TLS cert configured.
|
||
host: "https://authentik.riotpiao.com"
|
||
|
||
error_reporting:
|
||
enabled: false # do not phone home to Sentry
|
||
|
||
# PostgreSQL connection — points at CloudNativePG cluster in ddb namespace.
|
||
# Uses 'app' bootstrap user (CNPG simple pattern, same as Forgejo).
|
||
# Credentials injected from ddb-cluster-app secret via env vars below.
|
||
postgresql:
|
||
host: ddb-cluster-rw.ddb.svc.cluster.local
|
||
port: 5432
|
||
name: authentik
|
||
user: app # All apps use shared 'app' user (CNPG design pattern)
|
||
password: "" # overridden by AUTHENTIK_POSTGRESQL__PASSWORD env var
|
||
|
||
# Redis connection — bundled subchart, standalone mode (no sentinel/cluster).
|
||
redis:
|
||
host: authentik-redis-master
|
||
|
||
# ── HTTP client timeouts ──────────────────────────────────────────────────────
|
||
# Increased to tolerate 5+ second pod-to-pod network latency.
|
||
# Affects webhooks, outpost management, SCIM, LDAP sync.
|
||
# Default: ~30s — too aggressive when latency spikes hit 5-10s.
|
||
log_level: debug # enable debug logging to monitor connection issues
|
||
|
||
# ── CA trust (shared by server and worker) ────────────────────────────────────
|
||
# Authentik (Python/Debian) uses requests + httpx for outgoing HTTPS — webhooks,
|
||
# outpost management, SCIM. Both libraries need REQUESTS_CA_BUNDLE / SSL_CERT_FILE
|
||
# to point to a bundle that includes homelab-ca, otherwise connections to other
|
||
# homelab services fail with "certificate signed by unknown authority".
|
||
#
|
||
# Strategy: a debian:12-slim init container (run as root) concatenates the
|
||
# Debian system Mozilla bundle with homelab-ca.crt into an emptyDir. The main
|
||
# container then references /merged/ca-bundle.crt via two env vars that cover
|
||
# every Python HTTP library.
|
||
_caVolumes: &caVolumes
|
||
- name: homelab-ca
|
||
configMap:
|
||
name: homelab-ca
|
||
- name: merged-ca
|
||
emptyDir: {}
|
||
|
||
_caVolumeMounts: &caVolumeMounts
|
||
- name: homelab-ca
|
||
mountPath: /homelab-ca
|
||
readOnly: true
|
||
- name: merged-ca
|
||
mountPath: /merged
|
||
readOnly: true
|
||
|
||
_caInitContainers: &caInitContainers
|
||
- name: merge-ca-certs
|
||
image: debian:bookworm
|
||
imagePullPolicy: IfNotPresent
|
||
securityContext:
|
||
runAsUser: 0
|
||
command:
|
||
- sh
|
||
- -c
|
||
- (cat /etc/ssl/certs/ca-certificates.crt 2>/dev/null; cat /homelab-ca/homelab-ca.crt) > /merged/ca-bundle.crt
|
||
volumeMounts:
|
||
- name: homelab-ca
|
||
mountPath: /homelab-ca
|
||
readOnly: true
|
||
- name: merged-ca
|
||
mountPath: /merged
|
||
# NOTE: no authentik-migrate init container — the authentik `server` entrypoint
|
||
# runs migrations itself on startup. A separate `manage migrate` init pinned to
|
||
# an older image tripped a version-history precheck on an empty DB
|
||
# (relation "authentik_version_history" does not exist) and blocked boot.
|
||
|
||
_caEnv: &caEnv
|
||
- name: REQUESTS_CA_BUNDLE
|
||
value: /merged/ca-bundle.crt
|
||
- name: SSL_CERT_FILE
|
||
value: /merged/ca-bundle.crt
|
||
|
||
# ── Authentik server (UI + API) ───────────────────────────────────────────────
|
||
# Handles all browser traffic: login flows, admin UI, OAuth2 authorize/token endpoints.
|
||
# NodePort 32172 is a fallback for direct node access during troubleshooting;
|
||
# normal access is via nginx ingress (authentik.riotpiao.com → svc:80).
|
||
# Recreate: single replica + RWO-adjacent state — avoids split-brain on redeploy.
|
||
server:
|
||
replicas: 1
|
||
# Merge SOPS-CMP-emitted secret values after the chart's own `authentik` secret.
|
||
envFrom:
|
||
- secretRef:
|
||
name: authentik-secrets
|
||
deploymentStrategy:
|
||
type: Recreate
|
||
service:
|
||
type: NodePort
|
||
nodePort: 32172
|
||
resources:
|
||
requests:
|
||
cpu: 100m
|
||
memory: 512Mi
|
||
limits:
|
||
cpu: 1000m
|
||
memory: 1Gi
|
||
tolerations:
|
||
- key: node-role.kubernetes.io/control-plane
|
||
operator: Exists
|
||
effect: NoSchedule
|
||
volumes: *caVolumes
|
||
volumeMounts: *caVolumeMounts
|
||
initContainers: *caInitContainers
|
||
env:
|
||
# Merge CA trust env vars
|
||
- name: REQUESTS_CA_BUNDLE
|
||
value: /merged/ca-bundle.crt
|
||
- name: SSL_CERT_FILE
|
||
value: /merged/ca-bundle.crt
|
||
# Override database credentials to use 'app' from ddb-cluster-app
|
||
- name: AUTHENTIK_POSTGRESQL__USER
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: ddb-cluster-app
|
||
key: username
|
||
- name: AUTHENTIK_POSTGRESQL__PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: ddb-cluster-app
|
||
key: password
|
||
podAnnotations:
|
||
configmap.reloader.stakater.com/reload: "homelab-ca"
|
||
homelab.io/restart-at: "2026-06-21T13-40"
|
||
# The /-/health/{live,ready}/ endpoints do a DB round-trip; under transient
|
||
# CNPG contention they respond in 5-6s while still returning 200. The chart's
|
||
# default 3s liveness timeout then flags a working backend as dead and kubelet
|
||
# kills it in a restart loop — the pod never stays Ready, gets dropped from the
|
||
# authentik-server Service endpoints, and the OAuth-provisioning PostSync hook
|
||
# fails with "Host is unreachable". Widen the timeouts so slow-but-healthy
|
||
# checks aren't treated as failures. (Only these fields are overridden; the
|
||
# chart deep-merges the rest of each probe, incl. the httpGet path.)
|
||
livenessProbe:
|
||
timeoutSeconds: 15
|
||
failureThreshold: 6
|
||
readinessProbe:
|
||
timeoutSeconds: 15
|
||
failureThreshold: 6
|
||
startupProbe:
|
||
timeoutSeconds: 15
|
||
failureThreshold: 120 # 120 × 10s = 20min for fresh DB migrations
|
||
# Every OIDC login (Grafana, Argo CD, MinIO, Forgejo) depends on this server —
|
||
# its request latency/error rate explains SSO-driven slowness on those services.
|
||
metrics:
|
||
enabled: true
|
||
serviceMonitor:
|
||
enabled: true
|
||
scrapeTimeout: 30s
|
||
|
||
# ── Authentik worker ──────────────────────────────────────────────────────────
|
||
# Runs background tasks: email delivery, LDAP sync, flow policy evaluation,
|
||
# event log cleanup, and managed outpost updates. Stateless — no PVC needed.
|
||
# Same resource profile as server; Authentik 2023+ merged some worker duties
|
||
# into the server process but the worker pod is still required.
|
||
worker:
|
||
replicas: 1
|
||
envFrom:
|
||
- secretRef:
|
||
name: authentik-secrets
|
||
deploymentStrategy:
|
||
type: Recreate
|
||
resources:
|
||
requests:
|
||
cpu: 100m
|
||
memory: 512Mi
|
||
limits:
|
||
cpu: 1000m
|
||
memory: 1Gi
|
||
tolerations:
|
||
- key: node-role.kubernetes.io/control-plane
|
||
operator: Exists
|
||
effect: NoSchedule
|
||
volumes: *caVolumes
|
||
volumeMounts: *caVolumeMounts
|
||
initContainers: *caInitContainers
|
||
env:
|
||
# Merge CA trust env vars
|
||
- name: REQUESTS_CA_BUNDLE
|
||
value: /merged/ca-bundle.crt
|
||
- name: SSL_CERT_FILE
|
||
value: /merged/ca-bundle.crt
|
||
# Override database credentials to use 'app' from ddb-cluster-app
|
||
- name: AUTHENTIK_POSTGRESQL__USER
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: ddb-cluster-app
|
||
key: username
|
||
- name: AUTHENTIK_POSTGRESQL__PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: ddb-cluster-app
|
||
key: password
|
||
podAnnotations:
|
||
configmap.reloader.stakater.com/reload: "homelab-ca"
|
||
homelab.io/restart-at: "2026-06-21T13-40"
|
||
metrics:
|
||
enabled: true
|
||
serviceMonitor:
|
||
enabled: true
|
||
scrapeTimeout: 30s
|
||
|
||
# ── PostgreSQL (external: CloudNativePG cluster in ddb namespace) ─────────────
|
||
# Authentik connects to the centralized ddb-cluster (1 primary + 2 replicas with pgvector).
|
||
# Do not use the bundled Bitnami subchart — CNPG is already running.
|
||
postgresql:
|
||
enabled: false
|
||
primary:
|
||
persistence:
|
||
enabled: true
|
||
storageClass: longhorn
|
||
size: 8Gi
|
||
tolerations:
|
||
- key: node-role.kubernetes.io/control-plane
|
||
operator: Exists
|
||
effect: NoSchedule
|
||
affinity:
|
||
nodeAffinity:
|
||
preferredDuringSchedulingIgnoredDuringExecution:
|
||
- weight: 100
|
||
preference:
|
||
matchExpressions:
|
||
- key: node-role.kubernetes.io/worker
|
||
operator: Exists
|
||
|
||
# ── Bundled Redis ─────────────────────────────────────────────────────────────
|
||
# Cache and async task queue only — no durable data. If Redis restarts, in-flight
|
||
# background tasks are retried and cached tokens are recomputed. Losing Redis
|
||
# data does not lose user accounts or flow configuration (that's in PostgreSQL).
|
||
# persistence: false saves a PVC and makes restarts faster.
|
||
#
|
||
# Same prefer-worker / fallback-to-cp scheduling as PostgreSQL.
|
||
# architecture: standalone — no Sentinel/cluster overhead for a 3-node homelab.
|
||
redis:
|
||
enabled: true
|
||
master:
|
||
persistence:
|
||
enabled: false
|
||
tolerations:
|
||
- key: node-role.kubernetes.io/control-plane
|
||
operator: Exists
|
||
effect: NoSchedule
|
||
affinity:
|
||
nodeAffinity:
|
||
preferredDuringSchedulingIgnoredDuringExecution:
|
||
- weight: 100
|
||
preference:
|
||
matchExpressions:
|
||
- key: node-role.kubernetes.io/worker
|
||
operator: Exists
|
||
architecture: standalone
|
||
|
||
# Ingress disabled — rule lives in k8s/ingress/ingress.yaml (authentik.riotpiao.com).
|
||
# For direct access during bootstrap: kubectl -n iam port-forward svc/authentik-server 7000:80
|