125 lines
6.3 KiB
Markdown
125 lines
6.3 KiB
Markdown
---
|
|
id: user-engine-openbao-runtime-custody
|
|
demand_source: net-kingdom/workplans/NK-WP-0023-T05
|
|
consumer_repo: net-kingdom
|
|
credential_type: openbao-approle-kv
|
|
status: built
|
|
approved_by: "Bernd Worsch"
|
|
approved_at: "2026-07-30"
|
|
created: "2026-07-30"
|
|
updated: "2026-07-30"
|
|
---
|
|
|
|
# Construction plan: user-engine OpenBao runtime custody
|
|
|
|
## 1. Demand
|
|
|
|
The live portal edge marker and identity-provisioner service token are
|
|
bootstrap Kubernetes Secrets without an authoritative rotation source.
|
|
`user-engine` and `identity-provisioner` need the same runtime behavior with
|
|
OpenBao as authority and External Secrets Operator as delivery mechanism.
|
|
|
|
## 2. Existing-structure survey
|
|
|
|
- `Secret/user-engine-runtime` in namespace `user-engine` contains only
|
|
`proxy-secret`.
|
|
- `Secret/identity-provisioner-client` in namespace `user-engine` and
|
|
`Secret/identity-provisioner-token` in namespace `sso` carry the two copies
|
|
of the provisioner service token.
|
|
- The applications already consume only Secret references; no code or
|
|
Deployment interface change is required.
|
|
- The established `rapp-qonto` bridge proves that railiance01 External Secrets
|
|
must currently use AppRole against the OpenBao instance on CoulombCore;
|
|
railiance01 service-account tokens cannot use that instance's Kubernetes
|
|
auth mount.
|
|
- Existing activity-core stores and policies are unrelated and must not be
|
|
widened or reused across this identity boundary.
|
|
|
|
## 3. Proposed changes
|
|
|
|
| # | Action | Object | Rationale |
|
|
|---|---|---|---|
|
|
| 1 | create | KV path `platform/workloads/user-engine/runtime` | One authoritative workload path with fields `PROXY_SECRET` and `PROVISIONER_TOKEN` |
|
|
| 2 | create | policy `workload-kv-read-user-engine-runtime` | Read and metadata access only to the exact KV v2 path |
|
|
| 3 | create | AppRoles `external-secrets-user-engine` and `external-secrets-sso-user-engine` | Separate revocable bootstrap identities for the two consuming namespaces |
|
|
| 4 | deliver | AppRole bootstrap Secrets in `external-secrets` | Write-only Mason delivery; 15-minute tokens, 30-minute maximum, eight uses |
|
|
| 5 | create | namespace-restricted ClusterSecretStores for `user-engine` and `sso` | Prevent either identity from becoming a general cross-namespace store |
|
|
| 6 | create | three ExternalSecrets targeting the existing Secret names | Preserve application interfaces while changing authority |
|
|
| 7 | migrate | existing values into the KV path through a wrapped platform-admin process | Read source and write destination in one process; never return either value |
|
|
| 8 | verify | metadata, rollout, positive/negative authentication, and rotation rehearsal | Record field names, readiness, denial, and rollout only |
|
|
| 9 | retire | manual Secret-copy/bootstrap procedure | ExternalSecret becomes the sole writer and rotation path |
|
|
|
|
The migration does not mint a new application capability. It moves two
|
|
existing values into governed custody. Same-cluster Kubernetes auth remains
|
|
the target after OpenBao moves to reef-railiance.
|
|
|
|
## 4. Review and optimization
|
|
|
|
- Separate AppRoles avoid widening one namespace identity across `sso` and
|
|
`user-engine`.
|
|
- Both policies resolve to one exact path, avoiding duplicate values and
|
|
divergent rotation.
|
|
- Existing Secret names and keys remain stable, limiting rollout risk.
|
|
- A wrapped migration process is required because printing, downloading, or
|
|
staging either value would create a new disclosure path.
|
|
- Reversal deletes the ExternalSecrets/stores/AppRoles and restores the
|
|
protected pre-migration Secret snapshots during the bounded rollback window.
|
|
- Rotation changes the OpenBao fields, waits for all three ExternalSecrets,
|
|
and rolls the provisioner and portal together; failed synchronization stops
|
|
before either Deployment changes.
|
|
|
|
## 5. Executive summary
|
|
|
|
**One-line ask:** approve moving the existing user-engine edge marker and
|
|
provisioner token into one exact OpenBao workload path, delivered by two
|
|
namespace-specific, revocable External Secrets AppRoles.
|
|
|
|
**Who gets access:** only External Secrets through
|
|
`external-secrets-user-engine` and `external-secrets-sso-user-engine`.
|
|
Application pods continue to receive only their existing namespaced Secrets.
|
|
|
|
**To what:** read-only access to exactly
|
|
`platform/workloads/user-engine/runtime`; no sibling workload or tenant path.
|
|
|
|
**For how long:** each AppRole login receives a 15-minute token with a
|
|
30-minute maximum and eight uses. AppRole secret IDs persist for ESO continuity
|
|
until rotated or same-cluster Kubernetes auth replaces the bridge.
|
|
|
|
**Blast radius:** compromise permits impersonating the internal provisioner
|
|
client and/or the portal trusted marker, but grants no direct OpenBao sibling
|
|
read, directory administrator password, user password, MFA seed, or platform
|
|
role. Revoke both AppRole secret IDs, rotate both runtime values, and roll the
|
|
two workloads.
|
|
|
|
**Cost to reverse:** delete three ExternalSecrets, two stores, two AppRoles,
|
|
their bootstrap Secrets, and one exact policy/path; restore the protected
|
|
pre-migration Kubernetes Secret snapshots. No database or identity record
|
|
changes.
|
|
|
|
**Decision needed:** approve as proposed, reject, or return with changes.
|
|
Approval authorizes custody migration and bounded rotation rehearsal, never
|
|
printing or otherwise disclosing either value.
|
|
|
|
## 6. Build result
|
|
|
|
Built on 2026-07-30 exactly as approved:
|
|
|
|
- created KV path `platform/workloads/user-engine/runtime`;
|
|
- created policy `workload-kv-read-user-engine-runtime`;
|
|
- created AppRoles `external-secrets-user-engine` and
|
|
`external-secrets-sso-user-engine`;
|
|
- delivered each bootstrap identity directly into its Kubernetes Secret;
|
|
- created two namespace-restricted ClusterSecretStores and three
|
|
ExternalSecrets while preserving existing application Secret names;
|
|
- migrated the two existing values in a wrapped process without printing or
|
|
staging them;
|
|
- rehearsed coordinated rotation, waited for all three derived Secrets, and
|
|
returned both dependent Deployments to Ready;
|
|
- verified exact-path `read`, sibling-path `deny`, matching derived
|
|
provisioner tokens, and a live post-rotation identity reconciliation.
|
|
|
|
No new secret value requires founder paste-once provisioning. No credential
|
|
value was written to Git, logs, State Hub, or chat. The two executor audit
|
|
records are in `audit/build-log.jsonl`; no ops-warden catalog entry is needed
|
|
because this is an OpenBao/External Secrets runtime lane rather than an SSH
|
|
certificate route.
|