# 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: ```bash 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: ```bash 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: ```bash 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: ```bash 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.