Compare commits
2 commits
627810b478
...
fd369d4e21
| Author | SHA1 | Date | |
|---|---|---|---|
| fd369d4e21 | |||
| a3eb6634aa |
2 changed files with 86 additions and 0 deletions
48
docs/gated-actions.md
Normal file
48
docs/gated-actions.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Gated actions over `secret-catalog-lane`
|
||||||
|
|
||||||
|
Authoritative list of the `action` values secrets-engine passes to the shared
|
||||||
|
authorization gate (`_require_lane_approval` → `resolve_consume_binding` →
|
||||||
|
`require_production_consume`). Supplied to flex-auth for
|
||||||
|
`secrets-engine.catalog-lane.lifecycle` (FLEX-WP-0021-T01 / FLEX-DEC-2026-005).
|
||||||
|
|
||||||
|
This is the enforced set read out of `cli.py`, not the
|
||||||
|
`secrets-engine.lifecycle`/`v1` example vocabulary. `resource.type` is
|
||||||
|
`secret-catalog-lane` and `resource.system` is `secrets-engine`; the catalog id
|
||||||
|
is `request.resource.id`.
|
||||||
|
|
||||||
|
| action | Reached by | Side effect |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `apply` | `apply` | writes consumer ACL policy + AppRole metadata |
|
||||||
|
| `provision` | `provision` | writes one declared KV field |
|
||||||
|
| `rotate` | `rotate` | replaces one declared KV field |
|
||||||
|
| `verify` | `verify` | AppRole login + bounded read/capability probe |
|
||||||
|
| `handoff` | `handoff` | mints role-id/secret-id to mode-0600 files |
|
||||||
|
| `wrap` | `wrap` | response-wrapped operator handoff |
|
||||||
|
| `exec` | `exec` | fetches one field into a child process |
|
||||||
|
| `deactivate` | `revoke` **and** `lifecycle deactivate` | removes managed AppRole/policy; preserves KV |
|
||||||
|
| `suspend` | `lifecycle suspend` | removes managed AppRole; preserves policy |
|
||||||
|
| `destroy` | `lifecycle destroy` | irreversible KV metadata deletion |
|
||||||
|
| `compromise` | `lifecycle compromise` | marks lane compromised; blocks delivery |
|
||||||
|
| `reactivate` | `lifecycle reactivate` | clears overlay state |
|
||||||
|
|
||||||
|
## Things a package author would otherwise get wrong
|
||||||
|
|
||||||
|
- **`revoke` is not an action.** The CLI verb `revoke` gates as `deactivate`.
|
||||||
|
There is no `revoke` action value. Do not add one.
|
||||||
|
- **`destroy` is defined but currently unreachable live.** The handler raises
|
||||||
|
before the gate; only `--dry-run` renders. Keep it in the package as the
|
||||||
|
dual-control-capable case, but no live `destroy` Check will arrive until the
|
||||||
|
exact-action approval contract lands (`SECRETS-WP-0007-T04`).
|
||||||
|
- **`compromise` and `reactivate` mutate local overlay state only.** They touch
|
||||||
|
no OpenBao object. They are gated because they change delivery posture, not
|
||||||
|
because they write to the backend.
|
||||||
|
- **`plan`, `apply --dry-run`, `route`, `audit`, `catalog`, `decision inspect`
|
||||||
|
and `evidence` never reach the gate** and must not appear in the package.
|
||||||
|
- Build and test stages remain fail-open relative to approval-engine; only
|
||||||
|
`stage: prod` reaches consume.
|
||||||
|
|
||||||
|
## Request attributes carried today
|
||||||
|
|
||||||
|
`resource.attributes` carries `stage`, and sorted `fields`, `policy_targets`,
|
||||||
|
and `auth_targets`. `fields` is populated for `provision`, `rotate`, `verify`,
|
||||||
|
and `exec`; the others send an empty list rather than a guess.
|
||||||
|
|
@ -273,6 +273,44 @@ deployment: approval-engine must serve the claim endpoint and access-engine must
|
||||||
serve Check. Probed 2026-09-06 — neither is reachable, and State Hub exposes
|
serve Check. Probed 2026-09-06 — neither is reachable, and State Hub exposes
|
||||||
only `/decisions/`.
|
only `/decisions/`.
|
||||||
|
|
||||||
|
Inbound 2026-09-06 (approval-engine `APPROVAL-IN-0002`, flex-auth
|
||||||
|
`FLEX-DEC-2026-005`). The join committed in `627810b` validates the wrong
|
||||||
|
artifact and must not be extended until gate-house rules.
|
||||||
|
|
||||||
|
- `ActionAuthorization` is a PROPOSED, unratified object from flex-auth's own
|
||||||
|
contract. It appears zero times in gate-house and state-hub. `GH-DEC-2026-003`
|
||||||
|
already names step 1 as `GET /v1/approvals/{id}/claim -> valid_now`, an
|
||||||
|
approval-claim field that `ActionAuthorization` does not carry. The claim body
|
||||||
|
is an approval-claim envelope, not an `ActionAuthorization`.
|
||||||
|
- Confirmed defect, ours, independent of the ruling: `authorization.py` pins
|
||||||
|
`AUTHORITY = "state-hub"` and enforces it unconditionally, contradicting
|
||||||
|
flex-auth's statement that State Hub decision records are not the runtime
|
||||||
|
approval authority and our own read-model doctrine. Not patched yet: under
|
||||||
|
option A the authority check belongs on the claim issuer, so it moves with the
|
||||||
|
split rather than being guessed twice.
|
||||||
|
- If gate-house confirms option A, `validate_action_authorization` splits across
|
||||||
|
the two artifacts already fetched: the claim carries approval fact (binding
|
||||||
|
digest, validity window, consumption state, freshness, issuer); the step-2
|
||||||
|
DecisionEnvelope carries exact CheckRequest match and the package/version pin.
|
||||||
|
No check is lost. Do not start until the ruling.
|
||||||
|
- Auth gap, tracked separately so it does not ride the envelope decision: we
|
||||||
|
send a static mode-0600 token as Bearer. Production verifies a KeyCape RS256
|
||||||
|
JWT against JWKS and refuses opaque tokens. Requested registration clientId
|
||||||
|
`secrets-engine-approval`, scopes `approval:read` + `approval:consume`,
|
||||||
|
client_credentials, confidential. `aud` MUST be the resource server
|
||||||
|
`approval-engine`, never the clientId. `service_auth.py` already implements
|
||||||
|
this exchange for `secrets-engine-openbao`, so this is a second registration.
|
||||||
|
- approval-engine `APPROVAL-WP-0002-T03` will publish the base URL; it is not
|
||||||
|
deployed anywhere today and proceeds on its own evidence. The envelope
|
||||||
|
question gates our first live consume, not their rollout.
|
||||||
|
- flex-auth endorsed the no-default-pin decision explicitly. The reserved
|
||||||
|
coordinate `secrets-engine.catalog-lane.lifecycle` / `v1` is a RESERVATION,
|
||||||
|
not a publication; our pin stays unset. `docs/gated-actions.md` delivers the
|
||||||
|
authoritative twelve-action list `FLEX-WP-0021-T01` was blocked on. No
|
||||||
|
estate-wide PDP exists by design: flex-auth runs per-consumer cluster-local
|
||||||
|
pins, and `flex-auth-secrets-engine` has not been created yet, so the
|
||||||
|
2026-09-06 probe finding was the design working rather than an outage.
|
||||||
|
|
||||||
Define and enforce the decision contract needed by production commands. A
|
Define and enforce the decision contract needed by production commands. A
|
||||||
resolved approval must bind at least:
|
resolved approval must bind at least:
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue