These workplans exist only in the retired local hub. Their random pre-ADR-007 identifiers are refused by C-06 as stale references, so they cannot be registered. Deriving from the canonical record id takes no identity from anything: central does not hold them and the old ids die with the cache. Records central already holds were deliberately left untouched. Refs CUST-WP-0068-T06 Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
97 lines
5.1 KiB
Markdown
97 lines
5.1 KiB
Markdown
---
|
|
id: NK-WP-0026
|
|
type: workplan
|
|
title: "Promote user-engine workload identity to flex-auth"
|
|
domain: infotech
|
|
repo: net-kingdom
|
|
status: finished
|
|
owner: codex
|
|
topic_slug: netkingdom
|
|
created: "2026-08-18"
|
|
updated: "2026-08-19"
|
|
state_hub_workstream_id: "3e8965aa-494a-5dcf-a11d-b768c196c548"
|
|
---
|
|
|
|
# NK-WP-0026 — user-engine caller identity rollout
|
|
|
|
```task
|
|
id: NK-WP-0026-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "294eb50e-2d54-59f1-a793-d10e53e33020"
|
|
```
|
|
|
|
Declare a non-automounted `user-engine` ServiceAccount and a one-hour projected
|
|
token with audience `flex-auth`; mount only that token into the portal. Source
|
|
completed 2026-08-18. Existing NetworkPolicy already permits only the named
|
|
flex-auth user-engine instance on port 8080.
|
|
|
|
```task
|
|
id: NK-WP-0026-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "d24461e9-c378-58ac-97ed-60ad6e563d47"
|
|
```
|
|
|
|
Both sides promoted and probed. Verified live on railiance01, 2026-08-19, by
|
|
net-kingdom against the cluster rather than against another repo's assertion.
|
|
|
|
**Deployed digests**
|
|
|
|
| Side | Object | Digest |
|
|
| --- | --- | --- |
|
|
| user-engine | `deploy/user-engine` (ns `user-engine`), pod `user-engine-8569d7cb87-fp7px` | `forgejo.coulomb.social/coulomb/user-engine@sha256:c501aeb204154d85017565a87fd34cff12e5c48f600d124d3f8c82f11bb9d59c` |
|
|
| flex-auth | `deploy/flex-auth-user-engine` (ns `flex-auth`), pod `flex-auth-user-engine-b745b6b5c-zhsfv` | `forgejo.coulomb.social/coulomb/flex-auth@sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b` |
|
|
|
|
flex-auth serves with `--caller-auth-mode enforce` and
|
|
`--caller-binding user-engine=system:serviceaccount:user-engine:user-engine`.
|
|
The warn stage was run on flex-auth's side under FLEX-WP-0011 / FLEX-WP-0015-T02;
|
|
net-kingdom observed the end state, not the intermediate warn window.
|
|
|
|
**The T01 caveat is cleared.** The old digest did not read the projected file.
|
|
The deployed digest does: `user_engine/runtime.py:45` makes
|
|
`USER_ENGINE_FLEX_AUTH_TOKEN_FILE` a *required* setting (`_required(...)`, so the
|
|
portal cannot start without it), and
|
|
`user_engine/adapters/flex_auth.py:62-68` re-reads the file **per decision** —
|
|
deliberately, so projected-token rotation needs no restart — and sends it as
|
|
`Authorization: Bearer`. Both were read out of the running container, not out of
|
|
the source tree.
|
|
|
|
**Probes** — `POST /v1/check` against
|
|
`flex-auth-user-engine.flex-auth.svc.cluster.local:8080`, run from inside the
|
|
workload pods so NetworkPolicy and identity are exercised as in production. All
|
|
are read-only decision queries; nothing in the cluster was mutated.
|
|
|
|
| Probe | Run from | Credential | Result |
|
|
| --- | --- | --- | --- |
|
|
| valid | `user-engine-8569d7cb87-fp7px` | the pod's own projected token, audience `flex-auth` | **HTTP 200**, `decision:d9aef25f08e17b84`, `effect: allow`, `reason: self_service`, `matched_rule: self_service`, `policy_version: v1` |
|
|
| missing token | `user-engine-8569d7cb87-fp7px` | no `Authorization` header | **HTTP 401** `unauthenticated` |
|
|
| wrong system | `user-engine-8569d7cb87-fp7px` | valid user-engine token, body asserting `resource.system: tenant-engine` | **HTTP 403** `forbidden` |
|
|
| wrong system (network path) | `tenant-engine-6c6dcbddbb-4v26w` | tenant-engine's own projected token, against the *user-engine* PDP | connection refused — NetworkPolicy denies the cross-service path before flex-auth sees it |
|
|
|
|
Note on the wrong-system probe, because it differs from what flex-auth reported.
|
|
flex-auth's `tenancy.yaml` states "a token bound to the other protected system
|
|
returns 403". net-kingdom could not reproduce that literal case: the
|
|
tenant-engine pod cannot reach the user-engine PDP at all (Errno 111), so the
|
|
403 never arises on that path. What *is* reproducible, and is the same
|
|
substitution attack, is a caller authenticated as one system asserting another
|
|
system in the request body — ADR-0004's stated threat, "a caller could represent
|
|
another protected system" — and that returns 403. The estate position is
|
|
therefore stronger than claimed (two independent layers refuse it), but the
|
|
claimed evidence is not the evidence that exists. Recorded rather than smoothed.
|
|
|
|
**Manifest drift, found and closed.** `sso-mfa/k8s/user-engine/runtime.yaml`
|
|
still pinned `sha256:e3b5f65b…` — the digest T01 warned must not be applied —
|
|
while the cluster ran `c501aeb2…`. Anyone re-applying the repo's own manifest
|
|
would have rolled the portal back to an image that does not read the token file,
|
|
against a PDP now in `enforce`: every authorization call would 401 and the portal
|
|
would fail closed. The manifest is now pinned to the deployed digest and
|
|
`kubectl diff -f sso-mfa/k8s/user-engine/runtime.yaml` is **empty, exit 0** —
|
|
declared state and live state agree.
|
|
|
|
**Observation routed to flex-auth, not a blocker.** A syntactically invalid
|
|
bearer token returns **HTTP 503 `caller authentication unavailable`**, not 401.
|
|
ADR-0004 reserves 503 for TokenReview *unavailability* and puts invalid tokens
|
|
with the 401 class. It fails closed either way, so there is no bypass, but a
|
|
malformed credential is being reported as a flex-auth outage — which will
|
|
mislead whoever reads the first page of an incident.
|