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.
122 lines
4.9 KiB
YAML
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
|