6 KiB
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:
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:
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 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:
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:
{
"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:
bao write auth/netkingdom/role/warden-sign @warden-sign-oidc-role.json
After login, verify the token shape without printing the token value:
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:
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:
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:
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:
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:
{
"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:
bao token revoke -accessor <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:
BAO_ADDR=https://bao.coulomb.social \
secrets-engine revoke warden-sign \
--bootstrap-token-file ~/.secrets-engine/bootstrap/prod-warden-sign.token