Offline steps exercised against the secrets-engine example; live caller-auth steps remain unexercised. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 295952@bnt-lap001 Assistant-Session: e93f64ad-516c-46eb-9666-aad8d300c477
6.4 KiB
Add a protected system to flex-auth
Exercise status: unexercised
Workplan task: NK-WP-0009-T05
Pattern(s): authorization boundary (docs/platform-identity-security-architecture.md, ADR-0006); IAM Profile v0.3 consumption
Exercise notes: the offline commands in steps 4 and 5 were run once by Claude
on 2026-09-28 against the secrets-engine example in a local flex-auth
checkout and produced the outcomes listed under Verification. The live
caller-authentication steps (6 and 7) have not been run. Nobody has yet
completed the whole tutorial, so it stays unexercised.
Outcome
Your system publishes its resources and actions to flex-auth, sends check requests carrying a projected caller identity, enforces the decision it gets back, and is refused when the caller is wrong.
Prerequisites
- [owner: flex-auth] A local checkout of
flex-authwith Go, to rungo run ./cmd/flex-auth. Readflex-auth/docs/decision-record-contract.md. - [owner: your system's repo] A system id and a list of the things it protects and the actions it performs on them.
- [owner: railiance-platform / package owner, ADR-0015] A Kubernetes ServiceAccount that will represent your system. Package and runtime declarations belong to the owner, not to this repo.
- [owner: net-kingdom] Accepted IAM Profile v0.3 for the identity you
present (
canon/standards/iam-profile_v0.3.md).
Architecture context
flex-auth is the policy decision point; your system is the enforcement point.
flex-auth never sees secret material, only coordinates (ids, types,
attributes). The worked example throughout is secrets-engine
(flex-auth/examples/secrets-engine/). Two gates protect a consumer:
caller authentication (who is asking) and the policy decision (may they). A
consumer running with caller auth in warn mode is not protected.
Steps
- [owner: your system's repo] Define the resource types and the action
vocabulary. Actions are your system's own strings; do not infer them.
Copy the shape of
flex-auth/examples/secrets-engine/protected_system_manifest.yaml:resource_types(name, scope level, planes) andactions(name, capabilities, planes, exposure modes, required context). Keep a verb that is not a real gate out of the list (revokeis deliberately not an action in the example; the CLI verb gates asdeactivate). - [owner: your system's repo] Publish resource manifests and, for callers, a subject manifest: one service identity per protected system. Send empty lists rather than omitting or guessing attributes.
- [owner: flex-auth] Write the policy package (Markdown with Rego) and fixtures covering every allow and every denial branch, including wrong tenant, unknown subject and unknown action.
- [owner: flex-auth] Validate and load offline:
go run ./cmd/flex-auth validate -kind policy -file <policy_package.md>thengo run ./cmd/flex-auth load-registry -file <registry_snapshot.json>. - [owner: flex-auth] Evaluate a check request locally:
go run ./cmd/flex-auth check -registry <registry_snapshot.json> -policy <policy_package.md> -request <request.json>. A request istenant,subject,action,resourceandcontext. The result is a decision envelope (flex-auth.decision-record.v1) witheffect,reason, and a deterministic decisionid. - [owner: package owner] Give the caller a projected identity: a
short-lived, audience-scoped ServiceAccount token, and register the exact
binding
<system>=system:serviceaccount:<namespace>:<serviceaccount>on the flex-auth pin with audienceflex-auth. Send the token asAuthorization: Bearer. Use the in-cluster trailing-dot FQDN of the pin, never a bare service name. - [owner: flex-auth] Set caller authentication to
enforceand run the four negative tests fromflex-auth/docs/operator-caller-access-path.md(no header, wrong ServiceAccount, wrong audience, expired token). - [owner: your system's repo] Enforce the envelope:
allowproceeds;denyblocks;redactandaudit_onlyapply their obligations; any error or missing decision fails closed. Persist the decision id with every deny, redaction, export and privileged action.
Verification
Done when:
validateandload-registryexit 0 on your package and snapshot.- Offline
checkreturnsallowfor a permitted request, anddenywith reasonwrong_tenant,unknown_subjectandunknown_actionfor the matching negative requests. (Observed on thesecrets-engineexample:allow/catalog_lane_policy_matched;deny/wrong_tenant;deny/unknown_actionforrevoke;deny/unknown_subject.) - Against the live pin under
enforce: a valid token returns 200 and anallow; no header returns 401; a token for the wrong ServiceAccount returns 403; a wrong-audience token returns 401; an expired token returns 401. All four negatives must be refused before policy is evaluated. - A pin whose logs still show
warnis reported as not enforcing. That is a failed check, not a pass.
Rollback
- Offline artifacts are files; revert them in git.
- On the live pin, set caller authentication back only as a recorded,
time-boxed exception owned by the package owner, and never leave a
consumer in
warnas the resting state. - Removing a protected system means removing its binding and manifests; consumers must then fail closed.
Threat checks
- Never send a permanent token; mint short-lived tokens per use.
- Never point a consumer at a bare in-cluster service name; workstation resolvers can answer it with an unrelated host. Use the trailing-dot FQDN.
- A port-forward bypasses NetworkPolicy, so caller authentication is the only gate on an operator path.
- Never put secret values in a resource attribute or a check request.
- Do not give raw upstream group names platform meaning; map them explicitly per tenant.
- Do not apply stale tenant-engine reference YAML; take manifests from the current owner package.
Ownership notes
| Concern | Owner |
|---|---|
| Action vocabulary, resource manifests, enforcement of decisions | the protected system's repo |
| Policy packages, decision envelope, caller-auth verification | flex-auth |
| ServiceAccount, package and runtime declaration | package owner under ADR-0015 |
| Identity contract (IAM Profile v0.3) | net-kingdom |
| Credential routing for the token | ops-warden (pointer only) |