railiance-platform/credential-change-requests/CCR-2026-0009-qonto-assistant-workload-kv-read.yaml
codex dfa6373985
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Has been cancelled
Close RAILIANCE-WP-0015-T06 rapp credential-lane binding
Document the one recipe a new rapp uses to acquire runtime secrets:
standing KV secrets bind through a CCR target.rapp, leases through
grant rapp_id. Stamp the existing postgres grants and the qonto
workload CCR. Gate, delivery, and revocation are unchanged.
2026-08-14 00:47:28 +02:00

122 lines
4.9 KiB
YAML

id: CCR-2026-0009
kind: credential-change-request
schema_version: 1
request_type: workload-kv-read
title: qonto-assistant workload access to tenants/binky/qonto-api
status: proposed
created: '2026-07-24'
updated: '2026-08-13'
requester:
agent: claude
reason: >-
qonto-assistant (QONTO-WP-0004, docs/SecurityPractice.md) needs its own
running pod to fetch tenants/binky/qonto-api at cold-start, without
reusing the existing human/OIDC admin lane from CCR-2026-0008 (which is
scoped to net-kingdom-admins operators, not a workload identity). Mirrors
CCR-2026-0003's llm-connect pattern: External Secrets Operator reads the
KV path into a namespace-scoped Kubernetes Secret; qonto-assistant's pod
consumes the resulting Secret, never the OpenBao token itself.
review:
required: true
required_approvers:
- platform-operator
- binky-tenant-owner
comments: []
target:
domain: financials
tenant: binky
workload: qonto-assistant
rapp: rapp-qonto
environment: production
purpose: >-
Workload (not human/admin) read access to the existing
tenants/binky/qonto-api credential so qonto-assistant's own pod can fetch
it via External Secrets, matching the isolation profile requested in
qonto-assistant/docs/SecurityPractice.md #7 (I1 Reinforced minimum).
openbao:
mount: tenants
kv_path: tenants/binky/qonto-api
fields:
- API_KEY
- API_USER
policy_name: workload-kv-read-qonto-assistant
policy_file: openbao/policies/workload-kv-read-qonto-assistant.hcl
auth:
method: kubernetes
mount: kubernetes
role: external-secrets-qonto-assistant
bound_claims:
service_account_names:
- external-secrets
service_account_namespaces:
- external-secrets
bound_claims_confirmed: false
policies:
- workload-kv-read-qonto-assistant
ttl: 15m
access_frontdoor:
type: ops-warden
catalog_id: qonto-assistant-workload-kv
selector: qonto-assistant workload Qonto API key
command: warden access qonto-assistant-workload-kv --fetch API_KEY,API_USER
resolvable: false
readiness: pending-review
delivery:
surface: external-secrets
target: >-
ExternalSecret to Secret qonto-assistant-qonto-api in the (new, dedicated)
qonto-assistant namespace -- see
qonto-assistant/deploy/k8s/qonto-assistant/externalsecret.yaml (draft,
not yet applied).
risk:
classification: high
notes:
- Same underlying bank credential as CCR-2026-0008; this CCR does not
request a new secret value, only a second, workload-scoped access lane
into the existing tenants/binky/qonto-api path.
- The Kubernetes auth subject is the External Secrets Operator service
account external-secrets/external-secrets, with ClusterSecretStore usage
limited to the new qonto-assistant namespace (mirrors CCR-2026-0003's
activity-core scoping) -- no other namespace can use this store to read
this path.
- qonto-assistant's own policy kernel (default-deny, no spend/volume-cost
tools) is the downstream control on what the fetched credential is used
for; this CCR only governs whether the pod can fetch it at all.
- qonto-assistant's deployment isolation profile (namespace, NetworkPolicy,
resource limits) should land before or alongside this CCR's approval, not
after -- see qonto-assistant/deploy/k8s/qonto-assistant/.
verification:
positive:
- An approved qonto-assistant-namespace ExternalSecret can sync fields
API_KEY/API_USER to Secret qonto-assistant-qonto-api without printing
values.
- The qonto-assistant runtime can consume the resulting Kubernetes Secret
without exposing values (existing credentials.py env-injection path,
unchanged).
negative:
- A namespace outside the approved ClusterSecretStore condition cannot use
this store to read the path.
- A service account outside external-secrets/external-secrets cannot
authenticate through this OpenBao role.
activation_conditions:
- qonto-assistant namespace exists (see deploy/k8s/qonto-assistant/namespace.yaml,
draft).
- Policy and Kubernetes auth role applied with platform-admin/operator
authority.
- ClusterSecretStore openbao-qonto-assistant applied, scoped to the
qonto-assistant namespace only (draft manifest alongside this CCR).
- Positive and negative verification recorded with non-secret audit ids or
timestamps.
evidence: []
lifecycle:
deactivate: Disable ops-warden catalog entry and remove or detach the
external-secrets-qonto-assistant auth role policy. Does not affect
CCR-2026-0008's separate human/OIDC admin lane.
rotate: Shared with CCR-2026-0008 -- rotating the underlying API key in
Qonto's dashboard and OpenBao rotates both access lanes simultaneously;
no independent rotation exists for this lane alone.
compromised: Immediately deactivate this access front door; the underlying
key compromise/rotation procedure is CCR-2026-0008's, since both lanes
share the same secret value.
state_hub:
workplan_id: QONTO-WP-0004