From 276925863117135e24aee3ef6ee5b8b5124f646c Mon Sep 17 00:00:00 2001 From: codex Date: Fri, 14 Aug 2026 19:01:08 +0200 Subject: [PATCH] feat: propose CCR-2026-0012 for platform-pg Barman key Workload KV path and ESO drafts for Secret platform-pg-backup-s3. Founder mints the project-scoped Scaleway application; values stay out of git. --- ...platform-pg-backup.clustersecretstore.yaml | 32 ++++++ .../CCR-2026-0012-platform-pg-backup-s3.yaml | 103 ++++++++++++++++++ docs/put-platform-pg-backup-s3.md | 72 ++++++++++++ docs/rapp-credential-lane-binding.md | 2 +- ...workload-kv-read-platform-pg-backup-s3.hcl | 11 ++ 5 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 argocd/platform-addons/openbao-secretstore/openbao-platform-pg-backup.clustersecretstore.yaml create mode 100644 credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml create mode 100644 docs/put-platform-pg-backup-s3.md create mode 100644 openbao/policies/workload-kv-read-platform-pg-backup-s3.hcl diff --git a/argocd/platform-addons/openbao-secretstore/openbao-platform-pg-backup.clustersecretstore.yaml b/argocd/platform-addons/openbao-secretstore/openbao-platform-pg-backup.clustersecretstore.yaml new file mode 100644 index 0000000..9f5fbc9 --- /dev/null +++ b/argocd/platform-addons/openbao-secretstore/openbao-platform-pg-backup.clustersecretstore.yaml @@ -0,0 +1,32 @@ +# DRAFT — CCR-2026-0012. Do not apply until the CCR is approved and the +# KV values are real. Deploy on railiance01 (databases lives there), not +# the CoulombCore ArgoCD kustomization. +# +# Prereq: ESO can authenticate to OpenBao with policy +# workload-kv-read-platform-pg-backup-s3. Interim railiance01 identity +# may be AppRole or a child token; Kubernetes auth role +# external-secrets-platform-pg-backup is the CCR-declared steady state. +apiVersion: external-secrets.io/v1 +kind: ClusterSecretStore +metadata: + name: openbao-platform-pg-backup + labels: + app.kubernetes.io/part-of: railiance-gitops + railiance-platform/component: external-secrets + app.kubernetes.io/name: platform-pg-backup +spec: + provider: + vault: + server: http://openbao.openbao.svc:8200 + path: platform + version: v2 + auth: + kubernetes: + mountPath: kubernetes + role: external-secrets-platform-pg-backup + serviceAccountRef: + name: external-secrets + namespace: external-secrets + conditions: + - namespaces: + - databases diff --git a/credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml b/credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml new file mode 100644 index 0000000..2b7206a --- /dev/null +++ b/credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml @@ -0,0 +1,103 @@ +id: CCR-2026-0012 +kind: credential-change-request +schema_version: 1 +request_type: workload-kv-read +title: Scaleway scoped Barman key for platform-pg backup +status: proposed +created: '2026-08-14' +updated: '2026-08-14' +requester: + agent: grok + reason: >- + RESOURCE-WP-0002 T04 needs a renewable, revocable, bucket-and-prefix + scoped Scaleway key in OpenBao so railiance-platform can vend Secret + platform-pg-backup-s3 into the databases namespace. The bootstrap key + (CCR-2026-0011) can create buckets and must not be the runtime key. +review: + required: true + required_approvers: + - platform-operator + comments: [] +target: + domain: financials + tenant: railiance + workload: platform-pg-backup + rapp: rapp-postgres + environment: production + purpose: >- + CNPG/Barman object-store credentials for platform-pg WAL and base + backups. Secret keys ACCESS_KEY_ID and ACCESS_SECRET_KEY only. + Endpoint, bucket, prefix, and region stay on reef-storage. +openbao: + mount: platform + kv_path: platform/workloads/railiance/backup/platform-pg-backup-s3 + fields: + - ACCESS_KEY_ID + - ACCESS_SECRET_KEY + - APPLICATION_ID + policy_name: workload-kv-read-platform-pg-backup-s3 + policy_file: openbao/policies/workload-kv-read-platform-pg-backup-s3.hcl + auth: + method: kubernetes + mount: kubernetes + role: external-secrets-platform-pg-backup + bound_claims: + service_account_names: + - external-secrets + service_account_namespaces: + - external-secrets + bound_claims_confirmed: false + policies: + - workload-kv-read-platform-pg-backup-s3 + ttl: 15m +access_frontdoor: + type: ops-warden + catalog_id: platform-pg-backup-s3 + selector: platform-pg Barman Scaleway key + command: warden access platform-pg-backup-s3 --fetch ACCESS_KEY_ID + resolvable: false + readiness: pending-review +delivery: + surface: external-secrets + target: >- + ClusterSecretStore openbao-platform-pg-backup (namespace condition + databases) → ExternalSecret databases/platform-pg-backup-s3 → Secret + platform-pg-backup-s3 with keys ACCESS_KEY_ID and ACCESS_SECRET_KEY. + Drafts live under railiance-platform/argocd/platform-addons/openbao-secretstore/ + and rapp-postgres/helm/platform-pg-backup-s3.externalsecret.yaml. + Do not apply until this CCR is approved and the KV values are real. +risk: + classification: high + notes: + - The runtime key can write and delete objects under the backup prefix. + Compromise can destroy recovery points or fill the bucket. + - The bootstrap key (CCR-2026-0011) must be revoked after this key works. + - Do not enable continuous WAL archiving until the empty-archive preflight + passes (RESOURCE-WP-0002 T05). + - Values must not appear in Git, State Hub, logs, or chat. +verification: + positive: + - Field names present on the KV path; values not printed. + - An approved databases-namespace ExternalSecret can sync ACCESS_KEY_ID + and ACCESS_SECRET_KEY to Secret platform-pg-backup-s3. + - The scoped key can list/put/delete only under prefix platform-pg/. + negative: + - A token without this policy cannot read the KV path. + - A namespace outside the ClusterSecretStore condition cannot use the store. + - A second, unused key (or revoked key) cannot access the bucket. + - The scoped key cannot list sibling buckets or create compute resources. + activation_conditions: + - Platform-operator approves this CCR. + - Founder creates the Scaleway IAM application and project-scoped + Object Storage key, then replaces OpenBao placeholders. + - ESO store and ExternalSecret applied only after values are real. +lifecycle: + deactivate: Disable the catalog entry, delete the ExternalSecret, revoke + the Scaleway API key, delete the IAM application. + rotate: Overlap-first. Put a new key in OpenBao, wait for ESO refresh, + revoke the old Scaleway key. + compromised: Revoke both the Barman key and the bootstrap key at Scaleway, + rotate this path, review bucket contents, open incident follow-up. +state_hub: + workplan_id: RESOURCE-WP-0002 + task_id: RESOURCE-WP-0002-T04 diff --git a/docs/put-platform-pg-backup-s3.md b/docs/put-platform-pg-backup-s3.md new file mode 100644 index 0000000..aa1bf8c --- /dev/null +++ b/docs/put-platform-pg-backup-s3.md @@ -0,0 +1,72 @@ +# Put the scoped Barman key (founder, local only) + +Do this on a trusted terminal. **Do not paste ACCESS_KEY_ID or +ACCESS_SECRET_KEY into chat, Git, or State Hub.** + +CCR: `credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml` +Path: `platform/workloads/railiance/backup/platform-pg-backup-s3` + +This is **not** the bootstrap key (`…/scaleway/bootstrap`). That key +created the bucket. This key is the CNPG/Barman runtime identity. + +## 1. Create a dedicated IAM application + +In [console.scaleway.com](https://console.scaleway.com) → IAM → Applications: + +1. Create application `railiance-barman-platform-pg`. +2. Create an API key **on that application** (not on your user): + - Description: `platform-pg Barman runtime` + - **Preferred Project for Object Storage:** the project that owns + bucket `railiance-platform-pg-backup` +3. Copy the access key and secret key into a local scratch file + (`chmod 600`). The secret is shown once. + +## 2. Attach a project-scoped Object Storage policy + +IAM → Policies → create `railiance-barman-platform-pg-objects`: + +- Principal: the application from step 1 +- Scope: **that one project**, not the whole Organization +- Permission sets, if the console lists them: + - `ObjectStorageBucketsRead` + - `ObjectStorageObjectsRead` + - `ObjectStorageObjectsWrite` + - `ObjectStorageObjectsDelete` +- If those sets are not listed, `ObjectStorageFullAccess` **on this + project only** is acceptable because the project should contain only + this backup bucket. + +Do **not** attach `IAM*` or compute permission sets. + +## 3. Put the values in OpenBao + +On this host, with a token that can write the `platform` mount: + +```bash +bao kv put platform/workloads/railiance/backup/platform-pg-backup-s3 \ + ACCESS_KEY_ID='SCWxxxxxxxx' \ + ACCESS_SECRET_KEY='xxxxxxxx' \ + APPLICATION_ID='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' +``` + +Or replace the `xxx` placeholders in the OpenBao UI on that same path. + +`APPLICATION_ID` is the IAM application UUID (not a secret). It is needed +later for the bucket policy. + +## 4. Confirm without printing values + +```bash +bao kv metadata get platform/workloads/railiance/backup/platform-pg-backup-s3 +``` + +You should see a current version greater than any placeholder version. +Then tell the agent: **“the Barman key is in bao.”** Also say the +application name if `APPLICATION_ID` is in bao. + +Do not enable WAL archiving yourself. T04 still has to prove a negative +key cannot access the bucket and to vend Secret `platform-pg-backup-s3`. +T05 enables continuous archiving. + +After the scoped key works, delete or lock down the bootstrap key from +CCR-2026-0011. diff --git a/docs/rapp-credential-lane-binding.md b/docs/rapp-credential-lane-binding.md index 2962312..d06eed7 100644 --- a/docs/rapp-credential-lane-binding.md +++ b/docs/rapp-credential-lane-binding.md @@ -180,7 +180,7 @@ shape unless it *is* a secrets engine. | --- | --- | --- | --- | | `rapp-openbao` | none | none — package is the store | correct | | `rapp-postgres` | `consumer_contract` + `openbao-database-secrets-engine` | `rapp-postgres/audit-core-runtime`, `rapp-postgres/audit-core-migration` | bound | -| `rapp-postgres` | `s3-backup-target` | no lane yet; Secret `platform-pg-backup-s3` is S3 custody after RESOURCE-WP-0002 | fail-closed on purpose | +| `rapp-postgres` | `s3-backup-target` / `secret_references: platform/workloads/railiance/backup/platform-pg-backup-s3` | `CCR-2026-0012` | pointer set; CCR `proposed`; Secret not vended | | `rapp-qonto` | `secret_references: tenants/binky/qonto-api` | `CCR-2026-0009` | pointer set; CCR itself is still `proposed` | Live CCRs without `target.rapp` are un-rapped workloads. They stay on diff --git a/openbao/policies/workload-kv-read-platform-pg-backup-s3.hcl b/openbao/policies/workload-kv-read-platform-pg-backup-s3.hcl new file mode 100644 index 0000000..aee15e3 --- /dev/null +++ b/openbao/policies/workload-kv-read-platform-pg-backup-s3.hcl @@ -0,0 +1,11 @@ +# Least-privilege read of the Barman runtime key for platform-pg. +# ESO (or the later Kubernetes auth role) is the only in-cluster reader. +# Values never belong in Git. + +path "platform/data/workloads/railiance/backup/platform-pg-backup-s3" { + capabilities = ["read"] +} + +path "platform/metadata/workloads/railiance/backup/platform-pg-backup-s3" { + capabilities = ["read"] +}