Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02878-7c21-7692-bcd6-ce2838c4b448
8.8 KiB
| id | demand_source | consumer_repo | credential_type | status | approved_by | approved_at | created | updated |
|---|---|---|---|---|---|---|---|---|
| rapp-qonto-openbao-approle-bridge | reef-railiance/workplans/REEF-RAILIANCE-WP-0003-T01 | rapp-qonto | openbao-approle-kv | built | Bernd Worsch | 2026-07-27 | 2026-07-27 | 2026-08-22 |
Construction plan: rapp-qonto OpenBao AppRole bridge
1. Demand
rapp-qonto needs non-interactive, read-only delivery of the existing Binky
Qonto API credential from tenants/binky/qonto-api into its dedicated
Kubernetes namespace. External Secrets Operator should authenticate directly
to OpenBao and mint short-lived tokens; neither the application nor a
ClusterSecretStore should hold a long-lived OpenBao token.
2. Existing-structure survey
Live OpenBao state was checked on 2026-07-27:
- auth mounts include
kubernetes/; its configured API endpoint is the cluster-localhttps://10.43.0.1:443; - existing Kubernetes roles are
external-secrets-activity-core,external-secrets-issue-core, andexternal-secrets-reuse-surface; - policy
workload-kv-read-binky-qonto-apialready exists and is scoped to the existing tenant credential; - the
tenants/KV v2 mount andtenants/binky/qonto-apivalue already exist; this plan does not create or read the value; - existing cluster stores use an interim static-token pattern, despite the Kubernetes roles existing;
CCR-2026-0009proposed a duplicateworkload-kv-read-qonto-assistantpolicy and the transitionalqonto-assistantnamespace/name.
Topology verification established that this OpenBao instance runs on Coulombcore while the consumer runs on railiance01. Its existing Kubernetes auth mount validates Coulombcore service-account tokens and cannot validate a railiance01 token. A cross-cluster Kubernetes auth mount would additionally require stable TokenReview API reachability and a reviewer identity across the cluster boundary.
The existing read policy satisfies the requested data scope exactly. Reuse it; do not create the duplicate policy from CCR-2026-0009. Use a dedicated AppRole as a transitional bridge because it does not couple authentication to the wrong Kubernetes API. Retain same-cluster Kubernetes workload authentication as the target when secret custody and workload placement are unified.
3. Proposed changes
| # | Action | Object | Reuse-vs-new rationale |
|---|---|---|---|
| 1 | reuse | policy workload-kv-read-binky-qonto-api |
Already grants the exact required read scope; a second equivalent policy adds drift without isolation |
| 2 | create | AppRole external-secrets-rapp-qonto |
Dedicated non-human bridge; policy #1, token TTL 15 minutes, maximum TTL 30 minutes, bounded token uses |
| 3 | deliver | Kubernetes Secret external-secrets/openbao-rapp-qonto-approle |
Holds only the AppRole role ID and secret ID for ESO; created through the approved Mason delivery path, never committed or logged |
| 4 | create | ClusterSecretStore/openbao-rapp-qonto |
Uses AppRole #2 and secret #3 against the tenants KV v2 mount; namespace condition permits only rapp-qonto |
| 5 | modify | rapp-qonto ExternalSecret |
Map remote fields API_USER -> QONTO_LOGIN and API_KEY -> QONTO_SECRET_KEY; no values enter Git or logs |
| 6 | retire | proposed openbao-qonto-assistant static-token store |
Superseded before deployment; avoids a long-lived OpenBao token in a Kubernetes Secret |
| 7 | propose | ops-warden catalog entry rapp-qonto-workload-kv |
Pointer to the built AppRole lane, warden_executes: false, initially draft |
| 8 | record | migration residual | Replace the AppRole bridge with same-cluster Kubernetes auth when OpenBao custody or workload placement is unified |
No underlying Qonto secret is created, changed, printed, or rotated.
4. Review notes
- Naming: steady-state
rapp-qontonames replace the migration-onlyqonto-assistantnames. - TTL/scoping: 15-minute tokens match existing External Secrets roles; maximum TTL is 30 minutes and token uses are bounded. The ClusterSecretStore condition restricts consumers to one namespace.
- Redundancy: reuses the exact existing policy. This removes the duplicate policy proposed by CCR-2026-0009.
- Compaction: the draft static-token Qonto store is retired before it is deployed. Existing unrelated stores are untouched.
- Consumer usability: External Secrets performs authentication and delivery. The application consumes only a namespaced Kubernetes Secret.
- Posture: the lane accesses a high-risk bank credential, but it is read-only and the runtime exposes no financial write operation. Production still requires egress, audit, revocation, and failure-domain gates.
- Credential custody: the AppRole secret ID is a revocable bootstrap credential held only in a namespaced Kubernetes Secret accessible to ESO. It is not a Qonto credential and never enters Git, workplans, audit events, command output, or chat.
- Migration: this bridge is intentionally transitional. A cross-cluster TokenReview dependency is rejected for now because it expands networking, reviewer-identity, and failure-domain coupling.
5. Executive summary
One-line ask: allow External Secrets on railiance01 to use a dedicated,
revocable AppRole bridge to deliver the existing Binky Qonto read credential
to rapp-qonto, issuing only short-lived OpenBao tokens.
Who/what gets access: a new AppRole named
external-secrets-rapp-qonto. Its bootstrap identity is stored in
external-secrets/openbao-rapp-qonto-approle and referenced only by the
dedicated ClusterSecretStore. No application pod, human role, or unrelated
store receives the identity.
To what: read-only access through the existing
workload-kv-read-binky-qonto-api policy to exactly
tenants/binky/qonto-api. Store use is limited to ExternalSecret resources in
the rapp-qonto namespace.
For how long: each AppRole login receives a 15-minute OpenBao token with a 30-minute maximum and bounded uses. The revocable AppRole secret ID persists for ESO continuity until rotated or the bridge is retired; no OpenBao token persists in Kubernetes.
Blast radius if the identity is abused: an attacker able to read the AppRole bootstrap Secret could mint bounded, short-lived tokens and read the Binky Qonto API credential. The OpenBao policy cannot read any sibling tenant secret. Revoke/rotate the AppRole secret ID immediately; rotate the downstream Qonto key too if it may have been read.
Cost to reverse: delete one AppRole, its bootstrap Kubernetes Secret, one
ClusterSecretStore, and the rapp-qonto ExternalSecret/derived Secret. The
existing human Qonto lane and underlying credential remain intact.
Decision needed: approve as proposed, reject, or send back to phase 1 with changes. Approval authorizes the structural access lane only, never disclosure or modification of the Qonto credential value.
Previous decision: the Kubernetes-auth design was approved by Bernd Worsch on 2026-07-27. That approval does not authorize this revised AppRole design.
6. Build result
Build attempted 2026-07-27 and stopped during verification. The OpenBao role
was created, but the store login returned 403. Live topology inspection showed
that bao.coulomb.social resolves to Coulombcore (92.205.130.254), while the
ESO service account token belongs to railiance01 (92.205.62.239). The
existing kubernetes/ auth mount therefore validates a different cluster.
The failed ClusterSecretStore, ExternalSecret, disposable namespace, and mis-targeted OpenBao role were removed without reading a secret value. No live object from the failed build remains.
The revised phase-2 recommendation is alternative 2: use the dedicated
AppRole bridge described above until the OpenBao/cluster boundary is unified.
The revised plan was explicitly approved by Bernd Worsch on 2026-07-27
(go on). Phase 4 may proceed.
7. Revised build result
Built and verified on 2026-07-27 through
ops_mason.executor.build_approle_kv_lane:
- reused policy
workload-kv-read-binky-qonto-api, scoped to exactlytenants/binky/qonto-api; - created AppRole
external-secrets-rapp-qontowith 15-minute token TTL, 30-minute maximum TTL, eight token uses, and a revocable secret ID; - delivered the role ID and secret ID directly into Kubernetes Secret
external-secrets/openbao-rapp-qonto-approle; temporary local and remote delivery files were removed; - created namespace-restricted
ClusterSecretStore/openbao-rapp-qonto; - synchronized
ExternalSecret/rapp-qontointoSecret/rapp-qonto-runtime.
Metadata-only live verification reported the store Valid, the
ExternalSecret SecretSynced, and exactly two keys in the derived Secret. No
credential value was read, printed, committed, or recorded.
The bridge remains transitional. Replace it with same-cluster Kubernetes authentication when OpenBao custody and workload placement are unified.