secrets-engine delivered the action vocabulary T01 asked for: twelve actions read out of cli.py, not the example vocabulary. The gate earned its keep -- four would have been inferred wrongly, and revoke, the obvious thirteenth, does not exist as an action at all. It gates as deactivate, which is also reached from lifecycle deactivate. docs/secrets-engine-action-vocabulary.md records the list and the four traps. examples/secrets-engine/ carries the package, both manifests, a loadable registry snapshot, 26 fixtures, five check requests, and a README. validate -kind policy is valid with 22/22 Rego tests and 26/26 fixtures. allow_ttl is 15m, stated in the package rather than inherited from the engine default: these decisions authorize live secret operations, so the reliance window belongs where a reviewer sees it. Per FLEX-DEC-2026-004 it is authority to issue, not authority to keep using what the operation produced. destroy is the dual-control case, gated on a context.approval claim marked approved with two distinct approvers, repeated entries counting once. flex-auth checks what the claim says and deliberately does not re-derive its temporal validity, signature, or supersession -- those are approval-engine's to assert and the PEP's to verify against the live claim, per the split accepted in FLEX-DEC-2026-006. It stays in the package though its handler raises before the gate, so the rule is reviewed and fixtured before SECRETS-WP-0007-T04 opens the path. Following the FLEX-WP-0010-T02 precedent the denial ladder has no action_not_granted branch: one subject holding all twelve actions could never reach it, and a rule that cannot fail reads as control that is not there. Registering a second calling identity is the revisit trigger. Not deployed. No flex-auth-secrets-engine pin exists yet (T04), so their policy pin stays unset and fail-closed until T05. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JTbVXpEiXA7mNJVpDnEPcB Assistant: claude-code Assistant-Model: opus Assistant-Process: 412054@bnt-lap001 Assistant-Session: 3968fae1-8d59-4209-9bd6-c22594b8ab19
7.6 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-0021 | workplan | secrets-engine consumer policy package and cluster-local pin | infotech | flex-auth | active | claude | netkingdom | P1 | 210 |
|
|
2026-09-06 | 2026-09-06 | b01f655e-f71a-50ae-b110-178557f07c63 |
FLEX-WP-0021 — secrets-engine consumer policy package and cluster-local pin
Opened by FLEX-DEC-2026-005, answering secrets-engine's two questions of
2026-09-05. Both resolve to one piece of work in one order: publish the
package, then pin it.
Why this exists
secrets-engine has already built its side. Commit 627810b applies flex-auth's
PDP answers — resource.type: secret-catalog-lane, resource.system: secrets-engine, catalog id as request.resource.id — and validates
ActionAuthorization.decision.binding.request_digest against
flex-auth.decision-record.v1 with status: approved inside validity and
distinct approvers.
Two things it cannot supply itself:
SECRETS_ENGINE_AUTHORIZATION_POLICY_PACKAGE/_VERSIONare required configuration with no fallback, deliberately.secrets-engine.lifecycle/v1is example vocabulary, not a published package. Until flex-auth publishes a real one, that configuration cannot be set to anything true.- There is no address for secrets-engine to call. flex-auth runs as
per-consumer cluster-local pins with default-deny ingress admitting one
approved workload each (
deploy/README.md); no pin exists for secrets-engine. Its 2026-09-06 probe finding no reachable PDP found the design working, not an outage.
Glas real-key execution (SECRETS-WP-0009-T03) is the workload waiting.
Boundary
flex-auth authors the policy package; secrets-engine owns the action vocabulary
it encodes and the enforcement around the verdict. flex-auth never mutates the
approval object — that is approval-engine's (security-layer-model_v0.7 §9.4)
— and validates approvals only as input claims. This plan does not default,
weaken, or supply a fallback for the consumer's package pin.
1. Obtain the real action vocabulary from secrets-engine
id: FLEX-WP-0021-T01
status: done
priority: high
state_hub_task_id: "3c191808-6fe5-5a9b-9a68-a4ce4a672dbd"
Owner: flex-auth to request and document; secrets-engine owns the answer.
- Ask secrets-engine for the authoritative action list over
secret-catalog-lane— the operations it will actually gate, not thesecrets-engine.lifecycle/v1example set. - Record it in
docs/secrets-engine-action-vocabulary.md, followingdocs/tenant-engine-action-vocabulary.md. - Record the subject classes that may appear, and which of them are service accounts versus humans behind an approval.
Gate: every action in the vocabulary is named by secrets-engine, not inferred here. An inferred action is a blocker, not a default.
Done 2026-09-06. secrets-engine delivered twelve actions in their
docs/gated-actions.md, read out of cli.py: apply, provision, rotate,
verify, handoff, wrap, exec, deactivate, suspend, destroy,
compromise, reactivate. Recorded in
docs/secrets-engine-action-vocabulary.md. The gate earned its keep: four
would have been inferred wrongly, and revoke — the obvious thirteenth — does
not exist as an action at all.
2. Publish secrets-engine.catalog-lane.lifecycle v1
id: FLEX-WP-0021-T02
status: done
priority: high
state_hub_task_id: "38770813-dfcc-5711-bba3-0db50d3af135"
Owner: flex-auth.
- Write
examples/secrets-engine/policy_package.mdwithid: secrets-engine.catalog-lane.lifecycle,version: v1, and an explicitallow_ttl. An omitted TTL takes the 15m engine default;none/0sdenies withallow_lifetime_unstatedrather than granting standing access. - Add
protected_system_manifest.yaml,subject_manifest.yaml,resource_manifest.yaml, andregistry_snapshot.jsonfor the namespace. - Add allow and deny fixtures in
policy_fixtures.yamlpluscheck_request_*.json, covering at minimum: an allow per vocabulary action, wrong-tenant deny, unknown-subject deny, and an approval-claim-absent deny. - Add
examples/secrets-engine/README.md.
Gate: flex-auth validate passes, the fixture tests pass, and the package
digest is stable across two runs.
Done 2026-09-06. examples/secrets-engine/ carries the package
(allow_ttl: 15m stated explicitly), both manifests, a loadable
registry_snapshot.json, 26 fixtures, five standalone check requests, and a
README. validate -kind policy reports valid with 22/22 Rego tests and 26/26
fixtures passing. destroy is the dual-control case, gated on a
context.approval claim marked approved with two distinct approvers; flex-auth
checks what the claim says and does not re-derive its validity, signature, or
supersession (FLEX-DEC-2026-006). Per the FLEX-WP-0010-T02 precedent the
denial ladder has no action_not_granted branch, because one subject holding
all twelve actions could never reach it.
3. Confirm the digest join against a real decision record
id: FLEX-WP-0021-T03
status: todo
priority: high
state_hub_task_id: "8f7e5cdd-777e-5f54-9b92-c72b79f65672"
Owner: flex-auth to emit; secrets-engine to verify.
- Emit a real
DecisionEnvelopefrom the package above and hand it to secrets-engine as the replay fixture for the join it built in627810b. - Verify
binding.request_digestreproduces as SHA-256 over canonical JSON of tenant/subject/action/resource/context perdocs/canonical-request-digest.md. - Verify
provenance.registry_snapshot_digestis present — §9.7.2 promotes it to a conformance prerequisite andFLEX-WP-0019closed that gap.
Gate: secrets-engine confirms its validator accepts the real record unchanged. A validator change on their side is their work-record, not closed from here.
4. Stand up the flex-auth-secrets-engine pin
id: FLEX-WP-0021-T04
status: wait
priority: high
state_hub_task_id: "f4e8709a-65dd-5172-97ae-e7c3432afb22"
Owner: flex-auth; deployment approval required.
- Add
deploy/flex-auth-secrets-engine.yamlas a three-document manifest —Deployment,Service, default-denyNetworkPolicyadmitting ingress from the secrets-engine workload only — following the two existing pins. - Promote through the Railiance overlay (
railiance/app.toml,charts/flex-auth,values/), not by editing the flattened emergency files. - Build in CI and deploy by immutable digest, never by tag. Do not roll the other pins: they are pinned to their own digests precisely so one policy change does not move another consumer.
- Start
callerAuth.modeinwarn. Flip toenforceonly after secrets-engine adopts a calling identity and its warn logs are clean, asFLEX-WP-0016did for ops-warden.
Gate: the pin answers POST /v1/check for the secrets-engine workload and
default-denies every other source; the other two pins are unchanged.
5. Hand the pin coordinates back and close
id: FLEX-WP-0021-T05
status: wait
priority: medium
state_hub_task_id: "f0828871-fd65-5d8c-adfd-28b13fedd2b0"
Owner: flex-auth.
- Reply to secrets-engine with the Service DNS, the package id and version to
set in
SECRETS_ENGINE_AUTHORIZATION_POLICY_PACKAGE/_VERSION, and thecallerAuthmode currently in force. - Update
SCOPE.mdto list secrets-engine among the shipped consumers, and log a progress event.
Gate: secrets-engine can set its required configuration to published values and reach a pin; nothing about the fallback-free shape of that configuration changed.