# warden-sign auth-capability lane `warden-sign` is a non-KV secrets-engine lane for SECRETS-WP-0004. It creates an OpenBao ACL policy plus AppRole that lets ops-warden run `warden sign` over the HTTP API for the FLEX-WP-0007 T4 production smoke. No token value, AppRole `secret_id`, or SSH private material belongs in Git, State Hub, chat, prompts, workplans, or normal logs. State Hub gets pointers only; the operator receives `role_id` and `secret_id` out-of-band. ## Non-secret pointers | Pointer | Value | | --- | --- | | OpenBao address | `https://bao.coulomb.social` | | SSH mount | `ssh` | | Policy | `warden-sign` | | AppRole | `warden-sign` | | OIDC auth mount | `netkingdom` | | OIDC role | `warden-sign` | | OIDC role path | `auth/netkingdom/role/warden-sign` | | OIDC bound group | `net-kingdom-admins` | | Token TTL | `15m` | | Secret ID TTL | `30m` | | Secret ID uses | `1` | | Allowed paths | `ssh/sign/agt-role`, `ssh/sign/adm-role`, `ssh/sign/atm-role` | | Denied probes | `ssh/sign/unlisted-role`, `ssh/roles/agt-role`, `ssh/config/ca`, `sys/policies/acl/warden-sign`, `auth/token/create`, `identity/entity/id` | ## Plan and apply Preview without mutation: ```bash SECRETS_ENGINE_HUB_URL="" secrets-engine apply warden-sign --stage prod --dry-run ``` Live apply requires an approved decision/workplan and a short-lived bootstrap token file outside any repo: ```bash BAO_ADDR=https://bao.coulomb.social \ secrets-engine apply warden-sign --stage prod \ --bootstrap-token-file ~/.secrets-engine/bootstrap/prod-warden-sign.token ``` The bootstrap token file must be mode `0600`, revocable, and tracked in [hardening-backlog.md](hardening-backlog.md) H0 until revoked and shredded. ## OIDC operator login pointer For an attended human operator who has `bao` on the workstation, the intended narrow login is: ```bash bao login -method=oidc -path=netkingdom role=warden-sign ``` That role lives at `auth/netkingdom/role/warden-sign`, is bound through the `groups` claim to `net-kingdom-admins`, and attaches only the `warden-sign` policy. It is not the `platform-admin` role and not the whynot-design KV-read role. If the role has not been applied yet, create/update it from an approved OpenBao operator context with this non-secret payload: ```json { "role_type": "oidc", "allowed_redirect_uris": [ "https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback", "http://localhost:8250/oidc/callback", "http://127.0.0.1:8250/oidc/callback" ], "oidc_scopes": ["openid", "profile", "email", "groups"], "user_claim": "sub", "groups_claim": "groups", "bound_claims": { "groups": ["net-kingdom-admins"] }, "policies": "warden-sign", "ttl": "15m" } ``` Equivalent CLI path: ```bash bao write auth/netkingdom/role/warden-sign @warden-sign-oidc-role.json ``` After login, verify the token shape without printing the token value: ```bash bao token capabilities ssh/sign/agt-role bao token capabilities ssh/sign/adm-role bao token capabilities ssh/sign/atm-role bao token capabilities auth/token/create ``` The first three should include `update`; the last one should not grant token creation/admin capability. ## Handoff Mint a fresh single-use AppRole `secret_id` and write both handoff values to mode-0600 files outside any Git worktree: ```bash install -m 700 -d ~/.secrets-engine/handoff BAO_ADDR=https://bao.coulomb.social \ secrets-engine handoff warden-sign --stage prod \ --bootstrap-token-file ~/.secrets-engine/bootstrap/prod-warden-sign.token \ --role-id-file ~/.secrets-engine/handoff/warden-sign.role_id \ --secret-id-file ~/.secrets-engine/handoff/warden-sign.secret_id ``` The command prints only file paths and TTL metadata. It does not print the `secret_id`. On CoulombCore, the operator can authenticate without the `bao` CLI by posting the file contents to AppRole login and capturing the returned token into process state only: ```bash ROLE_ID="$(cat ~/.secrets-engine/handoff/warden-sign.role_id)" SECRET_ID="$(cat ~/.secrets-engine/handoff/warden-sign.secret_id)" VAULT_TOKEN="$( printf '{"role_id":"%s","secret_id":"%s"}' "${ROLE_ID}" "${SECRET_ID}" \ | curl -fsS \ --request POST \ --header 'Content-Type: application/json' \ --data @- \ https://bao.coulomb.social/v1/auth/approle/login \ | jq -r '.auth.client_token' )" unset ROLE_ID SECRET_ID ``` Run the smoke with the scoped token: ```bash FLEX_AUTH_EXTERNAL=1 SMOKE_VAULT=1 VAULT_TOKEN="${VAULT_TOKEN}" \ ~/ops-warden/scripts/policy_gate_production_smoke.sh ``` ## Verification After live apply and handoff, verify the scoped AppRole token shape without printing the token: ```bash BAO_ADDR=https://bao.coulomb.social \ secrets-engine verify warden-sign --positive --negative \ --bootstrap-token-file ~/.secrets-engine/bootstrap/prod-warden-sign.token ``` Positive verification checks `update` on the three allowlisted `ssh/sign` paths. Negative verification checks the denial probes lack `update`, `sudo`, and `root`. ## State Hub pointer payload Post only non-secret pointers, for example: ```json { "catalog_id": "warden-sign", "kind": "auth-capability", "addr": "https://bao.coulomb.social", "mount": "ssh", "policy": "warden-sign", "approle": "warden-sign", "token_ttl": "15m", "secret_id_ttl": "30m", "secret_id_num_uses": 1, "allowed_paths": ["ssh/sign/agt-role", "ssh/sign/adm-role", "ssh/sign/atm-role"], "status": "applied-and-handoff-ready" } ``` Do not include `role_id`, `secret_id`, `VAULT_TOKEN`, token accessors, raw curl responses, or smoke logs containing token material. ## Revocation and cleanup After the smoke, revoke the scoped token by accessor if available, then remove handoff files: ```bash bao token revoke -accessor shred -u ~/.secrets-engine/handoff/warden-sign.role_id shred -u ~/.secrets-engine/handoff/warden-sign.secret_id ``` To retire the lane metadata itself: ```bash BAO_ADDR=https://bao.coulomb.social \ secrets-engine revoke warden-sign \ --bootstrap-token-file ~/.secrets-engine/bootstrap/prod-warden-sign.token ``` ## Closeout status On 2026-06-29 ops-warden reported the joint production smoke as passed against the flex-auth runtime and production OpenBao. Non-secret evidence only: `warden sign agt-state-hub-bridge` returned policy decision `decision:032b096c433ad80c`, `--ttl 999` was denied with `ttl_out_of_bounds` before OpenBao signing, and the vault-backed allow path used the scoped `warden-sign` lane. `policy.enabled` remains off until the ecosystem moves from build-stage/pre-testing into the maturity posture where live enforcement is appropriate.