Record whynot OpenBao lane apply evidence
This commit is contained in:
@@ -55,6 +55,9 @@ openbao:
|
||||
method: oidc
|
||||
mount: netkingdom
|
||||
role: whynot-design-workload-kv-read
|
||||
allowed_redirect_uris:
|
||||
- https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback
|
||||
- http://localhost:8250/oidc/callback
|
||||
user_claim: sub
|
||||
groups_claim: groups
|
||||
bound_claims:
|
||||
@@ -91,6 +94,16 @@ verification:
|
||||
- OIDC role bound to confirmed whynot-design claim or approved service account.
|
||||
- Secret value provisioned directly in OpenBao through approved operator custody.
|
||||
- Positive and negative verification recorded with non-secret audit ids or timestamps.
|
||||
evidence:
|
||||
- at: '2026-06-28T10:37:42+00:00'
|
||||
actor: codex
|
||||
kind: non_secret_openbao_apply_check
|
||||
result: passed
|
||||
details:
|
||||
- Policy read succeeded for workload-kv-read-whynot-design-npm-publish.
|
||||
- OIDC role read showed the whynot-design bound claim, read policy, and callback URIs.
|
||||
- Metadata read showed catalog-id whynot-design-npm-publish.
|
||||
- Secret field presence check found NPM_AUTH_TOKEN without printing or recording the value.
|
||||
lifecycle:
|
||||
deactivate: Disable ops-warden catalog entry and remove or detach auth role policy.
|
||||
rotate: Replace NPM_AUTH_TOKEN value directly in OpenBao and record non-secret rotation
|
||||
|
||||
@@ -7,7 +7,7 @@ This is the next-session handoff for `CCR-2026-0001` and the
|
||||
|
||||
- CCR: `CCR-2026-0001`
|
||||
- Decision: `e6381a56-6b04-4fd5-b2de-f3ef59cde888`
|
||||
- Status: approved
|
||||
- Status: approved; non-secret OpenBao apply checks passed 2026-06-28
|
||||
- Front door: `template`, `resolvable=false`
|
||||
- Catalog id: `whynot-design-npm-publish`
|
||||
- Tenant/org: `coulomb`
|
||||
@@ -18,9 +18,11 @@ This is the next-session handoff for `CCR-2026-0001` and the
|
||||
`https://gitea.coulomb.social/api/packages/coulomb/npm/`
|
||||
|
||||
The operator reported that the Gitea token was generated and stored in OpenBao.
|
||||
Codex could not verify the metadata from the current token-helper identity:
|
||||
metadata lookup, policy read, and auth-role read all returned `403 permission
|
||||
denied`. No secret value was read or printed.
|
||||
Using the temporary operator token only for non-secret infrastructure work, Codex
|
||||
confirmed that the policy exists, the OIDC role exists with the whynot-design
|
||||
binding and redirect URIs, the secret metadata has the expected catalog id, and
|
||||
the `NPM_AUTH_TOKEN` field is present. No secret value was printed, recorded,
|
||||
or copied into Git, State Hub, chat, or workplans.
|
||||
|
||||
## Safety Rules
|
||||
|
||||
@@ -94,6 +96,10 @@ Role payload:
|
||||
```json
|
||||
{
|
||||
"role_type": "oidc",
|
||||
"allowed_redirect_uris": [
|
||||
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
|
||||
"http://localhost:8250/oidc/callback"
|
||||
],
|
||||
"user_claim": "sub",
|
||||
"groups_claim": "groups",
|
||||
"bound_claims": {
|
||||
@@ -111,6 +117,10 @@ role_payload_file="$(mktemp)"
|
||||
trap 'rm -f "$role_payload_file"' EXIT
|
||||
cat >"$role_payload_file" <<'JSON'
|
||||
{
|
||||
"allowed_redirect_uris": [
|
||||
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
|
||||
"http://localhost:8250/oidc/callback"
|
||||
],
|
||||
"bound_claims": {
|
||||
"groups": [
|
||||
"whynot-design"
|
||||
@@ -181,7 +191,8 @@ Only after these are true:
|
||||
|
||||
- secret metadata confirmed;
|
||||
- policy exists and is scoped to the corrected `coulomb/whynot-design` path;
|
||||
- OIDC role exists and binds only `groups=["whynot-design"]`;
|
||||
- OIDC role exists and binds only `groups=["whynot-design"]` with approved
|
||||
browser and local CLI callback URIs;
|
||||
- positive verification passed;
|
||||
- negative verification passed;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ Ops-warden batch follow-up:
|
||||
| Policy file | `openbao/policies/workload-kv-read-whynot-design-npm-publish.hcl` |
|
||||
| OIDC auth mount | `netkingdom` |
|
||||
| OIDC role | `whynot-design-workload-kv-read` |
|
||||
| OIDC callback URIs | `https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback`, `http://localhost:8250/oidc/callback` |
|
||||
| Kubernetes auth role | `whynot-design-workload-kv-read` if an in-cluster service account consumes this lane |
|
||||
| flex-auth ref | `secret.read:whynot-design` if tenant policy requires pre-approval |
|
||||
|
||||
@@ -109,6 +110,14 @@ The role must attach only:
|
||||
workload-kv-read-whynot-design-npm-publish
|
||||
```
|
||||
|
||||
The OIDC role must include the browser and local CLI callback URIs accepted by
|
||||
OpenBao:
|
||||
|
||||
```text
|
||||
https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback
|
||||
http://localhost:8250/oidc/callback
|
||||
```
|
||||
|
||||
The whynot-design pilot claim is confirmed as `groups=whynot-design`. Before
|
||||
applying any changed role, re-confirm the KeyCape/NetKingdom claim that
|
||||
identifies the whynot-design caller. The role must bind to that claim; do not
|
||||
@@ -154,9 +163,25 @@ Positive verification:
|
||||
|
||||
1. Authenticate as the whynot-design caller using the approved OIDC or
|
||||
Kubernetes auth role.
|
||||
2. Fetch the field in an attended session or through `warden access --fetch`.
|
||||
2. Fetch the field in an attended session or through `warden access --exec`.
|
||||
3. Record only that the fetch succeeded; do not record the value.
|
||||
|
||||
Safe attended command shape before the dedicated ops-warden catalog id is
|
||||
activated:
|
||||
|
||||
```bash
|
||||
set +x
|
||||
bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read
|
||||
warden access "npm token" \
|
||||
--path platform/workloads/coulomb/whynot-design/npm-publish \
|
||||
--field NPM_AUTH_TOKEN \
|
||||
--no-policy \
|
||||
--exec -- sh -lc 'test -n "$NPM_AUTH_TOKEN"'
|
||||
```
|
||||
|
||||
Use `--no-policy` only while the local ops-warden config reports
|
||||
`policy.enabled=false`; remove it once the flex-auth gate is enforced.
|
||||
|
||||
Negative verification:
|
||||
|
||||
1. Authenticate as a non-whynot identity.
|
||||
|
||||
@@ -81,6 +81,11 @@ workload_kv_read:
|
||||
- deactivate
|
||||
- rotate
|
||||
- compromised
|
||||
conditional:
|
||||
openbao.auth.method=oidc:
|
||||
required:
|
||||
- allowed_redirect_uris
|
||||
allowed_redirect_uris: non-empty list of OpenBao callback URIs accepted by the role
|
||||
|
||||
access_frontdoor_readiness:
|
||||
allowed:
|
||||
|
||||
@@ -169,6 +169,19 @@ def validate_workload_kv_read(ccr: dict[str, Any], errors: list[str], warnings:
|
||||
errors.append("openbao.auth.method must be oidc or kubernetes")
|
||||
require_string(auth.get("mount"), "openbao.auth.mount", errors)
|
||||
require_string(auth.get("role"), "openbao.auth.role", errors)
|
||||
if method == "oidc":
|
||||
redirect_uris = require_list(
|
||||
auth.get("allowed_redirect_uris"),
|
||||
"openbao.auth.allowed_redirect_uris",
|
||||
errors,
|
||||
)
|
||||
if not redirect_uris:
|
||||
errors.append("openbao.auth.allowed_redirect_uris must not be empty for oidc")
|
||||
for index, uri in enumerate(redirect_uris):
|
||||
if not isinstance(uri, str) or not uri.strip():
|
||||
errors.append(
|
||||
f"openbao.auth.allowed_redirect_uris[{index}] must be a non-empty string"
|
||||
)
|
||||
policies = [str(policy) for policy in require_list(auth.get("policies"), "openbao.auth.policies", errors)]
|
||||
if policies != [policy_name]:
|
||||
errors.append("openbao.auth.policies must contain exactly openbao.policy_name")
|
||||
@@ -346,6 +359,8 @@ def auth_payload(ccr: dict[str, Any]) -> dict[str, Any]:
|
||||
}
|
||||
if auth.get("groups_claim"):
|
||||
payload["groups_claim"] = auth["groups_claim"]
|
||||
if auth.get("allowed_redirect_uris"):
|
||||
payload["allowed_redirect_uris"] = auth["allowed_redirect_uris"]
|
||||
return payload
|
||||
|
||||
|
||||
|
||||
@@ -127,6 +127,18 @@ class CredentialChangeTests(unittest.TestCase):
|
||||
self.assertEqual(payload["bound_service_account_namespaces"], ["issue-core"])
|
||||
self.assertNotIn("bound_claims", payload)
|
||||
|
||||
def test_oidc_auth_payload_includes_redirect_uris(self) -> None:
|
||||
ccr, errors, _warnings = credential_change.validate_ccr(self.sample)
|
||||
self.assertEqual(errors, [])
|
||||
payload = credential_change.auth_payload(ccr)
|
||||
self.assertEqual(
|
||||
payload["allowed_redirect_uris"],
|
||||
[
|
||||
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
|
||||
"http://localhost:8250/oidc/callback",
|
||||
],
|
||||
)
|
||||
|
||||
def test_apply_plan_refuses_unapproved_ccr(self) -> None:
|
||||
with self.assertRaises(SystemExit):
|
||||
credential_change.command_apply_plan(type("Args", (), {"ref": str(self.issue_core)})())
|
||||
@@ -151,6 +163,11 @@ class CredentialChangeTests(unittest.TestCase):
|
||||
)
|
||||
self.assertIn('role_payload_file="$(mktemp)"', rendered)
|
||||
self.assertIn('"bound_claims": {', rendered)
|
||||
self.assertIn('"allowed_redirect_uris": [', rendered)
|
||||
self.assertIn(
|
||||
'"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback"',
|
||||
rendered,
|
||||
)
|
||||
self.assertIn(
|
||||
'bao write auth/netkingdom/role/whynot-design-workload-kv-read @"$role_payload_file"',
|
||||
rendered,
|
||||
|
||||
@@ -4,13 +4,13 @@ type: workplan
|
||||
title: "Workload KV Access Lanes for ops-warden Fetch"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: blocked
|
||||
status: active
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
planning_priority: high
|
||||
planning_order: 6
|
||||
created: "2026-06-27"
|
||||
updated: "2026-06-27"
|
||||
updated: "2026-06-28"
|
||||
depends_on_workplans:
|
||||
- RAIL-PL-WP-0002
|
||||
- RAILIANCE-WP-0004
|
||||
@@ -152,11 +152,15 @@ denied with `403 permission denied` while writing the policy, so live policy
|
||||
application waits on an approved platform-admin/operator token or a narrow
|
||||
token-helper capability.
|
||||
|
||||
**2026-06-28:** Using the temporary operator token provided outside the repo,
|
||||
Codex applied/confirmed the live policy in OpenBao. The verification read of the
|
||||
policy succeeded and no secret values were printed or recorded.
|
||||
|
||||
## T03 - Define and apply auth bindings
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0006-T03
|
||||
status: wait
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "a217371a-0f85-40c6-b691-ac67834c86b5"
|
||||
```
|
||||
@@ -181,11 +185,17 @@ Acceptance:
|
||||
of the KeyCape/NetKingdom whynot-design bound claim or approved service-account
|
||||
subject; do not create an unbounded OIDC role.
|
||||
|
||||
**2026-06-28:** Created/confirmed
|
||||
`auth/netkingdom/role/whynot-design-workload-kv-read` with
|
||||
`groups=["whynot-design"]`, only the
|
||||
`workload-kv-read-whynot-design-npm-publish` policy, `ttl=15m`, and the approved
|
||||
browser/local CLI callback URIs.
|
||||
|
||||
## T04 - Provision the KV path without exposing the token
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0006-T04
|
||||
status: wait
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "c43724a3-c83e-4ab6-b7d1-e427fd93a9a9"
|
||||
```
|
||||
@@ -208,11 +218,17 @@ Acceptance:
|
||||
provisioning is waiting on an approved operator/OpenBao custody path for the
|
||||
actual `NPM_AUTH_TOKEN` value.
|
||||
|
||||
**2026-06-28:** Confirmed the OpenBao metadata at
|
||||
`platform/workloads/coulomb/whynot-design/npm-publish` includes
|
||||
`catalog-id=whynot-design-npm-publish` and that the `NPM_AUTH_TOKEN` field is
|
||||
present. The value was not printed, recorded, or copied into Git, State Hub,
|
||||
chat, or workplans.
|
||||
|
||||
## T05 - Verify caller-scoped fetch behavior
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0006-T05
|
||||
status: wait
|
||||
status: progress
|
||||
priority: high
|
||||
state_hub_task_id: "dc1f470b-e78a-48a9-9957-965aed47861f"
|
||||
```
|
||||
@@ -233,11 +249,16 @@ Acceptance:
|
||||
secret provisioning. The runbook requires positive and negative fetch evidence
|
||||
without printing the token value.
|
||||
|
||||
**2026-06-28:** Non-secret operator checks now pass for policy, auth role,
|
||||
metadata, and field presence. Remaining verification is the attended
|
||||
whynot-design OIDC positive check and a non-whynot denial check, both without
|
||||
printing the token.
|
||||
|
||||
## T06 - Coordinate ops-warden catalog activation
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0006-T06
|
||||
status: wait
|
||||
status: progress
|
||||
priority: high
|
||||
state_hub_task_id: "8e84ec19-01db-4baf-a532-de87e51d4994"
|
||||
```
|
||||
@@ -260,6 +281,11 @@ handoff payload for ops-warden and sent the pointers by State Hub message. The
|
||||
entry should remain draft/non-active until live OpenBao provisioning and
|
||||
verification complete.
|
||||
|
||||
**2026-06-28:** The generic `openbao-api-key` ops-warden access lane can proxy
|
||||
the check with explicit `--path` and `--field`, but the dedicated
|
||||
`whynot-design-npm-publish` route is not yet present in the ops-warden routing
|
||||
catalog. Keep activation pending until caller verification and catalog update.
|
||||
|
||||
## T07 - Decide whether to batch sibling workload-KV requests
|
||||
|
||||
```task
|
||||
|
||||
@@ -180,6 +180,10 @@ not `approved` and also refuses unconfirmed bound claims. Remaining T04 work is
|
||||
to add a richer diff against existing source artifacts and eventually bridge
|
||||
from reviewed plan to the interactive live applier.
|
||||
|
||||
**2026-06-28:** Added OIDC `allowed_redirect_uris` to the CCR contract and
|
||||
generated role payloads after live OpenBao rejected an OIDC role without
|
||||
callbacks. Unit coverage now checks the generated whynot-design role payload.
|
||||
|
||||
## T05 - Add chat/CLI approval commands
|
||||
|
||||
```task
|
||||
@@ -286,6 +290,12 @@ received `403 permission denied`. Prepared
|
||||
policy, auth-role, metadata verification, positive verification, negative
|
||||
verification, and activation without printing the token.
|
||||
|
||||
**2026-06-28:** With the temporary operator token, Codex applied/confirmed the
|
||||
OpenBao read policy and OIDC role, confirmed metadata `catalog-id`, and confirmed
|
||||
`NPM_AUTH_TOKEN` field presence without printing or recording the value. The CCR
|
||||
now records non-secret evidence for that apply check. Positive whynot-design and
|
||||
negative non-whynot caller verification still gate `active`/`ready`.
|
||||
|
||||
## T08 - Add deactivation, rotation, and compromise flows
|
||||
|
||||
```task
|
||||
|
||||
Reference in New Issue
Block a user