RAILIANCE-WP is a family name, not a repository (ADR-007, and the prefix registry already lists it retired). Three repositories independently used one number space for unrelated work — RAILIANCE-WP-0012 was openbao extraction here, a cnpg backup in railiance-apps and a deploy-verify in railiance-cluster. This repository also carried two files both numbered 0016. Active workplans move to the successor prefix and are renumbered from 0001 in historical order. Archived workplans keep their historical identifiers. Projection UUIDs are re-derived from the new canonical ids. Records already registered under the old identifiers leave orphaned hub rows behind; that debt is recorded in CUST-WP-0068 and clears when ADR-012's reset-from-forge lands. Refs CUST-WP-0068-T03 Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
325 lines
13 KiB
Markdown
325 lines
13 KiB
Markdown
---
|
|
id: RPF-WP-0002
|
|
type: workplan
|
|
title: "OpenBao Approved Automation Delegation"
|
|
domain: financials
|
|
repo: railiance-platform
|
|
status: finished
|
|
owner: codex
|
|
topic_slug: railiance
|
|
planning_priority: high
|
|
planning_order: 8
|
|
created: "2026-06-28"
|
|
updated: "2026-07-01"
|
|
depends_on_workplans:
|
|
- RAIL-PL-WP-0002
|
|
- RAILIANCE-WP-0005
|
|
- RAILIANCE-WP-0006
|
|
- RAILIANCE-WP-0007
|
|
state_hub_workstream_id: "c69cb4e7-15c8-5858-aebd-73a6e46f0f21"
|
|
---
|
|
|
|
# RPF-WP-0002 - OpenBao Approved Automation Delegation
|
|
|
|
## Goal
|
|
|
|
Create a narrow OpenBao automation delegation path so approved credential and
|
|
it-sec changes can be applied without handing broad `platform-admin` power to an
|
|
agent, while still preserving different build, test, and production security
|
|
requirements.
|
|
|
|
This closes the current gap where reviewed CCRs can be approved and rendered,
|
|
but live application still fails with `403 permission denied` on
|
|
`sys/policies/acl/...` unless a human operator uses broad OpenBao admin
|
|
privileges.
|
|
|
|
## Problem
|
|
|
|
The current model has two bad modes:
|
|
|
|
- fully manual OpenBao UI work, which can unblock one credential but is slow,
|
|
hard to review, and easy to drift from the CCR;
|
|
- broad `platform-admin`, which is too powerful for routine automation and too
|
|
risky to hand to agents.
|
|
|
|
The issue appears in multiple workstreams:
|
|
|
|
- `RAILIANCE-WP-0005` token-grant apply failed on
|
|
`sys/policies/acl/credential-broker-warden-sign-issuer`;
|
|
- `RAILIANCE-WP-0007` whynot-design CCR apply failed on
|
|
`sys/policies/acl/workload-kv-read-whynot-design-npm-publish`.
|
|
|
|
Both are approved non-secret metadata changes. They should not require a human
|
|
to hand-type OpenBao policy and auth-role writes once review is complete.
|
|
|
|
## Direction
|
|
|
|
Add one or more constrained OpenBao applier identities that can apply only
|
|
reviewed, generated metadata for approved change classes.
|
|
|
|
The applier must not be a general `platform-admin` replacement. It should:
|
|
|
|
- verify a resolved State Hub decision or CCR status before live mutation;
|
|
- write only allowed policy names and auth role prefixes;
|
|
- never read or print secret values;
|
|
- record non-secret apply evidence;
|
|
- keep production secret value provisioning under approved operator custody
|
|
until a separate wrapped or dual-control flow is approved.
|
|
|
|
## Environment Model
|
|
|
|
Build and development:
|
|
|
|
- automation may apply approved sandbox metadata;
|
|
- generated test secrets may be allowed only in non-production mounts;
|
|
- approvals can be lightweight but still recorded.
|
|
|
|
Test and staging:
|
|
|
|
- automation may apply approved metadata after validation and owner review;
|
|
- verification must include positive and negative access checks;
|
|
- secret values should use wrapped delivery or operator custody depending on
|
|
risk classification.
|
|
|
|
Production:
|
|
|
|
- automation may apply only approved non-secret metadata such as narrow ACL
|
|
policies and auth roles;
|
|
- production secret values remain out-of-band operator custody unless a later
|
|
workplan creates a stronger wrapped or dual-control provisioning path;
|
|
- activation requires verification evidence before ops-warden or another front
|
|
door becomes resolvable.
|
|
|
|
## Proposed Policy Shape
|
|
|
|
Start with one production candidate policy, for example
|
|
`credential-change-prod-applier`, and keep it intentionally narrow:
|
|
|
|
- allow `create`, `update`, and `read` on `sys/policies/acl/workload-kv-read-*`;
|
|
- allow `create`, `update`, and `read` on approved credential-broker issuer
|
|
policy names such as `credential-broker-*-issuer`;
|
|
- allow `create`, `update`, and `read` on selected auth role prefixes such as
|
|
`auth/netkingdom/role/*` with local dry-run role-name constraints,
|
|
`auth/kubernetes/role/*`, and `auth/token/roles/credential-broker-*`;
|
|
- allow read/list only where needed for idempotent verification;
|
|
- deny broad `sys/*`, `auth/*`, `platform/*`, `identity/*`, `root`, and
|
|
`platform-admin` semantics.
|
|
|
|
Policy-name and role-name restrictions should be enforced in both OpenBao ACLs
|
|
and the local applier script.
|
|
|
|
## Tasks
|
|
|
|
## T01 - Specify delegated applier policy boundaries
|
|
|
|
```task
|
|
id: RPF-WP-0002-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "914a31ae-9fbf-5c8d-a5df-cc5a3c4633e3"
|
|
```
|
|
|
|
Define build, test, and production applier capabilities, including exact
|
|
OpenBao paths, allowed name prefixes, denied paths, and required audit evidence.
|
|
|
|
Acceptance:
|
|
|
|
- A human reviewer can see which OpenBao paths each environment can mutate.
|
|
- Production applier policy excludes secret value reads and broad admin paths.
|
|
- The proposal covers both workload KV read lanes and credential broker issuer
|
|
policies.
|
|
|
|
**2026-06-29:** Added `docs/openbao-approved-automation-delegation.md` and
|
|
`openbao/policies/credential-change-prod-applier.hcl`. The document defines
|
|
build/development, test/staging, and production boundaries, the allowed
|
|
production metadata mutation surface, denied secret/admin paths, and required
|
|
non-secret evidence. The production policy candidate allows only reviewed
|
|
metadata writes for workload KV read policies, credential-broker issuer
|
|
policies, approved auth-role prefixes, and self capability checks; it does not
|
|
grant secret value reads or writes.
|
|
|
|
## T02 - Implement a CCR-aware applier dry-run
|
|
|
|
```task
|
|
id: RPF-WP-0002-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "d02dd668-e75d-59b3-a1db-5c0e5b8ce301"
|
|
```
|
|
|
|
Extend the credential-change tooling so a proposed applier can validate a CCR,
|
|
check approval state, render the exact mutations, and refuse any out-of-policy
|
|
policy name, auth role, mount, path, or environment.
|
|
|
|
Acceptance:
|
|
|
|
- Dry-run succeeds for `CCR-2026-0001`.
|
|
- Dry-run refuses unapproved CCRs.
|
|
- Dry-run refuses attempts to create `root`, `platform-admin`, wildcard, or
|
|
unrelated policy names.
|
|
|
|
**2026-06-29:** Added `scripts/credential-change.py applier-dry-run <CCR>` and
|
|
Make target `credential-change-applier-dry-run`. The dry-run validates the CCR,
|
|
requires approved/applied/verified/active status, requires confirmed auth
|
|
bindings, verifies the OpenBao mount/path/policy/role stay inside the delegated
|
|
metadata surface, compares the policy artifact to the generated CCR policy body,
|
|
and renders only policy/auth-role mutations. It explicitly leaves secret value
|
|
writes, secret reads, and front-door activation out of scope. Unit tests cover
|
|
the active whynot-design CCR success path, unapproved CCR refusal, and rejection
|
|
of `platform-admin`/out-of-scope mount and path attempts. `make
|
|
credential-tests` passed with 28 tests.
|
|
|
|
## T03 - Add non-production applier role first
|
|
|
|
```task
|
|
id: RPF-WP-0002-T03
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "945a2847-ceaa-5bba-ab2b-29b4d90abac7"
|
|
```
|
|
|
|
Create a build/test applier identity and prove it can apply approved metadata in
|
|
a non-production lane without gaining unrelated OpenBao permissions.
|
|
|
|
Acceptance:
|
|
|
|
- Apply succeeds in a non-production mount or namespace.
|
|
- Negative checks prove unrelated policy/auth/secret paths are denied.
|
|
- Evidence is recorded without secret values.
|
|
|
|
**2026-06-30:** Added the non-production metadata-only policy candidate
|
|
`openbao/policies/credential-change-nonprod-applier.hcl` and documented that
|
|
generated test-secret paths require separate CCR-backed approval. Live non-prod
|
|
identity creation and positive/negative OpenBao evidence remain to close this
|
|
task.
|
|
|
|
**2026-06-30:** Added the guarded `applier-apply` execution path that reuses the
|
|
CCR dry-run guardrails, requires exact `DELEGATED APPLY <CCR-ID>` confirmation,
|
|
uses the local `bao` CLI with ambient delegated applier authority, writes only
|
|
policy/auth-role metadata, and records non-secret `delegated_metadata_apply`
|
|
evidence. Non-production task closure still needs a live build/test applier
|
|
identity plus positive and negative capability evidence.
|
|
|
|
**2026-06-30:** Added `scripts/openbao-apply-credential-change-appliers.py` and
|
|
Make target `openbao-credential-change-appliers-dry-run` to install/dry-run the
|
|
non-production applier policy plus bounded `auth/token/roles/credential-change-
|
|
nonprod-applier` role. The token role allows only the matching applier policy,
|
|
disallows `root` and `platform-admin`, disables the default policy, and does not
|
|
issue tokens by itself. Live non-production apply and denial evidence remains
|
|
the closeout gate.
|
|
|
|
**2026-07-01:** Applied the updated non-production metadata-only policy
|
|
and bounded `auth/token/roles/credential-change-nonprod-applier` role to live
|
|
OpenBao. The role attaches only `credential-change-nonprod-applier`, disables
|
|
the default policy, and disallows `root` / `platform-admin`; T03 remains open
|
|
until a non-production lane apply and denial probe are recorded.
|
|
|
|
## T04 - Add production metadata applier with human approval gate
|
|
|
|
```task
|
|
id: RPF-WP-0002-T04
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "493744db-445d-546f-82ea-2dee4bc72214"
|
|
```
|
|
|
|
Create the production metadata applier path and require a resolved CCR/State Hub
|
|
approval before mutation.
|
|
|
|
Acceptance:
|
|
|
|
- Approved `CCR-2026-0001` metadata can be applied without `platform-admin`.
|
|
- Unapproved CCRs fail closed.
|
|
- Secret value provisioning is still not automated in production.
|
|
|
|
**2026-06-30:** Strengthened the production gate by adding source-artifact
|
|
checks to the CCR applier dry-run and documenting that unapproved CCRs fail
|
|
closed before OpenBao mutation rendering. The production policy candidate exists
|
|
and remains metadata-only; live delegated identity creation/application evidence
|
|
still needs an operator-held OpenBao step.
|
|
|
|
**2026-06-30:** Added `applier-apply` and Make targets
|
|
`credential-change-applier-apply-plan` / `credential-change-applier-apply`. The
|
|
command fails closed for unapproved CCRs, renders the dry-run payload before
|
|
mutation, requires exact confirmation, does not accept tokens in argv, leaves
|
|
secret values out of scope, and appends State Hub/file-backed non-secret apply
|
|
evidence when requested. Production closure still requires live execution using
|
|
the constrained applier identity rather than broad `platform-admin`.
|
|
|
|
**2026-06-30:** Added `scripts/openbao-apply-credential-change-appliers.py` and
|
|
Make targets `openbao-credential-change-appliers-dry-run` /
|
|
`openbao-configure-credential-change-appliers` to configure the production
|
|
`credential-change-prod-applier` policy and bounded token role. The role allows
|
|
only `credential-change-prod-applier`, disallows `root` and `platform-admin`,
|
|
uses service tokens, disables default policy attachment, and keeps token issuance
|
|
outside the setup script. Production closure still needs a live run and
|
|
capability evidence using this constrained identity.
|
|
|
|
**2026-07-01:** Updated the delegated applier ACLs to use the OpenBao-matchable
|
|
`auth/netkingdom/role/*` path while keeping role-name and bound-claim
|
|
constraints in the local CCR dry-run. Applied the live prod/nonprod applier
|
|
policies and token roles, then issued a 15-minute
|
|
`credential-change-prod-applier` child token and used it to run
|
|
`scripts/credential-change.py applier-apply CCR-2026-0001`. The delegated
|
|
run wrote the workload KV policy and OIDC role metadata without
|
|
`platform-admin`. A `sys/capabilities-self` probe on
|
|
`platform/data/workloads/coulomb/whynot-design/npm-publish` returned
|
|
`deny`, and the matching short-lived child token accessor was revoked.
|
|
|
|
## T05 - Close the whynot-design pilot
|
|
|
|
```task
|
|
id: RPF-WP-0002-T05
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "b5959c20-7ac7-53a8-ba0d-ee569c122a4f"
|
|
```
|
|
|
|
Use the delegated production metadata applier to finish the whynot-design npm
|
|
publish token lane after the actual token is provisioned through approved
|
|
custody.
|
|
|
|
Acceptance:
|
|
|
|
- Policy and auth role are applied by the delegated applier.
|
|
- `NPM_AUTH_TOKEN` is provisioned through approved custody.
|
|
- Positive and negative verification pass without printing the token.
|
|
- `CCR-2026-0001` can move to `active`.
|
|
- ops-warden can mark `whynot-design-npm-publish` ready/resolvable.
|
|
|
|
**2026-07-01:** Closed the whynot-design pilot. `CCR-2026-0001` is
|
|
active, the front-door metadata is ready/resolvable, prior approved-custody
|
|
provisioning plus positive and negative verification are recorded without
|
|
secret values, and the delegated prod applier evidence is now recorded on the
|
|
CCR.
|
|
|
|
## Exit Criteria
|
|
|
|
- Routine approved OpenBao metadata changes no longer require broad
|
|
`platform-admin`.
|
|
- Production automation cannot read or exfiltrate managed secret values.
|
|
- Build, test, and production each have distinct, documented security
|
|
requirements.
|
|
- CCR approval, apply, verification, and front-door activation form one
|
|
reviewable chain.
|
|
|
|
|
|
## Completion 2026-07-02 — T03 live probe and workplan finish
|
|
|
|
T03 closed with live positive and negative evidence from a
|
|
`credential-change-nonprod-applier` child token (accessor
|
|
`pCznHtid1O0vy36QHqMbzu5Y`, revoked after use):
|
|
|
|
- allowed: `policy_write workload-kv-read-nonprod-probe-test` (test artifact
|
|
deleted afterwards by the operator session) and `policy_read
|
|
workload-kv-read-issue-core-runtime`;
|
|
- denied: `policy_read platform-admin`, out-of-pattern `policy_write
|
|
evil-probe-test`, KV secret read on the issue-core path, and
|
|
`auth/token/roles/credential-change-nonprod-applier` write;
|
|
- all recorded in `/openbao/audit/openbao-audit.log` (2026-07-02T10:09Z
|
|
window).
|
|
|
|
The production applier path was proven the same day: both `CCR-2026-0002`
|
|
and `CCR-2026-0003` were applied with a `credential-change-prod-applier`
|
|
child token holding only that policy — no `platform-admin` handoff. All
|
|
tasks are done; the workplan is finished.
|