Answer ops-warden and secrets-engine; open FLEX-WP-0021
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 1s

Two cross-repo questions arrived in the flex-auth inbox and both are
answered as decision records rather than as prose in a message.

FLEX-DEC-2026-004 answers ops-warden WARDEN-WP-0034-T05. A decision
lifetime shorter than the SSH certificate TTL is meaningful, but only as
authority to issue, never as authority to use an already-issued
certificate. The pre-sign gate is the only consumer of the shorter
lifetime: no replay past expires_at, fresh Check per sign. The lever that
shortens effective access is the requested TTL as a policy input, which
is already deployed as the ttl_out_of_bounds deny. ops-warden's section
9.7.2 window through certificate TTL is correct as written and correctly
owned by the PEP; flex-auth does not want that residue moved to the PDP.

docs/decision-input-freshness.md gains the same boundary as published
contract text, so the ruling is not only in the decision log.

FLEX-DEC-2026-005 answers secrets-engine. A real policy package is
expected and flex-auth authors it here as it does for every consumer; the
reserved coordinate is secrets-engine.catalog-lane.lifecycle v1 and it
does not exist yet. Their choice not to default the pin was correct and
is endorsed explicitly. POST /v1/check is deployed but has no
estate-wide address by design -- per-consumer cluster-local pins with
default-deny ingress -- so their 2026-09-06 probe found the design
working, not an outage.

FLEX-WP-0021 carries that work: obtain the real action vocabulary from
secrets-engine, publish the package with fixtures, confirm the digest
join against a real decision record, then stand up a
flex-auth-secrets-engine pin in warn without moving the other two pins.

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
This commit is contained in:
tegwick 2026-09-06 01:12:50 +02:00
parent 56940727bf
commit 6a6464fcc9
4 changed files with 659 additions and 15 deletions

View file

@ -0,0 +1,165 @@
---
id: FLEX-WP-0021
type: workplan
title: "secrets-engine consumer policy package and cluster-local pin"
domain: infotech
repo: flex-auth
status: proposed
owner: claude
topic_slug: netkingdom
planning_priority: P1
planning_order: 210
depends_on_workplans:
- FLEX-WP-0012
- FLEX-WP-0016
related_workplans:
- SECRETS-WP-0009
created: "2026-09-06"
updated: "2026-09-06"
---
# 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:
1. `SECRETS_ENGINE_AUTHORIZATION_POLICY_PACKAGE` / `_VERSION` are required
configuration with **no fallback**, deliberately. `secrets-engine.lifecycle/v1`
is example vocabulary, not a published package. Until flex-auth publishes a
real one, that configuration cannot be set to anything true.
2. 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
```task
id: FLEX-WP-0021-T01
status: todo
priority: high
```
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 the
`secrets-engine.lifecycle/v1` example set.
- Record it in `docs/secrets-engine-action-vocabulary.md`, following
`docs/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.
## 2. Publish `secrets-engine.catalog-lane.lifecycle` v1
```task
id: FLEX-WP-0021-T02
status: todo
priority: high
```
Owner: `flex-auth`.
- Write `examples/secrets-engine/policy_package.md` with
`id: secrets-engine.catalog-lane.lifecycle`, `version: v1`, and an explicit
`allow_ttl`. An omitted TTL takes the 15m engine default; `none`/`0s` denies
with `allow_lifetime_unstated` rather than granting standing access.
- Add `protected_system_manifest.yaml`, `subject_manifest.yaml`,
`resource_manifest.yaml`, and `registry_snapshot.json` for the namespace.
- Add allow and deny fixtures in `policy_fixtures.yaml` plus
`check_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.
## 3. Confirm the digest join against a real decision record
```task
id: FLEX-WP-0021-T03
status: todo
priority: high
```
Owner: `flex-auth` to emit; `secrets-engine` to verify.
- Emit a real `DecisionEnvelope` from the package above and hand it to
secrets-engine as the replay fixture for the join it built in `627810b`.
- Verify `binding.request_digest` reproduces as SHA-256 over canonical JSON of
tenant/subject/action/resource/context per `docs/canonical-request-digest.md`.
- Verify `provenance.registry_snapshot_digest` is present — §9.7.2 promotes it
to a conformance prerequisite and `FLEX-WP-0019` closed 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
```task
id: FLEX-WP-0021-T04
status: wait
priority: high
```
Owner: `flex-auth`; deployment approval required.
- Add `deploy/flex-auth-secrets-engine.yaml` as a three-document manifest —
`Deployment`, `Service`, default-deny `NetworkPolicy` admitting 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.mode` in `warn`. Flip to `enforce` only after secrets-engine
adopts a calling identity and its warn logs are clean, as `FLEX-WP-0016` did
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
```task
id: FLEX-WP-0021-T05
status: wait
priority: medium
```
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 the
`callerAuth` mode currently in force.
- Update `SCOPE.md` to 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.