Helm-adopted the kubectl-managed user-engine pin, promoted sha256:138aa347 warn then enforce. Reviewer volume needs fsGroup 65532; reviewer tokens must use the API default audiences or TokenReview 401s on this k3s. Live probe from user-engine-8569d7cb87-fp7px: 200 / 401 / 403. tenant-engine is unchanged. tenancy.current.A stays 0 until that pin moves.
12 KiB
| id | type | title | domain | repo | status | owner | topic_slug | planning_priority | planning_order | depends_on_workplans | related_workplans | created | updated | state_hub_workstream_id | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| FLEX-WP-0015 | workplan | Tenancy posture declaration and inbound caller authentication | infotech | flex-auth | active | claude | netkingdom | P1 | 150 |
|
2026-08-17 | 2026-08-19 | 31846b19-c2a3-428e-950b-5985bc9146eb |
FLEX-WP-0015 - Tenancy posture declaration and inbound caller authentication
Answer rapp-postgres's review request on NetKingdom Tenancy Posture v0.1
(message 82ec43ce), publish flex-auth's posture vector, and close the one
real defect the review surfaced.
Review output: docs/tenancy-posture-review.md
Declaration: tenancy.yaml (repo root, per framework §5.1)
Why this workplan exists
The original five axes described flex-auth unevenly; draft-8's sixth availability axis and canonical provider declaration now cover the remaining shape. Assessing against them turned up two things we did not know we were carrying:
/v1/checkauthenticates no caller. Any workload with network reach to the ClusterIP Service can assert any subject and any tenant and receive an authoritative allow. flex-auth is the estate's authorization oracle and trusts its callers completely. Framework levelA0.- The tenant-engine live-roles adapter is built and unwired. No non-test caller exists. The IAM Profile live re-query reads as a capability we have and is not one.
The framework itself needs six amendments, two of them corrections of
statements it makes about flex-auth. Those are in the review document and go
back to rapp-postgres as review output, not as work here.
Scope discipline: this workplan closes flex-auth's own gaps and answers
the review. It does not build fleet-level conformance tooling, does not adopt
AuthZEN, and does not touch production enforcement (policy.enabled stays off
per FLEX-WP-0007).
Tasks
id: FLEX-WP-0015-T01
status: done
priority: high
state_hub_task_id: "0a32500d-511a-4bd7-972e-de4cd3e62dd9"
Publish posture and answer the review. Write tenancy.yaml and
docs/tenancy-posture-review.md; reply to rapp-postgres with the posture
vector, the A4 ruling, the internal-hop ruling, and the two factual
corrections. Done 2026-08-17.
id: FLEX-WP-0015-T02
status: progress
priority: high
state_hub_task_id: "b2e87a81-b63d-4be4-ad44-01426b7e6f74"
Close the A0 — authenticate callers of /v1/check. Decide first, build
second: this is a production-facing security boundary on a service two
consumers already depend on, and the wrong instrument is worse than the delay.
Waiting on ops-warden (asked 2026-08-17): it owns how workloads prove
identity in this estate, and it is a flex-auth PEP, so it implements the
calling side of whatever we choose. warden route find was run first per the
credential-routing rules — the catalog holds credential lanes and has no entry
for service-to-service caller authentication as a pattern, which is part of
what was asked. Our stated instinct is ServiceAccount TokenReview; the
question is open pending their answer. Nothing is built until it lands.
Record an ADR covering at minimum:
- What identifies a caller — Kubernetes ServiceAccount token review, mTLS via
the cluster's own CA, or a shared secret header. Note that the Deployment
currently sets
automountServiceAccountToken: false, so option one changes the pod spec. - Whether caller identity only authenticates, or also constrains: may
user-engineask questions about resources owned bytenant-engine? A caller allowlist persystemis the natural shape and flex-auth's registry already keys onsystem. - Fail-closed vs fail-open during rollout. Given
policy.enabledis off in production and both consumers are ours, a warn-only phase that logs unauthenticated callers before rejecting them is available and probably right. - Whether NetworkPolicy is a sufficient interim control to declare
A1honestly before the real fix lands.
Target level A2 — a single inbound choke point binding caller identity —
with the §13 evidence artifact: a test that an unbound request is refused.
Ship through the FLEX-WP-0011 staged-promotion path, not by direct apply.
2026-08-18 source outcome: ADR 0004 selects audience-scoped Kubernetes
ServiceAccount TokenReview with a separately projected reviewer identity and
exact resource.system → ServiceAccount bindings. Both check endpoints share
the choke point; missing/mismatched identity fails 401/403 and reviewer outage
fails 503. Unit and handler tests include the required unbound request. Source
committed as 1e1e077.
2026-08-19 overlay outcome: the sanctioned Helm chart did not render caller
auth at all, so a FLEX-WP-0011 pin of the new digest would have stayed
disabled. That is now wired. Desired emergency manifests and production
values select warn, not enforce — applying the previous enforce
manifests was the hazard. CI image sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
(main-3de72fe, built 2026-08-18T13:25Z) contains the TokenReview flags.
The running cluster digest is still unchanged, so tenancy.current.A
remains 0 while tenancy.implemented.A is 2.
Better path than a global enforce flip. The two production Deployments
are independently rollable (FLEX-WP-0011). USER-WP-0023-T03 only probes
flex-auth-user-engine. Serializing that probe on tenant-engine's caller
status would 401 tenant-engine writes if we enforced them together, and
would delay user-engine A2 evidence for no safety gain. Sequence:
- Pin the caller-auth digest in overlay + emergency manifests — done
2026-08-19, first mode
warnon both consumers. - Operator: promote each pin in warn via
helm upgrade --install flex-auth-<consumer> charts/flex-auth --namespace flex-auth -f values/<consumer>.yaml. Isolated canary may boot the same digest with caller-auth disabled. Do notkubectl applyan enforce manifest. user-engine done 2026-08-19 (Helm releaseflex-auth-user-enginerev 4). Live objects were kubectl-managed; they were labelled for Helm adoption first. Two production bugs had to be fixed during warn: the reviewer volume neededfsGroup: 65532, and the reviewer token must use the API server's default audiences (a customhttps://kubernetes.default.svcaudience 401s TokenReview on this k3s). tenant-engine is still the old digest. - Confirm warn logs per consumer.
user-engineis migrated and deployed as of 2026-08-18 (imagesha256:c501aeb2…, token at/var/run/secrets/flex-auth-caller/token). On 2026-08-19 they confirmed USER-WP-0023-T03 stays wait and they will not run the three assertions against warn (messagef963906d).tenant-enginesource and desired manifests already project that token and send it; live digest is still unconfirmed. Warn is safe either way.ops-wardenadopts the calling side on its own schedule. - Flip user-engine only to
enforce(callerAuth.mode: enforceinvalues/user-engine.yaml, same digest). Then they capture the live negative probe from a user-engine pod. The three assertions are already written in user-enginedocs/flex-auth-caller-identity.md; they must not run against warn, because "no token returns 401" would still be a decision. Done 2026-08-19 from poduser-engine-8569d7cb87-fp7px: (1) Bearer projected token → 200decision:350b46fb42989606; (2) no Authorization → 401unauthenticated; (3)resource.system=tenant-engine→ 403forbidden. Digests: flex-authsha256:138aa347…, user-enginesha256:c501aeb2…. Live user-engine also neededfsGroup: 10001or the projected token was0440 root:rootand uid 10001 could not send it — persist that in rapp-user-enginemanifests/runtime.yaml. - Flip tenant-engine to enforce only after its warn logs are clean.
- Only then may
policy.enabledflip anywhere —ops-wardennames that the real deadline, and it is the same gate as FLEX-WP-0007.
Operator gate. Default KUBECONFIG pointed at HostEurope and is
Unauthorized. railiance01 is ~/.kube/config-railiance01. user-engine
warn→enforce used that kubeconfig. tenant-engine warn-then-enforce is
the remaining operator step. Promotion follows FLEX-WP-0011 and the CI
image, not a hand-built image.
RISK-F-0001 (risk-nexus) tracks this A0 externally. Their NetworkPolicy
question was answered 2026-08-18: both Deployments carry an ingress policy
restricted to one namespace and one pod label, predating this work — so the
reachable set was never "any pod in the cluster", and a sentence of mine that
said so was corrected to them.
id: FLEX-WP-0015-T03
status: done
priority: medium
state_hub_task_id: "64eb7652-3b67-4bfb-879b-8588deeec8b5"
Wire or delete internal/adapters/tenantengine. The adapter is complete
and has no non-test caller; decision.Engine has no field for it. Both
outcomes are conformant, silence is not.
Deciding factor is whether any live policy needs tenant_roles for a
privileged, destructive, credential-vending or aal2-class decision — the
IAM Profile's own trigger list. If yes, wire it into the decision path with a
timeout and an explicit unavailable-path decision (AttachToContext already
carries tenant_roles_available: false for exactly this), and note the new
synchronous dependency on tenant-engine's availability. If no, delete it and
say so in the review record rather than leaving it as latent capability.
Update tenancy.yaml I either way.
Completed 2026-08-18 by deletion. Repository-wide search found no non-test
caller and no policy consuming tenant_roles; wiring it would add a
synchronous dependency without a decision that uses the result. The adapter
and its isolated tests were removed, and the review records that any future
live-role policy must introduce the dependency explicitly.
id: FLEX-WP-0015-T04
status: wait
priority: low
state_hub_task_id: "06432560-c28c-4de2-a672-87e74be54a6a"
AuthZEN evaluation endpoint (framework A4). Deliberately deferred, not
backlogged. POST /access/v1/evaluation translating onto the existing engine
beside /v1/check, non-breaking.
Trigger to start: either a PEP arrives that flex-auth's operator does not control, or a delegated backend under FLEX-WP-0004 needs uniform addressing. Until one of those, A4 buys swappability nobody can use.
Note when starting: AuthZEN standardises the envelope, not the action
vocabulary — it does not end action-string copying between repos. The cheaper
fix for that is serving registry.Actions read-only, which is independent of
this task and may be worth doing first.
id: FLEX-WP-0015-T05
status: done
priority: medium
state_hub_task_id: "9195ba20-ab0f-4d75-b293-86978073beb1"
Guard the declaration. Framework §12 requires verifying the declared posture still holds — against our own declaration, not a universal maximum.
Small mechanical check, make verify-posture, in the shape tenant-engine used
for verify-pin (bash, no dependency tree). Assert what code can actually
prove: that the /v1/check handler has caller authentication iff
tenancy.yaml claims A >= 2; that tenantengine has a non-test caller iff
I >= 3; that the production Deployment carries no --log and no volume iff
R is n/a. Exit 1 on drift.
Designed for invisible failure per §12: posture regression returns correct-looking responses, exactly like the two silent pin rollbacks the estate has already been bitten by.
Completed 2026-08-18. make verify-posture checks the current/implemented
distinction, both authenticated handlers, warn-or-enforce desired manifests
and overlay pins, TokenReview RBAC, absence of a latent tenant-engine caller,
and the stateless deployment assumptions behind R: n/a. First production
pin is warn; enforce is the end state, flipped per consumer.