ops-mason/plans/reef-storage-scaleway-bootstrap.md

144 lines
6.2 KiB
Markdown

---
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: built
approved_by: "Bernd Worsch"
approved_at: "2026-08-14"
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 backup path
`platform/workloads/railiance/backup/object-storage`.
- **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 backup key | T04 / CCR for `backup/object-storage`; 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
Executed 2026-08-14 after founder asked to bootstrap with example
data and replace values in the OpenBao UI.
Created (structure + placeholders only; values are the string `xxx`):
- policy `operator-kv-scaleway-bootstrap` (read/write that one path)
- KV v2 `platform/workloads/railiance/scaleway/bootstrap` version 1
fields `ACCESS_KEY`, `SECRET_KEY`, `DEFAULT_ORGANIZATION_ID`,
`DEFAULT_PROJECT_ID`
- custom_metadata `placeholder=true`, `ccr=CCR-2026-0011`,
`replace_in_ui=true`
Catalog draft `scaleway-bootstrap` already proposed.
**Founder next:** OpenBao UI → secret
`platform/workloads/railiance/scaleway/bootstrap` → create version 2
with the real Terraform values. Then say “bootstrap is in OpenBao.”
The bucket-create script refuses `xxx` placeholders.