Skip to content

feat: configure auth-api and auth-ui for the estate path - #113

Merged
ExtraToast merged 1 commit into
mainfrom
chore/80-estate-handover
Oct 23, 2026
Merged

ExtraToast merged 1 commit into
mainfrom
chore/80-estate-handover

Conversation

@ExtraToast

Copy link
Copy Markdown
Contributor

Part of #80 (epic JorisJonkers-dev/estate#204). The fragment side of handing auth over to the estate path as it runs today (operator decision 2026-10-23: as is, on deploy-kit 0.31, migration: self).

Do not merge before JorisJonkers-dev/auth-ui's 8080 release is out (JorisJonkers-dev/auth-ui#57) and fleet-infra's two handover PRs have reconciled: this release's publish locks auth-ui's latest release and now refuses a root image. Order and commands: JorisJonkers-dev/estate docs/runbooks/auth-handover.md.

What changes

  • deploy/env/auth-api/base.env: every variable of the old path's Deployment. The injector's /vault/secrets/auth-api.env values (8 AUTH_CLIENTS_*_SECRET, DB_USER/DB_PASSWORD, MAIL_PASSWORD, SPRING_RABBITMQ_USERNAME/PASSWORD) are ${secret:...} placeholders, synced by VSO; AUTH_TRANSIT_* are literals; hosts and ports are ${dependency:...}, URLs ${exposure:auth.public#url}.
  • Transit stays delivery: self, but auth-api logs in as the old role auth-api: deploy-kit can declare sign but not the read of transit/keys/auth-api-jwt its JWKS needs. The old role also keeps database/creds/auth-api (VAULT_DB_ENABLED=true, as today).
  • deploy/env/auth-ui/base.env: no configuration, as today.
  • auth-ui provides: http: 8080, writablePaths: [/tmp] (unprivileged nginx).
  • Dockerfile: USER 65532:65532. The render sets runAsNonRoot: true with the lock's uid, so the current uid 0 would be refused at pod start. Checked locally: the v0.19.0 image as 65532, read-only root, /tmp tmpfs, all caps dropped, starts Spring up to the datasource.
  • publish.yml: the fragment lock step refuses a root image.

Validated and rendered with deploy-kit 0.31.0

Built from the tag (git archive v0.31.0). deploy-kit validate: accepted. publish and then compose against every participant's latest fragment from GHCR and this repository's cluster-state.yml:

  • with auth still legacy: composes, nothing rendered for auth, other artifacts unchanged;
  • with auth on estate and the collector's serving location (estate PR): 19 artifacts, no refusal.

Render vs live (kubectl get -o yaml, 2026-10-23)

auth-api Deployment

  • selector {name} → {name, instance}: immutable, so the first pin force-recreates it (runbook keeps old pods serving).
  • Flagger blue-green: auth-api-primary serves, the target scales to 0; HPA min=max=2 (live replicas: 2).
  • labels added: instance, part-of: auth, managed-by: deploy-kit, component: jvm, app.kubernetes.io/version, 4 consumes.*; Vault injector annotations gone.
  • priorityClassName: platform-critical-app → none.
  • nodeSelector: site=frankfurt → required affinity on frankfurt-contabo-1, enschede-gtx-960m-1, enschede-t1000-1 (may run in Enschede; Postgres/Valkey stay in Frankfurt).
  • command (sources the injector file, -XX:+UseZGC -XX:MaxRAMPercentage=55, two javaagents) → image entrypoint (otel agent), flags in JAVA_TOOL_OPTIONS. Pyroscope init container, its volume and the 7 PYROSCOPE_* vars are gone: no continuous profiling.
  • securityContext: none → runAsNonRoot, uid/gid 65532, seccomp RuntimeDefault, read-only root, drop ALL, no privilege escalation; /tmp emptyDir (64Mi limit).
  • resources: req 400m/2Gi, lim 2000m/4Gi → req 400m/4Gi, lim 4Gi, no CPU limit.
  • progressDeadlineSeconds 1800 → 2100. Strategy same (surge 1, unavailable 0).
  • env names: same set, minus PYROSCOPE_*; plus PORT=8081, JAVA_TOOL_OPTIONS; the 15 injector-file vars are now pod env.
  • env values changed: DB_HOST → platform-postgres, VALKEY_HOST → platform-valkey, SPRING_RABBITMQ_HOST → platform-rabbitmq, MAIL_HOST → stalwart (ExternalName aliases to the same Services); OTEL_EXPORTER_OTLP_ENDPOINT alloy…:4318 → alloy…:4317 with OTEL_EXPORTER_OTLP_PROTOCOL http/protobuf → grpc.
  • ports: same (8081 http). Probes: same paths and port; readiness/liveness period 10s, timeout 5s, threshold 3 (same); startup 5s×120 (timeout 1s → 5s).

auth-ui Deployment

  • image v0.6.0 (nginx:alpine, root, :80) → next auth-ui release (nginx-unprivileged, uid 101, :8080). Port and probes 80 → 8080; a startup probe is added (5s×6).
  • selector {name} → {name, instance} (recreate); Flagger primary; replicas 1.
  • ServiceAccount default → auth-ui, no token automount.
  • affinity: preferred arm64 + hostname spread → required any of the 6 nodes, no spread.
  • resources: req 100m/96Mi, lim 300m/192Mi → req 100m/192Mi, lim 192Mi.

Services: not rendered. Flagger takes over auth-api (8081) and auth-ui (8080, which fleet-infra adds and routes to first) in place, selecting <name>-primary, and adds -primary/-canary.

PDB: auth-api minAvailable 1 on name=auth-api → maxUnavailable 1 on name=auth-api-primary. auth-ui: none rendered (the orphan is deleted by hand).

ServiceMonitor auth-api → PodMonitor auth-api (same path, 30s, jobLabel: app.kubernetes.io/instance, so still job=auth-api). Orphan deleted by hand.

Namespace: gains managed-by: deploy-kit. ServiceAccount auth-api: same name, labels added.

New: VaultConnection, VaultAuth (role auth-system-auth-api), 4 VaultStaticSecrets, 4 ExternalName aliases, the vault-policy Job/CronJob, 2 Canaries, HPA, release-gate ConfigMap, the reporter-auth/rollouts-auth pair. NetworkPolicies are rendered but not applied.

Vault: new policy auth-system-auth-api: read on the 4 KV documents, update on transit/sign/auth-api-jwt, read on database/creds/auth-owner.

Elsewhere in the composition: the estate-vso-secrets Postgres catalog gains auth_db (owner auth-owner, data auth-data). It adopts the existing database: REASSIGN OWNED BY auth_user TO "auth-owner", then GRANT "auth-owner" TO auth_user. apps-grimoire, apps-n8n, apps-outline, apps-tribelt and apps-estate-dashboard gain dependsOn: apps-auth.

Unchanged and noted: AUTH_CORS_ALLOWED_ORIGINS is as live, which lacks estate. and digital-strategy. (they sign in with OIDC, not forward-auth).

The fragment changes the handover of auth needs (#80), so the estate path can
run auth in auth-system as the old path runs it today:

- deploy/env/auth-api/base.env carries every variable of the old path's
  Deployment. What the Vault Agent Injector templated into
  /vault/secrets/auth-api.env (each OIDC client's secret, the database, mail
  and RabbitMQ logins) becomes ${secret:...} placeholders VSO syncs; the
  coordinates of what auth-api depends on and its own address become
  placeholders. auth-api keeps reading the transit key and the dynamic
  database login itself, as the old path's Vault role: deploy-kit 0.31 cannot
  declare the read of transit/keys/auth-api-jwt the JWKS needs.
- deploy/env/auth-ui/base.env says auth-ui takes no configuration.
- auth-ui listens on 8080, as JorisJonkers-dev/auth-ui's unprivileged nginx does.
- The image runs as uid 65532. deploy-kit renders the lock's uid beside
  runAsNonRoot, so a root image never starts there; the fragment's lock step now
  refuses one.
@ExtraToast ExtraToast added type: feature New user-facing or operator-facing capability. area: deploy homelab-deploy, deploy-v2, manifests, and rollout flow. component: deploy Deployment pipeline, manifests, or release rollout. status: blocked Cannot move forward until an external dependency is resolved. labels Oct 23, 2026
@ExtraToast ExtraToast mentioned this pull request Oct 23, 2026
3 tasks
@ExtraToast
ExtraToast merged commit 51a13d4 into main Oct 23, 2026
10 checks passed
@ExtraToast
ExtraToast deleted the chore/80-estate-handover branch October 23, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: deploy homelab-deploy, deploy-v2, manifests, and rollout flow. component: deploy Deployment pipeline, manifests, or release rollout. status: blocked Cannot move forward until an external dependency is resolved. type: feature New user-facing or operator-facing capability.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant