From 94b2f7cc9c116c94f07122194053804aebd34b7a Mon Sep 17 00:00:00 2001 From: codex Date: Fri, 14 Aug 2026 19:19:56 +0200 Subject: [PATCH] retarget: CCR-2026-0012 is the general backup object-store lane Use IAM application resource-control and policy Scoped backup access. OpenBao path is platform/workloads/railiance/backup/object-storage. rapp-postgres keeps Secret platform-pg-backup-s3 as the first projection. --- ...up-object-storage.clustersecretstore.yaml} | 15 +-- ...011-scaleway-object-storage-bootstrap.yaml | 4 +- .../CCR-2026-0012-backup-object-storage.yaml | 112 ++++++++++++++++++ .../CCR-2026-0012-platform-pg-backup-s3.yaml | 103 ---------------- ...kup-s3.md => put-backup-object-storage.md} | 42 ++++--- docs/rapp-credential-lane-binding.md | 5 +- ...workload-kv-read-backup-object-storage.hcl | 11 ++ ...workload-kv-read-platform-pg-backup-s3.hcl | 11 -- 8 files changed, 160 insertions(+), 143 deletions(-) rename argocd/platform-addons/openbao-secretstore/{openbao-platform-pg-backup.clustersecretstore.yaml => openbao-backup-object-storage.clustersecretstore.yaml} (59%) create mode 100644 credential-change-requests/CCR-2026-0012-backup-object-storage.yaml delete mode 100644 credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml rename docs/{put-platform-pg-backup-s3.md => put-backup-object-storage.md} (55%) create mode 100644 openbao/policies/workload-kv-read-backup-object-storage.hcl delete 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-backup-object-storage.clustersecretstore.yaml similarity index 59% rename from argocd/platform-addons/openbao-secretstore/openbao-platform-pg-backup.clustersecretstore.yaml rename to argocd/platform-addons/openbao-secretstore/openbao-backup-object-storage.clustersecretstore.yaml index 9f5fbc9..16a44ab 100644 --- a/argocd/platform-addons/openbao-secretstore/openbao-platform-pg-backup.clustersecretstore.yaml +++ b/argocd/platform-addons/openbao-secretstore/openbao-backup-object-storage.clustersecretstore.yaml @@ -1,19 +1,20 @@ # 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. +# KV values are real. Deploy on railiance01 (first consumer lives in +# databases), not the CoulombCore ArgoCD kustomization. # # Prereq: ESO can authenticate to OpenBao with policy -# workload-kv-read-platform-pg-backup-s3. Interim railiance01 identity +# workload-kv-read-backup-object-storage. Interim railiance01 identity # may be AppRole or a child token; Kubernetes auth role -# external-secrets-platform-pg-backup is the CCR-declared steady state. +# external-secrets-backup-object-storage is the CCR-declared steady state. +# Add further namespace conditions when another backup consumer is bound. apiVersion: external-secrets.io/v1 kind: ClusterSecretStore metadata: - name: openbao-platform-pg-backup + name: openbao-backup-object-storage labels: app.kubernetes.io/part-of: railiance-gitops railiance-platform/component: external-secrets - app.kubernetes.io/name: platform-pg-backup + app.kubernetes.io/name: backup-object-storage spec: provider: vault: @@ -23,7 +24,7 @@ spec: auth: kubernetes: mountPath: kubernetes - role: external-secrets-platform-pg-backup + role: external-secrets-backup-object-storage serviceAccountRef: name: external-secrets namespace: external-secrets diff --git a/credential-change-requests/CCR-2026-0011-scaleway-object-storage-bootstrap.yaml b/credential-change-requests/CCR-2026-0011-scaleway-object-storage-bootstrap.yaml index 877860c..67b74cd 100644 --- a/credential-change-requests/CCR-2026-0011-scaleway-object-storage-bootstrap.yaml +++ b/credential-change-requests/CCR-2026-0011-scaleway-object-storage-bootstrap.yaml @@ -55,7 +55,7 @@ risk: classification: high notes: - Bootstrap key can create projects/buckets; rotate or delete after scoped key exists. - - Scoped Barman key is a different path: platform/workloads/railiance/backup/platform-pg-backup-s3 + - Scoped backup key is a different path: platform/workloads/railiance/backup/object-storage - Values must not appear in Git, State Hub, or chat. verification: positive: @@ -64,5 +64,5 @@ verification: - default-policy token denied on the data path. lifecycle: deactivate: Delete bootstrap key at Scaleway after the scoped bucket key works. - rotate: Put a new bootstrap key; do not reuse the Barman key. + rotate: Put a new bootstrap key; do not reuse the scoped backup key. compromised: Revoke both Scaleway keys; rotate bucket policy. diff --git a/credential-change-requests/CCR-2026-0012-backup-object-storage.yaml b/credential-change-requests/CCR-2026-0012-backup-object-storage.yaml new file mode 100644 index 0000000..86d0a1f --- /dev/null +++ b/credential-change-requests/CCR-2026-0012-backup-object-storage.yaml @@ -0,0 +1,112 @@ +id: CCR-2026-0012 +kind: credential-change-request +schema_version: 1 +request_type: workload-kv-read +title: Scaleway scoped backup object-storage key +status: proposed +created: '2026-08-14' +updated: '2026-08-14' +requester: + agent: grok + reason: >- + RESOURCE-WP-0002 T04 needs a renewable, revocable, project-scoped + Scaleway backup key in OpenBao. Custody is the resource-control + procuring identity, not a Barman-specific application. First + consumer is rapp-postgres (Secret platform-pg-backup-s3). The + bootstrap key (CCR-2026-0011) must not be the runtime key. +review: + required: true + required_approvers: + - platform-operator + comments: [] +target: + domain: financials + tenant: railiance + workload: backup + rapp: rapp-postgres + environment: production + purpose: >- + Object-store credentials for Railiance backup destinations. + Secret keys ACCESS_KEY_ID and ACCESS_SECRET_KEY. APPLICATION_ID + is the resource-control IAM application (for a later bucket + policy). Endpoint, bucket, prefix, and region stay on reef-storage. +openbao: + mount: platform + kv_path: platform/workloads/railiance/backup/object-storage + fields: + - ACCESS_KEY_ID + - ACCESS_SECRET_KEY + - APPLICATION_ID + policy_name: workload-kv-read-backup-object-storage + policy_file: openbao/policies/workload-kv-read-backup-object-storage.hcl + auth: + method: kubernetes + mount: kubernetes + role: external-secrets-backup-object-storage + bound_claims: + service_account_names: + - external-secrets + service_account_namespaces: + - external-secrets + bound_claims_confirmed: false + policies: + - workload-kv-read-backup-object-storage + ttl: 15m +access_frontdoor: + type: ops-warden + catalog_id: backup-object-storage + selector: resource-control scoped backup access + command: warden access backup-object-storage --fetch ACCESS_KEY_ID + resolvable: false + readiness: pending-review +delivery: + surface: external-secrets + target: >- + ClusterSecretStore openbao-backup-object-storage (first namespace + condition: databases) → ExternalSecret databases/platform-pg-backup-s3 + → Secret platform-pg-backup-s3 (consumer projection). 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: + - Scaleway policies attach to the IAM application, not to one API key. + Application resource-control must hold only backup-scoped keys. + - The runtime key can write and delete backup objects. Compromise can + destroy recovery points or fill the bucket. + - The bootstrap key (CCR-2026-0011) must stay off this application and + 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 backup prefixes on the procured + bucket. + 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 create compute resources. + activation_conditions: + - Platform-operator approves this CCR. + - Founder creates or reuses IAM application resource-control, binds + policy Scoped backup access, mints the API key of that name, then + replaces OpenBao placeholders. + - ESO store and ExternalSecret applied only after values are real. +lifecycle: + deactivate: Disable the catalog entry, delete consumer ExternalSecrets, + revoke the Scoped backup access API key. Keep application + resource-control if other backup keys remain. + rotate: Overlap-first. Put a new key in OpenBao, wait for ESO refresh, + revoke the old Scaleway key. + compromised: Revoke the Scoped backup access 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/credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml b/credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml deleted file mode 100644 index 2b7206a..0000000 --- a/credential-change-requests/CCR-2026-0012-platform-pg-backup-s3.yaml +++ /dev/null @@ -1,103 +0,0 @@ -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-backup-object-storage.md similarity index 55% rename from docs/put-platform-pg-backup-s3.md rename to docs/put-backup-object-storage.md index aa1bf8c..fa582a5 100644 --- a/docs/put-platform-pg-backup-s3.md +++ b/docs/put-backup-object-storage.md @@ -1,31 +1,38 @@ -# Put the scoped Barman key (founder, local only) +# Put the scoped backup object-store 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` +CCR: `credential-change-requests/CCR-2026-0012-backup-object-storage.yaml` +Path: `platform/workloads/railiance/backup/object-storage` This is **not** the bootstrap key (`…/scaleway/bootstrap`). That key -created the bucket. This key is the CNPG/Barman runtime identity. +created the bucket. This key is the general **backup** runtime identity +for application `resource-control`. First consumer is `rapp-postgres` +(Secret `platform-pg-backup-s3`). -## 1. Create a dedicated IAM application +## 1. Use IAM application `resource-control` In [console.scaleway.com](https://console.scaleway.com) → IAM → Applications: -1. Create application `railiance-barman-platform-pg`. +1. Create application `resource-control` if it does not exist. Do **not** + create a Barman- or postgres-specific application. 2. Create an API key **on that application** (not on your user): - - Description: `platform-pg Barman runtime` + - Description / name: `Scoped backup access` - **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 +Put **only** backup-scoped keys on this application. Scaleway attaches +policies to the application, not to one key. The bootstrap key must stay +off `resource-control`. -IAM → Policies → create `railiance-barman-platform-pg-objects`: +## 2. Bind policy `Scoped backup access` -- Principal: the application from step 1 +IAM → Policies → create (or reuse) `Scoped backup access`: + +- Principal: application `resource-control` - Scope: **that one project**, not the whole Organization - Permission sets, if the console lists them: - `ObjectStorageBucketsRead` @@ -34,7 +41,7 @@ IAM → Policies → create `railiance-barman-platform-pg-objects`: - `ObjectStorageObjectsDelete` - If those sets are not listed, `ObjectStorageFullAccess` **on this project only** is acceptable because the project should contain only - this backup bucket. + backup buckets. Do **not** attach `IAM*` or compute permission sets. @@ -43,7 +50,7 @@ Do **not** attach `IAM*` or compute permission sets. On this host, with a token that can write the `platform` mount: ```bash -bao kv put platform/workloads/railiance/backup/platform-pg-backup-s3 \ +bao kv put platform/workloads/railiance/backup/object-storage \ ACCESS_KEY_ID='SCWxxxxxxxx' \ ACCESS_SECRET_KEY='xxxxxxxx' \ APPLICATION_ID='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' @@ -51,21 +58,20 @@ bao kv put platform/workloads/railiance/backup/platform-pg-backup-s3 \ 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. +`APPLICATION_ID` is the `resource-control` 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 +bao kv metadata get platform/workloads/railiance/backup/object-storage ``` 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. +Then tell the agent: **“the backup key 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`. +key cannot access the bucket and to vend the first consumer Secret. T05 enables continuous archiving. After the scoped key works, delete or lock down the bootstrap key from diff --git a/docs/rapp-credential-lane-binding.md b/docs/rapp-credential-lane-binding.md index d06eed7..c604f63 100644 --- a/docs/rapp-credential-lane-binding.md +++ b/docs/rapp-credential-lane-binding.md @@ -47,7 +47,8 @@ the list does not say who provisions the thing that satisfies a name. `openbao-database-secrets-engine` and `s3-backup-target` are capabilities. The database engine is configured by S3 from statements the package owns; the backup bucket is a `resource-control` resource and the -provider credential is S3 custody (`Secret platform-pg-backup-s3`). +provider credential is S3 custody (`secret:railiance-platform/backup`, +first projection Secret `platform-pg-backup-s3`). Fail-closed until that handoff lands is correct, not a hole in the package. @@ -180,7 +181,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` / `secret_references: platform/workloads/railiance/backup/platform-pg-backup-s3` | `CCR-2026-0012` | pointer set; CCR `proposed`; Secret not vended | +| `rapp-postgres` | `s3-backup-target` / `secret_references: platform/workloads/railiance/backup/object-storage` | `CCR-2026-0012` | pointer set; CCR `proposed`; first consumer of the general backup key; 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-backup-object-storage.hcl b/openbao/policies/workload-kv-read-backup-object-storage.hcl new file mode 100644 index 0000000..e9aa431 --- /dev/null +++ b/openbao/policies/workload-kv-read-backup-object-storage.hcl @@ -0,0 +1,11 @@ +# Least-privilege read of the resource-control backup object-store key. +# ESO (or the later Kubernetes auth role) is the only in-cluster reader. +# Values never belong in Git. + +path "platform/data/workloads/railiance/backup/object-storage" { + capabilities = ["read"] +} + +path "platform/metadata/workloads/railiance/backup/object-storage" { + capabilities = ["read"] +} diff --git a/openbao/policies/workload-kv-read-platform-pg-backup-s3.hcl b/openbao/policies/workload-kv-read-platform-pg-backup-s3.hcl deleted file mode 100644 index aee15e3..0000000 --- a/openbao/policies/workload-kv-read-platform-pg-backup-s3.hcl +++ /dev/null @@ -1,11 +0,0 @@ -# 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"] -}