Files
dezky/infrastructure/production/fleet/authentik
Ronni Baslund db1354a151
ci / typecheck (map[dir:apps/booking name:booking]) (push) Failing after 6s
ci / typecheck (map[dir:apps/portal name:portal]) (push) Has been cancelled
ci / typecheck (map[dir:apps/website name:website]) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / typecheck (map[dir:services/platform-api name:platform-api]) (push) Has been cancelled
feat(infra): Authentik blueprints (portal+operator OIDC, dezky brand)
Mirror the dev Authentik config in prod via blueprints, applied & successful on
node1:
- brand.yaml: dezky branding on the default brand (title + signal-green custom
  CSS) — login page now in dezky colors.
- portal-application.yaml / operator-application.yaml: dezky-portal &
  dezky-operator OIDC apps/providers (prod redirect URLs) + the
  dezky-platform-admins group & operator access policy.

Two 2026.5 gotchas handled + documented in README:
- invalidation_flow is now REQUIRED on OAuth2 providers (added via !Find).
- ConfigMap mounts are symlinks (discovery can't read them) → worker uses an
  initContainer that copies them to an emptyDir as real files. (chart
  worker.volumes didn't apply on this version; patch reverts on helm upgrade —
  noted as a durability TODO.)

Client secrets (PORTAL/OPERATOR_OIDC_CLIENT_SECRET) live in authentik-secret;
the apps must reuse them.
2026-06-08 19:46:48 +02:00
..

fleet/authentik — identity provider (auth.dezky.eu)

Authentik, mirroring the dev docker-compose service but pointed at the in-cluster data tier. Deployed via the k3s Helm controller (helmchart.yaml, which mirrors values.yaml). Live at https://auth.dezky.eu (Let's Encrypt).

  • External Postgres (postgres.dezky-data, db/user authentik) + Redis (redis.dezky-data) — chart's bundled subcharts disabled.
  • Secrets via global.envFrom → the authentik-secret Secret (generated on-box; see secret.example.yaml). DB/Redis passwords match the dezky-data secrets.
  • Ingress: Traefik + cert-manager letsencrypt-prod.
  • error_reporting off, update-check off, bootstrap email admin@dezky.eu.

Deploy

# 1. secret (reads DB/Redis pw from dezky-data so they match; rest generated)
ADB=$(kubectl -n dezky-data get secret postgres-secret -o jsonpath='{.data.AUTHENTIK_DB_PASSWORD}' | base64 -d)
RDB=$(kubectl -n dezky-data get secret redis-secret    -o jsonpath='{.data.REDIS_PASSWORD}'        | base64 -d)
kubectl create namespace dezky-auth --dry-run=client -o yaml | kubectl apply -f -
kubectl -n dezky-auth create secret generic authentik-secret \
  --from-literal=AUTHENTIK_SECRET_KEY=$(openssl rand -hex 50) \
  --from-literal=AUTHENTIK_POSTGRESQL__PASSWORD="$ADB" \
  --from-literal=AUTHENTIK_REDIS__PASSWORD="$RDB" \
  --from-literal=AUTHENTIK_BOOTSTRAP_PASSWORD=$(openssl rand -hex 16) \
  --from-literal=AUTHENTIK_BOOTSTRAP_TOKEN=$(openssl rand -hex 32)
# 2. install
kubectl apply -f helmchart.yaml
kubectl -n dezky-auth rollout status deploy/authentik-server --timeout=300s

First login

# akadmin password (store in Bitwarden):
kubectl -n dezky-auth get secret authentik-secret -o jsonpath='{.data.AUTHENTIK_BOOTSTRAP_PASSWORD}' | base64 -d; echo

Log in at https://auth.dezky.eu as akadmin / that password.

Blueprints + branding (APPLIED)

blueprints/ holds prod blueprints (applied & successful on node1):

  • brand.yaml — dezky branding on the default brand (title + signal-green custom CSS). This is what puts the login page in dezky colors.
  • portal-application.yamldezky-portal OIDC app/provider (https://app.dezky.eu/api/auth/callback).
  • operator-application.yamldezky-operator OIDC app/provider (https://operator.dezky.eu/auth/oidc/callback) + dezky-platform-admins group + an access policy restricting operator login to that group.

Client secrets live in authentik-secret (PORTAL_OIDC_CLIENT_SECRET, OPERATOR_OIDC_CLIENT_SECRET) — the apps must reuse the SAME values.

Applying them (two gotchas, both handled)

  1. invalidation_flow is REQUIRED on OAuth2 providers in Authentik 2026.5 (dev's 2025.10 didn't need it) — both providers set it via !Find.
  2. ConfigMap mounts present files as symlinks, which Authentik's discovery won't read. So the worker uses an initContainer that copies the ConfigMap into an emptyDir as real files at /blueprints/custom:
    kubectl -n dezky-auth create configmap authentik-blueprints \
      --from-file=blueprints/ --dry-run=client -o yaml | kubectl apply -f -
    # patch worker: add bp-src(configMap) + bp-cust(emptyDir) + initContainer
    #   `cp -L /bp-src/*.yaml /bp-cust/`, mount bp-cust at /blueprints/custom
    kubectl -n dezky-auth rollout restart deploy/authentik-worker
    # apply each (or let discovery): ak apply_blueprint custom/<file>.yaml
    

    The chart's worker.volumes value did NOT take effect on this chart version, hence the direct Deployment patch. Caveat: a helm upgrade of Authentik reverts the patch — re-apply it (move it into a custom image or a post-render kustomize patch to make it durable). TODO.

Still deferred

  • Rebrand of the "Powered by authentik" string (web-bundle sed, needs a root lifecycle override) — cosmetic; the colors are done via the brand CSS.
  • Pin the chart version (currently latest → app 2026.5.2).