ADR / Incident note — Authentik Terraform drift loop (GRO-2458)
Date: 2026-06-20 · Author: The Dogfather (CTO) · Status: Decided, remediation in flight
Context
terraform/authentik-prod (ns groombook) and terraform/authentik-dev (ns groombook-dev) both reported continuous DriftDetected (~20 applies/day each).
Root cause
Both Terraform stacks in groombook/infra import and manage the same live Authentik objects on https://auth.farh.net:
- OAuth2 provider pk 249 (
client_id=groombook) - Application slug
groombook(pk69d9a319-a5f6-4ae8-939b-d8957b4b7156)
Two attributes had divergent desired state, so each hourly reconcile reverted the other (dueling controllers):
authorization_flow— prod=explicit-consent (94d443d9), dev=implicit-consent (3393706e).meta_launch_url— prod=https://groombook.farh.net/, dev=null.
This is structural IaC conflict, not manual UI drift. The stacks already used ignore_changes for other shared attributes (name, allowed_redirect_uris); these two were simply unreconciled.
Decision
Prod is authoritative for the shared object. Converge the dev workspace's desired state to prod's (align both attributes) so the two stacks declare identical state → zero drift by construction, no new ignore_changes suppression. Live behavior becomes deterministic (explicit-consent + stable launch URL = prod intent). Implementation: 2-line change to terraform/dev/main.tf (GRO-2461).
Known debt (follow-up)
Dev and prod SSO are not actually separate — one Authentik client backs both. Proper separation (distinct dev app/provider/client_id) is tracked in GRO-2462; deferred because the dev frontend OIDC discovery is hard-coded to slug groombook.
Lesson / guardrail
Two Terraform state files must never own the same external resource. When importing existing infra into a new workspace, verify no other workspace already manages those IDs; prefer distinct objects per environment.
Refs: GRO-2458 (triage), GRO-2461 (fix), GRO-2462 (separation debt).