# ADR 0004 — authenticate and bind authorization callers Status: accepted (source implemented; production promotion pending) Date: 2026-08-18 ## Context `POST /v1/check` and `/v1/batch_check` accepted an asserted subject, tenant and protected-system name from any workload with network reach. NetworkPolicy limited reachability but did not establish caller identity. A caller could therefore represent another protected system and obtain an authoritative decision under the wrong policy package. The boundary must authenticate workloads without turning flex-auth into an identity issuer, sharing a long-lived secret between services, or coupling authorization availability to an unrelated identity-provider round trip. ## Decision Use Kubernetes ServiceAccount tokens with audience `flex-auth`. flex-auth calls the Kubernetes TokenReview API through a separately projected reviewer token and binds the authenticated ServiceAccount principal to every `resource.system` in the request. Both the single and batch endpoints use the same choke point; health remains unauthenticated. Each deployed policy instance has an explicit, exact binding. For example: ```text tenant-engine=system:serviceaccount:tenant-engine:tenant-engine user-engine=system:serviceaccount:user-engine:user-engine ``` Unknown systems, missing or invalid tokens, audience mismatch and principal mismatch fail closed. TokenReview unavailability returns 503 rather than an authorization answer. Tokens and reviewer credentials are re-read rather than cached across rotation. Three modes support promotion: `disabled`, `warn`, and `enforce`. Warn mode records the same authentication failures without logging credentials. It is a bounded migration aid, not a conformant steady state. The reviewed desired manifests select `enforce`; promotion still follows FLEX-WP-0011 and requires a new immutable image digest plus caller rollout evidence. ## Rejected alternatives - NetworkPolicy alone proves network position, not workload identity. - A shared header secret has broad replay and rotation blast radius and cannot bind a Kubernetes workload principal. - Application mTLS would add a separate certificate lifecycle where the cluster already has short-lived projected workload identity. - Using the caller token itself to invoke TokenReview would grant callers an unnecessary API permission. A narrow reviewer ServiceAccount holds only `create` on `tokenreviews.authentication.k8s.io`. ## Consequences - Caller identity is bound once at the flex-auth ingress and cannot be swapped by changing request JSON. - flex-auth depends on the Kubernetes authentication API for uncached checks; an outage fails closed with 503. - Each new protected system needs an explicit binding and projected caller token. There is no wildcard binding. - Source and desired state reach A2, while the live declaration remains A0 until the immutable digest is promoted and probed.