Files
Homelabv4/infrastructure/authentik/values.yaml
T
Scooby HuskyandClaude Sonnet 5 185e9c292e Fix real cause of VPS authentik's DB timeout loop + repo secrets cleanup
Root cause of the 'PostgreSQL connection failed, retrying... (connection
timeout expired)' loop that survived every earlier fix (streaming
replication, the password sync, the port fix, the CoreDNS override):
authentik's Helm values had TWO sources for AUTHENTIK_POSTGRESQL__HOST/
PORT - an explicit uppercase env: override (pointed at the floating
pg-authentik.ha.huskypup.net:61432) AND a chart-generated envFrom
secretRef (pg-authentik-app, prefix: AUTHENTIK_POSTGRESQL__) whose keys
are lowercase (host, port, ...), producing a SEPARATE
AUTHENTIK_POSTGRESQL__host/port pair pointing at the old local
pg-authentik-rw:5432. Kubernetes treats these as two unrelated env vars
(case-sensitive), but authentik's own generic AUTHENTIK_*-prefixed
env-var scanner apparently doesn't, and was resolving to the lowercase
(stale, local) values regardless of the explicit override - confirmed
live by dumping the pod's actual env: both HOST and host were present
with different values. Removed the now-fully-redundant envFrom entry
(every key it provided is already explicitly set via valueFrom).

Also: user correctly pointed out plaintext secrets don't belong in the
repo. Audited for the same class of issue as the already-fixed Cloudflare
token (infrastructure/cert-manager/manifests/secret-cf-token.yaml):
- infrastructure/external-dns/manifests/secret-external-dns-unifi.yaml
  had a live UniFi API key in plaintext - moved to Vault+ExternalSecret,
  same pattern as the Cloudflare token fix. The key itself is still the
  original (now Vault-stored) value - rotating it requires the UniFi web
  UI (no self-service API), noted in the file as a separate pending step.
- infrastructure/vps-eso/manifests/clustersecretstore.yaml had the
  AppRole's roleId inline (added this session) - moved to roleRef,
  sourced from the same Secret as secretId, consistent with 'nothing
  sensitive in git' regardless of how sensitive one field is alone.

NOT touched, flagged separately for the user: infrastructure/authentik/
*-blueprint.yaml (vault, gitlab, n8n, nextcloud, rancher, grafana, argocd,
guacamole) all have live-looking high-entropy client_secret values
hardcoded in plaintext - same class of issue but much larger blast radius
(8 apps' SSO), needs its own coordinated rotation, not bundled into this
commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 18:47:50 -05:00

211 lines
6.9 KiB
YAML

# Authentik configuration
authentik:
secret_key: env://AUTHENTIK_SECRET_KEY
postgresql:
host: env://AUTHENTIK_POSTGRESQL__HOST
port: 5432
name: env://AUTHENTIK_POSTGRESQL__NAME
user: env://AUTHENTIK_POSTGRESQL__USER
password: env://AUTHENTIK_POSTGRESQL__PASSWORD
global:
envFrom:
# First secret: Authentik-specific settings (AUTHENTIK_SECRET_KEY)
- secretRef:
name: authentik
# The second secretRef (pg-authentik-app, prefix: AUTHENTIK_POSTGRESQL__)
# that used to live here is GONE - found live 2026-08-20 that it was
# actively breaking things, not just redundant. That prefix mechanism
# copies the raw secret's lowercase keys (host, port, dbname, username,
# password) into lowercase-suffixed env vars (AUTHENTIK_POSTGRESQL__host,
# etc.) - env var names are case-sensitive to Kubernetes, but authentik's
# own generic AUTHENTIK_*-prefixed env-var scanner is NOT, and it was
# picking up the lowercase AUTHENTIK_POSTGRESQL__host=pg-authentik-rw
# instead of the explicit uppercase AUTHENTIK_POSTGRESQL__HOST override
# below - silently connecting to the local CNPG service on port 5432
# the whole time regardless of what HOST/PORT were explicitly set to,
# surfacing as an unexplained "connection timeout expired" loop (the
# local hostname resolves fine in-cluster but on the VPS the request
# apparently doesn't complete - never fully root-caused, just confirmed
# dropping this duplicate source fixes it). Every key that secretRef
# used to provide (dbname/username/password) is already explicitly set
# via valueFrom below, so nothing is lost by removing it.
env:
# Configure external URL for proper OIDC discovery responses
- name: AUTHENTIK_URL
value: "https://auth.kube.huskypup.net"
# Multi-site active failover pilot (see
# /home/scooby/.claude/plans/jiggly-snacking-iverson.md): HOST/PORT
# point at the floating pg-authentik.ha.huskypup.net Cloudflare A
# record instead of the local pg-authentik-app secret's host/port -
# the failover-watcher flips that record between home's and the VPS's
# public IP, both listening on the SAME external port 61432 (home via
# UniFi WAN forward, VPS via pg-authentik-forward.service's local
# socat forward - see infrastructure/ha-failover/manifests/). This way
# app pods on EITHER site always reach whichever site is currently
# primary, without needing per-site Helm value differences that would
# go stale on failover.
#
# NAME/USER/PASSWORD still come from the local pg-authentik-app secret
# (CNPG-generated, doesn't change on failover) - but the two sites'
# copies of this secret must hold the SAME password, since either site
# may end up dialing the other. CNPG only sets it once at cluster
# creation from an independently-generated value per cluster, so this
# needed a one-time manual sync (VPS's copy was stale from before
# streaming replication existed - confirmed live 2026-08-20, VPS's
# local secret still had its original bootstrap-time password even
# though the live Postgres role itself now replicates from home via
# WAL). If the app user's password is ever rotated, it must be synced
# to both sites' secrets the same way.
- name: AUTHENTIK_POSTGRESQL__HOST
value: "pg-authentik.ha.huskypup.net"
- name: AUTHENTIK_POSTGRESQL__NAME
valueFrom:
secretKeyRef:
name: pg-authentik-app
key: dbname
- name: AUTHENTIK_POSTGRESQL__USER
valueFrom:
secretKeyRef:
name: pg-authentik-app
key: username
- name: AUTHENTIK_POSTGRESQL__PASSWORD
valueFrom:
secretKeyRef:
name: pg-authentik-app
key: password
- name: AUTHENTIK_POSTGRESQL__PORT
value: "61432"
# Blueprints - Mount ConfigMaps for auto-discovery
blueprints:
configMaps:
- authentik-blueprints-gitlab
- authentik-blueprints-nextcloud
- authentik-blueprints-argocd
- authentik-blueprints-grafana
- authentik-blueprints-forward-auth
- authentik-blueprints-prometheus
- authentik-blueprints-n8n
- authentik-blueprints-ceph
- authentik-blueprints-home-assistant
- authentik-blueprints-guacamole
- authentik-blueprints-percona-everest
- authentik-blueprints-rancher
- authentik-blueprints-netbird
- authentik-blueprints-vault
# Enable Prometheus metrics
server:
# Single replica required: the embedded outpost stores forward-auth sessions
# in-memory (no Redis). Multiple replicas cause callback failures because
# the session created during ext_authz check is only on one pod.
replicas: 1
containerSecurityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
metrics:
enabled: true
serviceMonitor:
enabled: true
labels:
release: prometheus
# Resource limits to prevent OOM
resources:
requests:
cpu: 50m
memory: 512Mi
limits:
memory: 1Gi
# Health probes - removed invalid 'enabled' fields
startupProbe:
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 24 # 120 seconds for Authentik startup
readinessProbe:
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
livenessProbe:
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Spread across nodes
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: authentik
app.kubernetes.io/component: server
topologyKey: kubernetes.io/hostname
worker:
containerSecurityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
metrics:
enabled: true
serviceMonitor:
enabled: true
labels:
release: prometheus
# Resource limits to prevent OOM
resources:
requests:
cpu: 50m
memory: 512Mi
limits:
memory: 1Gi
# Spread across nodes
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: authentik
app.kubernetes.io/component: worker
topologyKey: kubernetes.io/hostname
# Mount cert-manager secret for auto-import of Let's Encrypt cert
volumeMounts:
- name: certs
mountPath: /certs
readOnly: true
volumes:
- name: certs
secret:
secretName: authentik-tls
optional: true
# Disable bundled Postgres
postgresql:
enabled: false