# OpenBao Approved Automation Delegation This document specifies the narrow OpenBao metadata surface that approved credential-change automation may mutate. It exists to avoid routine use of broad `platform-admin` while keeping secret values under operator custody. ## Scope The delegated applier is for reviewed metadata only: - ACL policies generated from approved CCRs; - auth roles bound to reviewed OIDC claims or Kubernetes service accounts; - credential-broker issuer policies and token roles generated from reviewed grant catalog entries; - readback and capability checks needed to prove the mutation landed. It must not read, write, print, wrap, unwrap, or proxy managed secret values. Production secret provisioning remains an attended OpenBao/operator custody step unless a later workplan approves a stronger dual-control flow. ## Environment Boundaries Build and development may use sandbox metadata once a non-production OpenBao mount or namespace is declared. Generated test secrets must stay in the sandbox and must never be copied into State Hub, prompts, Git, or chat. The non-production applier policy candidate is `openbao/policies/credential-change-nonprod-applier.hcl`. It currently grants only metadata writes, matching the no-secret-value rule used in production. Any future generated test-secret path needs a separate CCR-backed approval so it cannot silently expand this delegation. Test and staging may apply reviewed metadata after owner review. Verification must include positive and negative access checks, and evidence must be non-secret. Production may apply only reviewed non-secret metadata. The production applier policy is `openbao/policies/credential-change-prod-applier.hcl`, and every live run must be preceded by `scripts/credential-change.py applier-dry-run `. Unapproved CCRs fail closed before any OpenBao mutation is rendered. Live metadata mutation uses `scripts/credential-change.py applier-apply ` with an exact `DELEGATED APPLY ` confirmation phrase and the local `bao` CLI under ambient delegated applier authority; the command does not accept OpenBao tokens in argv. ## Production Mutation Surface | Change class | Allowed OpenBao path | Notes | | --- | --- | --- | | Workload KV read policies | `sys/policies/acl/workload-kv-read-*` | Generated from CCR mount/path/field metadata. | | Credential broker issuer policies | `sys/policies/acl/credential-broker-*-issuer` | Generated from grant catalog metadata. | | OIDC workload roles | `auth/netkingdom/role/*-workload-kv-read` | Bound claims must be confirmed before apply. | | Kubernetes workload roles | `auth/kubernetes/role/*` | Bound service accounts/namespaces must be confirmed before apply. | | Credential broker token roles | `auth/token/roles/credential-broker-*` | Child-token roles only; no root or platform-admin policies. | | Self checks | `auth/token/lookup-self`, `sys/capabilities-self` | Read/update only as required by OpenBao. | Denied by omission: - `platform/data/*`, `platform/metadata/*`, or any other secret value path; - `sys/*` outside the approved ACL policy prefixes; - `auth/*` outside the approved role prefixes; - `identity/*`, unseal/recovery material, audit devices, mounts, and root/admin policy assignment; - wildcard, parent-directory, or mismatched policy and role names. ## Local Dry-Run Guardrails The CCR dry-run is deliberately stricter than the OpenBao ACL policy. It must: 1. validate the CCR schema and secret-marker scan; 2. require CCR status `approved`, `applied`, `verified`, or `active`; 3. require `openbao.auth.bound_claims_confirmed=true`; 4. require mount `platform` and path `platform/workloads/...` for workload KV requests; 5. require policy names to start with `workload-kv-read-` and remain under `openbao/policies/.hcl`; 6. require OIDC roles to stay under `auth/netkingdom/role/*-workload-kv-read`; 7. require Kubernetes roles to stay under `auth/kubernetes/role/*-workload-kv-read` or `auth/kubernetes/role/*-secrets-read`; 8. render only exact policy and auth-role metadata mutations; 9. leave secret value writes and front-door activation out of scope. `applier-apply` reuses the same guardrails, renders the dry-run payload before mutation, requires exact confirmation, writes only policy/auth-role metadata, and appends non-secret `delegated_metadata_apply` evidence. For approved CCRs it can advance file-backed status to `applied`; for already applied/verified/active CCRs it records idempotent evidence without moving the lifecycle backward. ## Required Evidence Record only non-secret evidence: - CCR id and approval/decision reference; - applier identity and timestamp; - policy name and auth role path; - OpenBao request id or audit timestamp; - positive and negative verification references; - front-door activation confirmation after verification. ## Applier Identity Setup `openbao-apply-credential-change-appliers.py` configures the source-owned metadata applier policies and matching OpenBao token roles: - `credential-change-nonprod-applier` uses `openbao/policies/credential-change-nonprod-applier.hcl`; - `credential-change-prod-applier` uses `openbao/policies/credential-change-prod-applier.hcl`. The token roles allow only their matching applier policy, explicitly disallow `root` and `platform-admin`, disable the default policy, use service tokens, and do not issue tokens by themselves. Token issuance remains an approved custody path outside this setup script. Use `make openbao-credential-change-appliers-dry-run` before any live apply. ## Current Production Policy Candidate `openbao/policies/credential-change-prod-applier.hcl` is the source candidate for a future production applier identity. It is not a substitute for CCR review; it is the OpenBao-side capability envelope used after local dry-run validation. ## Current Non-Production Policy Candidate `openbao/policies/credential-change-nonprod-applier.hcl` is the source candidate for a build/test/staging applier identity. It is intentionally metadata-only until this repo declares a non-production OpenBao mount or namespace and records live positive/negative evidence for that lane.