112 lines
6.9 KiB
Markdown
112 lines
6.9 KiB
Markdown
|
|
# Service-JWT final acceptance — SECRETS-WP-0008-T06
|
||
|
|
|
||
|
|
Prepared 2026-10-11; source preparation only. T06 remains wait. This packet
|
||
|
|
neither grants live authority nor provides owner acknowledgment.
|
||
|
|
|
||
|
|
## Delivered producer and consumer work
|
||
|
|
|
||
|
|
SECRETS-WP-0012 is finished: protected in-memory client-secret acquisition,
|
||
|
|
operator cleanup, KeyCape exchange, service JWT login and service cleanup passed
|
||
|
|
in `docs/evidence/2026-10-10-keycape-openbao-probe.json`. The platform applied
|
||
|
|
CCR-2026-0038 on October 8 and published
|
||
|
|
`railiance-platform/docs/contracts/secrets-engine-openbao-jwt-login.yaml` on
|
||
|
|
October 10. Mount `keycape-services`, role `secrets-engine-openbao`, issuer
|
||
|
|
`https://kc.coulomb.social` are published. An unpublished-mount or
|
||
|
|
unprovisioned-registration wait is obsolete.
|
||
|
|
|
||
|
|
The consumer no-fallback receipt
|
||
|
|
`docs/evidence/2026-10-10-service-jwt-no-fallback.json` proves synthetic selection
|
||
|
|
and real Bao CLI header behavior against a loopback listener. It is not native
|
||
|
|
claim rejection evidence. KEY-WP-0039-T01 is source acceptance done; T02 owns the
|
||
|
|
attended actual negative-token session. RPF-WP-0035-T02 retains native claims,
|
||
|
|
effective policy/capability denials, and MASON-WP-0009-T05 return.
|
||
|
|
|
||
|
|
WP0007 is six of seven complete with native per-lane adoption outstanding.
|
||
|
|
WP0009 credential apply/verify/delivery/revocation passed in the September 27
|
||
|
|
attended receipts, but its task cannot finish: held EUR 10 reservation still
|
||
|
|
needs accounting reconciliation, replacement runtime admission and separate
|
||
|
|
retry authority. These are existing live tasks; this packet closes neither.
|
||
|
|
|
||
|
|
## Executable missing identity-boundary check
|
||
|
|
|
||
|
|
`tools/verify_service_jwt_boundary.py` defaults to backend-free preparation.
|
||
|
|
It checks exact applied CCR, published mount/role and issuer, client-secret-file
|
||
|
|
refusal and exact guarded paths. Preparation cannot produce a passing native
|
||
|
|
receipt. After explicit authorization for the attended metadata check, add
|
||
|
|
`--execute` to the same command:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
env -u BAO_TOKEN -u VAULT_TOKEN -u SECRETS_ENGINE_KEYCAPE_CLIENT_SECRET_FILE \
|
||
|
|
BAO_ADDR=http://127.0.0.1:18200 \
|
||
|
|
SECRETS_ENGINE_KEYCAPE_TOKEN_URL=https://kc.coulomb.social/token \
|
||
|
|
SECRETS_ENGINE_KEYCAPE_ISSUER=https://kc.coulomb.social \
|
||
|
|
SECRETS_ENGINE_OPENBAO_JWT_LOGIN=/home/worsch/railiance-platform/docs/contracts/secrets-engine-openbao-jwt-login.yaml \
|
||
|
|
uv run python tools/verify_service_jwt_boundary.py \
|
||
|
|
--ccr /home/worsch/railiance-platform/credential-change-requests/CCR-2026-0038-secrets-engine-service-jwt-login.yaml
|
||
|
|
```
|
||
|
|
|
||
|
|
Live mode uses existing attended custody and performs two service-token metadata
|
||
|
|
requests: lookup-self and one batch capabilities-self. The batch checks both
|
||
|
|
client-secret guarded paths, `sys/policies/acl/*`, `auth/*/role/*` and
|
||
|
|
`auth/token/create`; it never reads their values or attempts writes. Cleanup
|
||
|
|
runs even on failed verification. Two metadata calls reserve room for cleanup
|
||
|
|
within the service token's eight-use budget. Passing requires exactly the
|
||
|
|
self policy, no identity-policy additions, deny on every requested path and
|
||
|
|
both operator and service revocation success. Output contains hashes, capability
|
||
|
|
booleans and session fingerprints. No backend response/error body is printed.
|
||
|
|
Transport fixes bind each request to the configured OpenBao origin, disable
|
||
|
|
environment proxies and refuse all redirects including relative redirects.
|
||
|
|
Only HTTP 200 application/json with a bounded 64 KiB body and object data is
|
||
|
|
accepted. Errors and response bodies are suppressed. Session evidence is
|
||
|
|
restricted to the contract whitelist with strict boolean types, the fixed
|
||
|
|
source name, and twelve-hex session handles. Native acceptance requires every
|
||
|
|
contract field (established, source, both fingerprints and attempted/succeeded
|
||
|
|
cleanup flags), a normally returned cleanup call, and no verification failure.
|
||
|
|
Stale true evidence cannot override a cleanup exception. HTTP JSON with an
|
||
|
|
errors member is refused even when a data member also exists. Synthetic/local-loopback tests
|
||
|
|
cover redirects, proxy environment, size/status/content/shape failures, absent
|
||
|
|
responses, unknown exceptions and unknown evidence fields with cleanup.
|
||
|
|
This does not prove expiry/use exhaustion, native claim negatives or adoption.
|
||
|
|
Platform retains those native test obligations and owner review of this tool.
|
||
|
|
|
||
|
|
## Protected-operation adoption is a distinct missing contract
|
||
|
|
|
||
|
|
INTENT requires task-bounded authority and a functional Lifecycle API. The
|
||
|
|
platform design explicitly says this login policy is insufficient for native
|
||
|
|
lanes; future execution entitlement requires a separately reviewed CCR type and
|
||
|
|
backend-enforced scope. No standing wildcard policy is accepted.
|
||
|
|
|
||
|
|
Actual CLI flow (`cli._require_lane_approval`, `_open_backend`, `cmd_apply`) is
|
||
|
|
claim → validated PDP Check → approval CAS consume → select provider → OpenBao
|
||
|
|
operation. `_open_backend` supplies the login-only service token directly.
|
||
|
|
There is no per-action delegated grant or scoped backend exchange in that path.
|
||
|
|
Consequently a service-jwt default flip would consume a real approval then fail
|
||
|
|
the protected operation. Configured `auto` chooses service-jwt; unconfigured
|
||
|
|
`auto` still chooses bootstrap/env. Neither selection proves steady-state
|
||
|
|
adoption. Keep existing service policy and provider defaults until the execution
|
||
|
|
contract exists; failed JWT never switches provider.
|
||
|
|
|
||
|
|
Founder/owner choice needed: retain login-self-only and implement a separately
|
||
|
|
owned task-scoped delegation contract (recommended), or explicitly redesign
|
||
|
|
backend execution mediation with platform enforcement. Both must preserve
|
||
|
|
claim/PDP/CAS binding, exact action/lane/target/expiry/principal scope, failure
|
||
|
|
closed, revocation and audit evidence; neither means granting broad standing
|
||
|
|
ACLs. Retaining attended bootstrap/env as a transition leaves T06 open.
|
||
|
|
|
||
|
|
Concrete missing owner obligation: secrets-engine and railiance-platform must
|
||
|
|
agree the execution entitlement's owner and CCR schema, implementation endpoint,
|
||
|
|
backend policy enforcement, exact request binding, TTL/use budget and revocation,
|
||
|
|
then wire it after successful consume. KeyCape supplies identity, not authority.
|
||
|
|
Existing native AppRole delivery sessions are short-lived workload read sessions,
|
||
|
|
not an engine administrative entitlement. Existing native lane cutover requires
|
||
|
|
scoped attended platform authority but does not implement this exchange.
|
||
|
|
|
||
|
|
T06 closes only after native KEY39/CCR negative/expiry/use/cleanup evidence and
|
||
|
|
MASON return, a reviewed implemented execution entitlement, and a selected real
|
||
|
|
protected action through service identity plus delegated authority: exact bound
|
||
|
|
PDP/CAS evidence, intended backend result, unauthorized target/action/expired or
|
||
|
|
replayed request refusal, cleanup on success and failure, no standing engine
|
||
|
|
credential, and steady-state invocation/default migration evidence. Do not use
|
||
|
|
`apply` or any other protected live command to discover the missing entitlement.
|
||
|
|
All of this remains in T06 and owner tasks; no residual is silently finished.
|