Two real DecisionEnvelopes in examples/secrets-engine/replay/ for secrets-engine to verify its digest join unchanged: a plain allow (rotate, empty context) and the dual-control allow (destroy with a valid approval-claim). Both are included deliberately. input_claim_digests.context appears only when the request carries a non-empty context, so a consumer asserting the field is always present would pass on destroy and fail on rotate. One fixture would have hidden that. request_digest, policy_package_digest, registry_snapshot_digest and the context claim digest are verified identical across two runs and are the fields to pin. id, decision_time and the lifetime bounds move with the clock; the README says so rather than leaving a consumer to discover it by flake. lifetime.ttl is 15m from the package allow_ttl. Emitted from flex-auth/local in standalone mode, not from a cluster pin. T03 is progress, not done -- it closes when secrets-engine confirms their validator accepts the records unchanged. 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
8.2 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: progress
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.
Emitted 2026-09-06, awaiting their confirmation.
examples/secrets-engine/replay/ carries two real envelopes — a plain allow
(rotate, empty context) and the dual-control allow (destroy with a valid
approval-claim). All three digests plus input_claim_digests.context verified
identical across two runs; id, decision_time, and the lifetime bounds move
with the clock and are documented as unpinnable. Both fixtures are included
because input_claim_digests.context appears only for a non-empty context, so a
consumer asserting it is always present would pass on one and fail on the other.
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.