diff --git a/docs/flex-auth-caller-identity.md b/docs/flex-auth-caller-identity.md index ccc80b2..ea89c56 100644 --- a/docs/flex-auth-caller-identity.md +++ b/docs/flex-auth-caller-identity.md @@ -1,6 +1,6 @@ # flex-auth caller identity contract -Status: caller side implemented and deployed; live proof pending flex-auth A2 promotion (FLEX-WP-0015-T02). +Status: source implemented; production promotion pending. user-engine calls `flex-auth-user-engine` with a projected Kubernetes ServiceAccount token whose audience is exactly `flex-auth`. The adapter reads @@ -23,80 +23,6 @@ The tenant authority seam is distinct: user-engine identifies itself as actor own flex-auth decision before store access. Tenant ids remain opaque and are URL-encoded. No client may infer existence from an unauthorized read. -As of 2026-08-18 the deployed user-engine image carries this file-based caller -token, so the caller side is no longer the laggard. The remaining asymmetry runs -the other way: flex-auth's A2 enforcement is implemented but unpromoted, so the -header is sent and ignored. That ordering is safe — a caller that authenticates -against a service that does not yet check is harmless, whereas the reverse -would have returned 401 to every decision. - -## Live promotion probe (USER-WP-0023-T03) - -The caller side is deployed: image `sha256:c501aeb2…` (user-engine `7604d31`) -runs in namespace `user-engine` as ServiceAccount `user-engine`, with the -projected token mounted at `/var/run/secrets/flex-auth-caller/token` under -audience `flex-auth` and `USER_ENGINE_FLEX_AUTH_TOKEN_FILE` pointing at it. - -**This probe cannot pass yet, and the reason is upstream.** FLEX-WP-0015-T02 -is `wait`: ADR 0004's TokenReview choke point is implemented in flex-auth -source, but the running digest is unchanged, so production still accepts -unauthenticated callers. Our Authorization header is currently sent and -ignored. Run the probe only after flex-auth promotes A2 through -FLEX-WP-0011; before then step 2 returns a normal decision instead of 401 and -would record a false pass. - -Run from an operator shell with cluster credentials (this repo's sessions do -not hold them). `POD` is any ready user-engine pod. - -```bash -POD=$(kubectl -n user-engine get pod -l app.kubernetes.io/name=user-engine \ - -o jsonpath='{.items[0].metadata.name}') -CHECK=http://flex-auth-user-engine.flex-auth.svc.cluster.local:8080/v1/check -BODY='{"actor":{"issuer":"https://kc.coulomb.social","subject":"probe", - "tenant":"tenant:friendly:binky","principal_type":"human", - "audience":["user-engine"],"roles":["tenant-admin"]}, - "resource":{"system":"user-engine","type":"user-engine:user","id":"probe"}, - "action":"user.update","tenant":"tenant:friendly:binky", - "correlation_id":"probe-t03","context":{}}' -``` - -1. **A valid caller succeeds.** Expect `200` and a decision id. - ```bash - kubectl -n user-engine exec "$POD" -c portal -- sh -c \ - "curl -sS -o /dev/null -w '%{http_code}\n' -X POST $CHECK \ - -H 'Content-Type: application/json' \ - -H \"Authorization: Bearer \$(cat /var/run/secrets/flex-auth-caller/token)\" \ - -d '$BODY'" - ``` -2. **No token is refused.** Expect `401`, not a decision. - ```bash - kubectl -n user-engine exec "$POD" -c portal -- sh -c \ - "curl -sS -o /dev/null -w '%{http_code}\n' -X POST $CHECK \ - -H 'Content-Type: application/json' -d '$BODY'" - ``` -3. **user-engine cannot represent another protected system.** Re-run step 1 - with `resource.system` set to `tenant-engine`. Expect a refusal from the - binding, not an allow: the token binds `user-engine` to - `system:serviceaccount:user-engine:user-engine` only. - -Record all three results, the flex-auth digest they ran against, and the -user-engine digest, in USER-WP-0023-T03 before marking it done. A pass on -steps 1 and 3 without a 401 on step 2 means enforcement is still off. - -## Live cross-service check (USER-WP-0021) - -Owed separately to tenant-engine after production served 404 on the lifecycle -routes from 2026-08-13 to 2026-08-16 while our contract-level suite passed -throughout. Contract evidence structurally cannot see a pin rollback, so this -must be exercised live, from a pod, against the real authority. - -Use a disposable tenant — never a real one, since retire is a lifecycle -mutation. Through the portal's own platform routes as a platform operator: -`GET` the record, `PATCH` its display name, `retire`, then `reactivate`, -echoing each returned version as the next `If-Match`. Expect `200` throughout -and no `404`, which is what the rollback window produced. Capture the -tenant-engine digest alongside the results; both silent rollbacks this month -were digest-level and neither raised an alert. - -This shares the operator rollout with the T03 probe above and is most -efficiently run in the same session. +The current deployed image predates this file-based caller token. Promote only +with the matching flex-auth A2 image and bindings; otherwise enforcing flex-auth +will correctly return 401 to the old caller. diff --git a/workplans/USER-WP-0023-flex-auth-caller-identity.md b/workplans/USER-WP-0023-flex-auth-caller-identity.md index ac86853..7cd56c7 100644 --- a/workplans/USER-WP-0023-flex-auth-caller-identity.md +++ b/workplans/USER-WP-0023-flex-auth-caller-identity.md @@ -59,25 +59,4 @@ ServiceAccount token manifest. Prove a valid caller succeeds, no token returns 401, and user-engine cannot represent another protected system. This is a live operator rollout and was not performed by the source change. -2026-08-18 readiness review: our half is done. The `rapp-user-engine` managed -package is now the apply home, and image `sha256:c501aeb2…` from `7604d31` — -which contains the caller-token change — is live and passed `make verify-live`. -The projected ServiceAccount token manifest is in place: audience `flex-auth`, -mounted at `/var/run/secrets/flex-auth-caller/token`, with -`USER_ENGINE_FLEX_AUTH_TOKEN_FILE` pointing at it. flex-auth's deploy carries -the binding `user-engine=system:serviceaccount:user-engine:user-engine`. - -The blocker is now precisely one upstream item. FLEX-WP-0015-T02 is `wait`: -ADR 0004's TokenReview choke point exists in flex-auth source, but the running -digest is unchanged, so production still accepts unauthenticated callers and -our Authorization header is sent and ignored. Running the probe today would -pass steps 1 and 3 and silently fail step 2 — a false pass on the only -assertion that proves enforcement. The probe is therefore written down rather -than run: see `docs/flex-auth-caller-identity.md`, which carries all three -checks as commands plus the digests to record. - -This task stays `wait` on FLEX-WP-0015-T02 promotion through FLEX-WP-0011, -and on an operator shell with cluster credentials, which agent sessions in -this repo do not hold. - Contract: `docs/flex-auth-caller-identity.md`.