| 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-qonto` names replace the migration-only
`qonto-assistant` names.
- **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.