Review construction plan for audit-core OpenBao runtime custody

Awaiting founder approve. Receiver already runs on the interim ESO token;
phase 4 replaces it with an AppRole and an empty senders KV path.
This commit is contained in:
tegwick 2026-08-13 10:27:13 +02:00
parent dcc933abd5
commit 93b9c1a027

View file

@ -0,0 +1,120 @@
---
id: audit-core-openbao-runtime-custody
demand_source: audit-core/workplans/AUDIT-WP-0005-T02
consumer_repo: audit-core
credential_type: openbao-approle-kv
status: reviewed
approved_by: null
approved_at: null
created: "2026-08-13"
updated: "2026-08-13"
---
# Construction plan: audit-core OpenBao runtime custody
## 1. Demand
audit-core on railiance01 needs durable PostgreSQL custody and a sender
registry without the founder typing OpenBao tokens or running `bao kv put`.
The founders remaining acts are: approve this plan, and unseal OpenBao if
it is sealed. Mechanics belong to ops-mason (structure) and ops-warden
(routing / founder desk), not to an ad-hoc terminal session.
## 2. Existing-structure survey
Checked 2026-08-13 against live railiance01 and the routing catalog:
- **Database leases already exist.** `rapp-postgres` provisioned `audit_core`
with `audit_core_app` / `audit_core_migrate`, and OpenBao already vends
`database/creds/audit-core-runtime` and `database/creds/audit-core-migration`
through railiance-platform grants `rapp-postgres/audit-core-runtime` and
`rapp-postgres/audit-core-migration`. `warden route show
database-dynamic-credentials` points at that playbook. Do not create a
second database engine or a KV copy of a rotating lease.
- **ESO token already exists.** `external-secrets/openbao-audit-core-eso-token`
was minted 2026-08-13 with policy `external-secrets-audit-core` (read on
the two database cred paths and on `platform/data/workloads/audit-core/senders`).
ClusterSecretStore YAML is drafted; it is not yet applied.
- **KV senders path does not exist.** A founder `bao kv put` against
`platform/workloads/audit-core/senders` 403d because the workstation
`~/.vault-token` is not an operator identity. That is the failure this
plan exists to retire.
- **Catalog.** `database-dynamic-credentials` already covers the lease.
There is no `audit-core-senders` entry. `openbao-api-key` is the generic
template and must not become the concrete lane.
- **Auth topology.** Same as user-engine / rapp-qonto: railiance01 ESO
cannot use CoulombCore Kubernetes auth. AppRole is the transitional
bridge; same-cluster Kubernetes auth remains the target.
- **Does an existing lane already satisfy this?** The database half, yes —
bind to the existing OpenBao database roles. The sender-registry half,
no — there is no path, no AppRole, and no catalog entry. Reuse the
email-connect / user-engine *shape* (namespace-limited store, 15m
tokens, eight uses), do not widen those identities.
## 3. Proposed changes
| # | Action | Object | Reuse-vs-new rationale |
|---|---|---|---|
| 1 | reuse | OpenBao roles `audit-core-runtime` / `audit-core-migration` | Already vended; a KV copy of a lease recreates the delivery gap |
| 2 | reuse | policy `external-secrets-audit-core` | Already written; covers database creds + senders read |
| 3 | create | AppRole `external-secrets-audit-core` | Replace the long-lived ESO token with the same 15m/30m/8-use bridge as user-engine and rapp-qonto |
| 4 | deliver | Secret `external-secrets/openbao-audit-core-approle` | Mason write-only delivery of role_id/secret_id; never logged |
| 5 | create | ClusterSecretStore `openbao-audit-core` | Namespace-limited to `audit-core`; AppRole auth (token store is the interim until this builds) |
| 6 | reuse | ClusterSecretStore `openbao-audit-core-database` + ExternalSecret | Namespaced VaultDynamicSecret cannot read the ESO token in `external-secrets`; CSS can. One `dataFrom` extract per lease. Applied 2026-08-13, SecretSynced |
| 7 | create | empty KV path `platform/workloads/audit-core/senders` | Structure only. Values are **not** founder-pasted: first deploy mints sender tokens in-cluster into Secret `audit-core-senders`. A later wrap-migrate (user-engine pattern) can move them into this path without printing |
| 8 | propose | ops-warden catalog `audit-core-senders` | Pointer, `warden_executes: false`, starts `draft` |
| 9 | retire | founder `bao kv put` / token-prompt as the T02 delivery path | That is the error-prone interaction this demand forbids |
No sibling workload path is readable. Mason does not print, log, or return
sender tokens or database passwords.
## 4. Review notes
- **Naming:** `external-secrets-audit-core` / `openbao-audit-core` matches
email-connect and user-engine. Database grant names stay with rapp-postgres.
- **TTL/scoping:** 15-minute tokens, 30-minute max, eight uses. Store
condition is `audit-core` only.
- **Redundancy:** does not create a second database role or a KV cache of
the lease. Does not widen `openbao-email-connect` or
`openbao-user-engine-runtime`.
- **Compaction:** retires the attended `bao kv put` path as the way T02
completes. The already-minted static ESO token is interim and is revoked
after the AppRole store is Ready.
- **Secret values:** sender tokens are generated by us, not imported from a
vendor. Founder paste-once is the wrong desk for them. Generate in-cluster;
optional later wrap-migrate into the empty KV path.
- **Founder remaining acts:** approve this plan; unseal OpenBao if sealed.
No token paste, no `bao` command review.
## 5. Executive summary
**One-line ask:** approve letting ops-mason finish audit-cores OpenBao
lane (AppRole + namespace-limited store + empty senders path + catalog
pointer) so the receiver can run without you typing OpenBao tokens.
**Who gets access:** only External Secrets, through AppRole
`external-secrets-audit-core`. Application pods keep seeing mounted
files and `AUDIT_CORE_SENDERS`. Nothing else gains a new identity.
**To what:** read `database/creds/audit-core-runtime`,
`database/creds/audit-core-migration`, and (later)
`platform/workloads/audit-core/senders`. No sibling workload or tenant
path.
**For how long:** each AppRole login is 15 minutes, 30 minutes maximum,
eight uses. The AppRole secret ID lasts until rotated or replaced by
same-cluster Kubernetes auth.
**Blast radius if the credential leaks:** append to the audit trail and
read the sender registry; cannot rewrite or delete stored events (append-only
trigger). Revoke the AppRole secret ID, rotate sender tokens overlap-first,
and roll the receiver. Database leases expire on their own.
**Cost to reverse:** delete the AppRole, its bootstrap Secret, the
ClusterSecretStore, and the empty KV path. Database roles and the
`audit_core` database stay (owned by rapp-postgres). No other consumer
is on this identity.
**Decision:** approve, reject, or send back to phase 1.
Approval authorizes Mason build of structure and in-cluster sender
minting. It does not authorize printing any secret value.