railiance-platform/docs/coding-agent-openbao-identity.md
codex 429cc912ed
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Finish coding-agent high-risk boundary coverage
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02669-87ee-7a31-b111-edc95a16e0fa
2026-08-22 10:03:54 +02:00

4.7 KiB

Coding-agent OpenBao identity

RAILIANCE-WP-0022 requires an OpenBao identity that is distinct from the attended human platform-admin role. The identity is split across its proper owners:

  • KeyCape owns a confidential client_credentials service principal and its signed short-lived JWT.
  • railiance-platform owns the exact-bound OpenBao JWT role and the policies on the resulting OpenBao token.
  • ops-warden remains an interested consumer and SSH-certificate issuer; it does not issue this identity or its credentials.

The operational identity is the platform-owned AppRole coding-agent-railiance-platform. The exact-bound KeyCape JWT role is the issuer-backed migration target; it does not block the deny-wins control while the KeyCape client is being registered.

Operational AppRole

The reviewed role body is openbao/auth/coding-agent-approle.json. Apply it with attended platform authority:

bao write auth/approle/role/coding-agent-railiance-platform \
  @openbao/auth/coding-agent-approle.json

This is a standing machine role, not a manually minted token. Every SecretID expires after five minutes and is single-use; resulting tokens last at most 15 minutes, have eight uses, omit the default policy, and always carry agent-high-risk-boundary. The role also carries the otherwise-readable issue-core policy solely to make the deny-wins invariant directly testable. The boundary permits token metadata lookup, capabilities inspection, and self-revocation; it does not grant token creation or management of any other token.

Run the non-disclosing verifier while holding attended authority to create one ephemeral SecretID:

python3 scripts/verify_coding_agent_approle.py

The verifier holds the SecretID and token only in memory, calls sys/capabilities-self rather than a KV read, and revokes the test token before exit. It prints only policy names, TTL, capabilities, and pass/fail state.

KeyCape contract

The accepted service token must contain exactly the following identity coordinates:

Claim Required value
aud / client id codex-railiance-platform
sub service:codex:railiance-platform
principal_type service
tenant tenant:coulomb
roles contains coding-agent
requested scope openbao:login

The KeyCape access token lifetime is 15 minutes. Its confidential client secret must be generated and delivered through an approved out-of-repository custody path. It must never appear in Git, State Hub, command arguments, logs, or chat.

KeyCape-backed OpenBao role

The migration-target role body is openbao/auth/coding-agent-jwt-role.json. Apply it only with attended platform authority:

bao write auth/netkingdom/role/coding-agent \
  @openbao/auth/coding-agent-jwt-role.json

The role binds the exact service audience, subject, principal type, tenant, and role. It produces a 15-minute, eight-use token without the default policy. The token deliberately combines agent-high-risk-boundary with workload-kv-read-issue-core-runtime: the latter would otherwise read the issue-core bundle, while the former must win with deny.

Value-safe verification

Do not verify by attempting bao kv get; an unexpected policy error could print a protected value. After KeyCape exchanges the client credential and the JWT login produces an OpenBao token through a mode-0600 temporary file, use only capabilities and token metadata:

BAO_TOKEN_FILE=/run/user/$(id -u)/coding-agent.openbao-token
BAO_TOKEN=$(head -n 1 "$BAO_TOKEN_FILE") \
  bao token capabilities \
  platform/data/workloads/issue-core/issue-core/issue-core-runtime
BAO_TOKEN=$(head -n 1 "$BAO_TOKEN_FILE") \
  bao token capabilities \
  platform/metadata/workloads/issue-core/issue-core/issue-core-runtime
BAO_TOKEN=$(head -n 1 "$BAO_TOKEN_FILE") bao token lookup -format=json \
  | jq '{display_name:.data.display_name,policies:.data.policies,ttl:.data.ttl}'

Expected results are deny for the data path and read for the metadata path. The lookup must list both policies, omit default, and report a TTL no greater than 15 minutes. Shred the temporary JWT and OpenBao token files after the check. Revoke the issued OpenBao token if it remains live.

Abort and rollback

  • Abort if any bound claim differs, the JWT issuer/audience is not the live KeyCape contract, or a token would be printed.
  • Delete auth/netkingdom/role/coding-agent if deny-wins does not appear in capabilities or the token includes an unexpected policy.
  • Delete auth/approle/role/coding-agent-railiance-platform if its metadata differs from the reviewed body or its verifier fails.
  • Revoke the test OpenBao token, disable the KeyCape client, and rotate its confidential secret after suspected disclosure.