Liveness probe was firing after 60s with failureThreshold:6, killing the server container before it finished applying 200+ DB migrations. The startup probe (20min timeout) never got a chance to complete. Root cause: Authentik health checks fail during long DB bootstrap. Both liveness and startup probes run in parallel. Liveness killed the pod at 60s; migrations need 2-3min minimum. Solution: Add initialDelaySeconds:300 to liveness/readiness probes so they don't fire until 5min have passed (migrations definitely complete). Worker gets same treatment since it depends on server's DB bootstrap.
285 lines
11 KiB
YAML
285 lines
11 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 authentik-db-app secret via env vars below.
|
||
postgresql:
|
||
host: authentik-db-rw.iam.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 authentik-db-app
|
||
- name: AUTHENTIK_POSTGRESQL__USER
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: authentik-db-app
|
||
key: username
|
||
- name: AUTHENTIK_POSTGRESQL__PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: authentik-db-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:
|
||
initialDelaySeconds: 300 # skip probe until 5min passed (migrations finish)
|
||
timeoutSeconds: 15
|
||
failureThreshold: 6
|
||
readinessProbe:
|
||
initialDelaySeconds: 300 # skip probe until migrations complete
|
||
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 authentik-db-app
|
||
- name: AUTHENTIK_POSTGRESQL__USER
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: authentik-db-app
|
||
key: username
|
||
- name: AUTHENTIK_POSTGRESQL__PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: authentik-db-app
|
||
key: password
|
||
podAnnotations:
|
||
configmap.reloader.stakater.com/reload: "homelab-ca"
|
||
homelab.io/restart-at: "2026-06-21T13-40"
|
||
livenessProbe:
|
||
initialDelaySeconds: 300 # skip probe until 5min passed (migrations finish)
|
||
readinessProbe:
|
||
initialDelaySeconds: 300 # skip probe until migrations complete
|
||
startupProbe:
|
||
initialDelaySeconds: 30 # let server finish DB work first
|
||
failureThreshold: 120
|
||
metrics:
|
||
enabled: true
|
||
serviceMonitor:
|
||
enabled: true
|
||
scrapeTimeout: 30s
|
||
|
||
# ── PostgreSQL (external: CloudNativePG cluster in ddb namespace) ─────────────
|
||
# Authentik connects to the dedicated authentik-db (1 primary + 2 replicas).
|
||
# 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
|