# Secrets-engine service JWT login Status: proposed, not provisioned. Owner: railiance-platform, RPF-WP-0032. Demand: State Hub message `38b47122-07eb-4a7f-a5df-13a38f50e110`. ## Contract and ownership KeyCape's accepted provider contract is `../key-cape/docs/openbao-service-auth-contract.md`. The consumer implementation is `../secrets-engine/src/secrets_engine/engine_auth.py`; the existing coding agent role is `openbao/auth/coding-agent-jwt-role.json`. The service must have its own role and identity. It must not acquire the coding-agent role or an operator's policy set. Propose an isolated JWT auth mount `keycape-services`, role `secrets-engine-openbao`, and policy `secrets-engine-login-self`. Survey first: if an equivalent service mount already exists, the owner may select it in the approved contract instead. Do not reconfigure the browser `netkingdom` mount or the coding-agent mount to introduce this service. | Setting | Proposed value / evidence required | | --- | --- | | Verification | RS256 only; exact HTTPS issuer and approved discovery/JWKS URL, both pending KeyCape owner confirmation | | Role type / user claim | `jwt` / `sub` | | Audience | `secrets-engine-openbao` | | Subject | `service:secrets-engine` | | Bound claims, string matching | `principal_type=service`, `tenant=tenant:coulomb`, required `roles=secrets-engine`, `scope=openbao:login` | | Token policy | `secrets-engine-login-self` only; no default policy | | Token bounds | service token, TTL/max/explicit max `5m`, 8 uses, no periodic token; budget must include cleanup | | Logging | verbose OIDC logging disabled; no JWT claim dump or token/accessor in receipts | The self policy permits only `auth/token/lookup-self` read, `sys/capabilities-self` update, and `auth/token/revoke-self` update. These explicit self endpoints are necessary because default policy is disabled. No KV read, policy/auth mutation, SecretID minting, child-token creation or renewal is granted. Verify the token's effective identity policies too: disabling default policy alone does not prove that aliases/groups add no permissions. This is an identity login contract. It is intentionally insufficient to apply native lanes. `../secrets-engine/docs/native-lane-cutover.md` still requires canonical ActionAuthorization, successful approval-engine consume, scoped attended production authority and consumer verification per lane. Granting this service standing wildcard ACL/role-write privileges would let a raw OpenBao token bypass those application checks. Any future execution entitlement needs a separate reviewed CCR type and backend-enforced scope. The current `workload-kv-read` schema cannot encode this JWT administrative authority. ## Publication and custody After live verification, publish a separate non-secret consumer file with exactly these fields (the template below is deliberately invalid until filled): ```yaml mount: keycape-services role: secrets-engine-openbao bound_issuer: null # required exact HTTPS KeyCape issuer; do not guess ``` Point `SECRETS_ENGINE_OPENBAO_JWT_LOGIN` only at the approved final file. The consumer requires its issuer to equal `SECRETS_ENGINE_KEYCAPE_ISSUER`. The client secret remains in the separately approved KeyCape client custody lane, mounted as a protected file; the JWT exchange and OpenBao login remain in memory or private temporary input with cleanup. This design does not establish that client secret's live path or provision it. `--auth service-jwt` is the explicit pilot; failure must never fall back to bootstrap/env authentication. KeyCape bounds JWT lifetime to 15 minutes and provides no refresh token. OpenBao login is not a one-time consumption guarantee for that JWT: it may be replayed while valid. Disabling issuance does not recall already issued JWTs or OpenBao tokens. In an incident, disable the exact role/client and revoke issued service tokens through owner custody; do not disable a shared mount. Without active revocation, residual access can extend by the OpenBao token TTL after the last accepted JWT login. Renew by a fresh exchange; always self-revoke after use. ## Approval and acceptance KeyCape confirms issuer, verification endpoint, registration and claim types; platform approves the exact mount/config/role/policy and effective policy set; secrets-engine accepts the five-minute token/use budget and login-only scope. The installed OpenBao version must support the reviewed parameters. A metadata survey must show no conflicting role before any write. Prove correct-service login, exact policy set, expiry/use exhaustion and cleanup. Reject wrong issuer/audience/subject/tenant/principal/role/scope, invalid or expired signatures, and coding-agent credentials. Prove KV read, policy write, SecretID issuance and child-token creation are denied. Separately prove a failed login never consults bootstrap/env providers. Retain only timestamps, public contract revision, capability outcomes and boolean cleanup evidence. First-lane apply remains gated on SECRETS-WP-0007-T04 and its own exact approval. Rollback disables the role and revokes its tokens; removing an exclusively owned empty mount is a later review. Existing ESO lanes and interim proxies remain available. The login contract is withdrawn until verification is green. OpenBao's [JWT documentation](https://openbao.org/docs/auth/jwt/) describes signature verification and claim binding; its [role API](https://openbao.org/docs/2.4.x/api/auth/jwt/) defines token TTL/use limits and the explicit maximum. These are mechanism references, not evidence of this cluster's installed configuration.