WARDEN-WP-0026 T01: capabilities-safe lane verification + incident note
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

T01 (done): canonical capabilities-based verify pattern in the fleet promotion
checklist (catalog-lane-promotion.md) and applied to the railiance-backup and
forgejo-admin lane playbooks. Verification proves allow/deny via
`bao token capabilities` against the KV v2 data path, never `bao kv get`; a denied
default-policy token-create is a pass, not a privileged-fallback trigger.

T07 (progress): lessons-learned note for the 2026-07-16 CCR-2026-0004 disclosure
(three root causes). Live re-verify + rotation block remain (depend on T06).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-07-16 14:26:05 +02:00
parent 2ad8a53781
commit ea98d6bf39
5 changed files with 161 additions and 3 deletions

View file

@ -22,12 +22,50 @@ Before changing `status: draft` → `status: active`:
| 5 | **Resolvable** | `warden route show <id> --json` shows `resolvable: true` when placeholders are documented |
| 6 | **Tests** | Routing test or smoke proving lookup + handoff shape (no secret values in fixtures) |
| 7 | **Review date** | Update `reviewed:` in catalog entry |
| 8 | **Verification** | Positive + negative proof via **`bao token capabilities`** — never `bao kv get` (see below) |
Promotion PR touches: `registry/routing/catalog.yaml`, playbook, optional
`tests/test_routing.py`, and a one-line note in `wiki/CredentialRouting.md` draft table.
---
## Capabilities-safe lane verification (WARDEN-WP-0026 T01)
**Verifying a lane must never read the secret *data*.** A negative deny-test that
runs `bao kv get <path>` will, if the deny fails (e.g. a privileged token
fallback), print the secret value into a logged context — this is exactly the
2026-07-16 CCR-2026-0004 disclosure. Prove *allow/deny* with
`bao token capabilities`, which returns the capability list, not the value.
For KV v2, capabilities are checked against the **API data path**
(`<mount>/data/<lane-path>`), not the `kv get` logical path.
```bash
# Positive: the lane's own OIDC identity can read the data path.
bao login -method=oidc -path=netkingdom role=<lane-role> # caller identity
bao token capabilities "$(bao print token)" platform/data/<lane-path>
# → expect the list to include: read
# Negative: a default-only identity is denied — no value is ever read.
DEFAULT_TOKEN=$(bao token create -policy=default -field=token) # if denied, STOP — do not fall back
bao token capabilities "$DEFAULT_TOKEN" platform/data/<lane-path>
# → expect: deny
```
- **Never** substitute `bao kv get` for the checks above. Reading a value to
"confirm it's there" is the anti-pattern; presence is proven by `read` in the
capability list.
- If `bao token create -policy=default` is itself denied for your identity, that
is a *pass for the deny direction* — **do not** fall back to your privileged
login token to force the read.
- Fetching a value **for use** (`--field` into an env var or file, or
`warden access … --field`) is a separate, intended action — not verification.
Record the capability lists (allow/deny) as the promotion evidence; they contain
no secret material and are safe for CCRs, State Hub, and Git.
---
## Worked examples (already active)
**`ops-warden-warden-sign-token`** — promoted 2026-07-01 after RAILIANCE-WP-0005: