Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02669-87ee-7a31-b111-edc95a16e0fa
117 lines
4.7 KiB
Markdown
117 lines
4.7 KiB
Markdown
# 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.
|