diff --git a/plans/reef-storage-scaleway-bootstrap.md b/plans/reef-storage-scaleway-bootstrap.md new file mode 100644 index 0000000..5eff3ba --- /dev/null +++ b/plans/reef-storage-scaleway-bootstrap.md @@ -0,0 +1,127 @@ +--- +id: reef-storage-scaleway-bootstrap +demand_source: resource-control/workplans/RESOURCE-WP-0002-T03 +consumer_repo: reef-storage +credential_type: openbao-kv-founder-provision +status: reviewed +approved_by: null +approved_at: null +created: "2026-08-14" +updated: "2026-08-14" +--- + +# Construction plan: Scaleway bootstrap key for reef-storage + +## 1. Demand + +We need to create a private Scaleway Multi-AZ bucket in `nl-ams` for +postgres backup (`RESOURCE-WP-0002`). The founder has a new Scaleway +account and an API key in the usual Terraform snippet shape +(`access_key`, `secret_key`, `organization_id`, `project_id` in +`scaleway.auto.tfvars`). Those four values must live in OpenBao, not in +git or chat. ops-mason builds the empty lane. The founder pastes the +values once (desk or local tfvars ingest). reef-storage then creates the +bucket by reading OpenBao and never printing the keys. + +## 2. Existing-structure survey + +Checked 2026-08-14: + +- **KV path does not exist.** + `platform/metadata/workloads/railiance/scaleway/bootstrap` is 404. + Same for the later Barman path + `platform/workloads/railiance/backup/platform-pg-backup-s3`. +- **CCR already reserved the path.** + `railiance-platform` `CCR-2026-0011` names + `platform/workloads/railiance/scaleway/bootstrap` and the four fields. + Reuse that path. Do not invent a second one. +- **CCR-2026-0004** is Nextcloud/age offsite backup + (`platform/workloads/railiance/backup/offsite-lane`). Different + provider, different fields. Do not merge. +- **Catalog.** No `scaleway` / `s3-backup` lane. `openbao-api-key` is the + generic template and must not become this concrete key. +- **Auth.** This is an operator-workstation bootstrap key for a one-shot + (or rare) `scw` create, not an in-cluster ESO consumer. No AppRole. + Founder paste-once / local tfvars ingest is the right desk. The later + scoped Barman key (T04) is a different path and may get a workload + CCR then. +- **Does an existing lane already satisfy this?** No live secret. The + reserved CCR path is the one to build. + +Terraform snippet → OpenBao fields (same four facts, scw-native names): + +| Terraform (`scaleway.auto.tfvars`) | OpenBao field | +| --- | --- | +| `access_key` | `ACCESS_KEY` | +| `secret_key` | `SECRET_KEY` | +| `organization_id` | `DEFAULT_ORGANIZATION_ID` | +| `project_id` | `DEFAULT_PROJECT_ID` | + +## 3. Proposed changes + +| # | Action | Object | Reuse-vs-new rationale | +|---|---|---|---| +| 1 | reuse | CCR-2026-0011 path `platform/workloads/railiance/scaleway/bootstrap` | Already reserved; do not fork | +| 2 | create | empty KV v2 path (metadata only, no secret data) | Structure so paste-once / ingest has a home | +| 3 | create | policy `operator-kv-scaleway-bootstrap` (read/write that path only) | Founder desk and the bucket-create script; no sibling paths | +| 4 | reuse | founder paste-once desk + optional local tfvars ingest | ops-mason never sees values; four fields, four desk pastes or one founder-run ingest | +| 5 | propose | catalog `scaleway-bootstrap` (draft) + playbook | Pointer only; `warden_executes: false` | +| 6 | defer | AppRole / ESO / scoped Barman key | T04 / CCR for `platform-pg-backup-s3`; not this plan | + +No new rail. Scaleway operates S3. + +## 4. Review notes + +- **Naming:** path follows `platform/workloads/railiance/…`. Policy + `operator-kv-scaleway-bootstrap` matches “operator workstation, not + workload ESO.” +- **TTL/scoping:** no AppRole token. The *downstream* Scaleway key is + long-lived until the founder deletes it after the scoped key exists. +- **Redundancy:** does not reuse Nextcloud offsite-lane. Does not put + org-admin keys in the Barman runtime path. +- **Compaction:** none. This is the first Scaleway lane. +- **Secret values:** mason does not read, write, or log them. Founder + uses `warden desk --act paste_once_provision` four times, or + `reef-storage/tools/ingest-scaleway-tfvars.sh` on a local 0600 + `scaleway.auto.tfvars` they already have. +- **Founder remaining acts:** approve this plan; paste four fields (or + run ingest once); say “bootstrap is in OpenBao.” + +## 5. Executive summary + +**One-line ask:** approve an OpenBao home for the four Scaleway Terraform +variables so we can create the backup bucket without putting keys in git +or chat. + +**Who gets access:** you (founder / operator token) to write the four +fields; the bucket-create script, using that same operator token, to +read them once. No new AppRole. No cluster workload. Nothing else gains +a path. + +**To what:** only +`platform/workloads/railiance/scaleway/bootstrap` +(`ACCESS_KEY`, `SECRET_KEY`, `DEFAULT_ORGANIZATION_ID`, +`DEFAULT_PROJECT_ID`). Not the later Barman key path. Not other +`platform/workloads/railiance/backup/*` secrets. + +**For how long:** the KV version stays until you rotate or delete it. +This bootstrap key should be revoked at Scaleway after the scoped bucket +key works (T04). + +**Blast radius if the credential leaks:** create/list/delete Object +Storage (and whatever else that API key can do in the project). Revoke +the key in the Scaleway console, delete the KV version, rotate to a +scoped bucket-only key. + +**Cost to reverse:** delete the KV path, draft catalog entry, and +policy. No other consumer is bound. The bucket, once created, stays +until you empty and delete it. + +**Decision:** approve, reject, or send back to phase 1. +Approval authorizes structure (empty path, policy, catalog draft) and +your paste-once / tfvars ingest. It does not authorize ops-mason to +handle the Terraform secret values. + +## 6. Build result + +Not executed. Waiting on phase-3 approval of this plan.