diff --git a/docs/provisioning.md b/docs/provisioning.md index 4bd1af8..f22ad5d 100644 --- a/docs/provisioning.md +++ b/docs/provisioning.md @@ -118,17 +118,23 @@ Reconciliation is **converging, never destructive**: Nothing sensitive enters the spec or the resolved state. Both are committed. -Paths are `//`, set by `BAO_MOUNT` and `FLUID_BAO_PREFIX`. -The default (`secret/fluid-telegram//telegram`) is a development -fallback, and the campaign is part of it so that two campaigns on one interface -cannot read each other's credentials. +Paths follow the fleet convention +`platform/workloads///`, owned by railiance-platform +and routed to by ops-warden (`ops-warden/wiki/CredentialRouting.md`): -**This repository does not get to invent the fleet's secret layout.** ops-warden -routes API-key needs to railiance-platform, whose convention is -`platform/workloads///` — see -`ops-warden/wiki/CredentialRouting.md`. The final names are owner-confirmed, so -they are configuration here rather than a constant, and the production values -are settled with railiance-platform before the first apply. +``` +platform/workloads/infotech/fluid-telegram// +``` + +The campaign sits between the workload and the bundle so that two campaigns on +one interface cannot read each other's credentials; the bundle then names the +secret itself. `BAO_MOUNT` and `FLUID_BAO_PREFIX` override both halves, because +the layout belongs to its owner and not to this repository. + +ops-warden does not hold any of these. It **issues** SSH certificates and +**routes** every other credential need to the subsystem that owns it, so it is +where to ask *how* to authenticate to OpenBao — `warden access 'openbao token +for reading a kv secret'` — and never where the secret lives. | Secret | Key | Rule | |---|---|---| diff --git a/docs/seeding-runbook.md b/docs/seeding-runbook.md index 20759ec..c77362d 100644 --- a/docs/seeding-runbook.md +++ b/docs/seeding-runbook.md @@ -67,20 +67,17 @@ The provisioner computes these paths; they are not a convention you may vary. For campaign `hall-of-helix` on the default `secret` mount: ``` -secret/fluid-telegram/hall-of-helix/telegram/operator-app api_id, api_hash -secret/fluid-telegram/hall-of-helix/telegram/operator-session written by the tool -secret/fluid-telegram/hall-of-helix/telegram/bot-token written by the tool -secret/fluid-telegram/hall-of-helix/telegram/redaction-salt written by the tool, once +platform/workloads/infotech/fluid-telegram/hall-of-helix/operator-app api_id, api_hash +platform/workloads/infotech/fluid-telegram/hall-of-helix/operator-session written by the tool +platform/workloads/infotech/fluid-telegram/hall-of-helix/bot-token written by the tool +platform/workloads/infotech/fluid-telegram/hall-of-helix/redaction-salt written by the tool, once ``` -Those are the **development defaults**. The fleet convention for an API-key -bundle is `platform/workloads///`, owned by -railiance-platform; ask ops-warden for the current shape and override it: - -```bash -export BAO_MOUNT=platform -export FLUID_BAO_PREFIX=workloads/infotech/fluid-telegram -``` +This follows the fleet convention +`platform/workloads///` owned by railiance-platform, +with the campaign between workload and bundle so two campaigns on one interface +cannot read each other's credentials. These are the defaults; `BAO_MOUNT` and +`FLUID_BAO_PREFIX` override them if the owner changes the layout. Authenticate the way ops-warden routes you, which is OIDC through key-cape rather than a plain token login: @@ -140,14 +137,14 @@ exposes it, Step 2 disappears. everything downstream reads it: ```bash -bao kv put secret/fluid-telegram/hall-of-helix/telegram/operator-app \ +bao kv put platform/workloads/infotech/fluid-telegram/hall-of-helix/operator-app \ api_id= api_hash= ``` Verify the tool can see it before going on: ```bash -bao kv get secret/fluid-telegram/hall-of-helix/telegram/operator-app +bao kv get platform/workloads/infotech/fluid-telegram/hall-of-helix/operator-app ``` They are shown once per application. Losing them means creating another. @@ -165,7 +162,7 @@ go run ./cmd/provision session bootstrap --campaign hall-of-helix It prompts for the phone number, the login code, and the 2FA password, then writes the session string to OpenBao at -`secret/fluid-telegram/hall-of-helix/telegram/operator-session`. +`platform/workloads/infotech/fluid-telegram/hall-of-helix/operator-session`. The session string is a **full-account credential** — it can do anything the account can. It never leaves OpenBao, is never given to the adapter, and is used diff --git a/internal/secrets/secrets.go b/internal/secrets/secrets.go index f66cba8..0747275 100644 --- a/internal/secrets/secrets.go +++ b/internal/secrets/secrets.go @@ -54,14 +54,18 @@ func NewFromEnv(campaign string) (*Store, error) { return nil, fmt.Errorf("no OpenBao token: set BAO_TOKEN, or run `bao login` "+ "to write ~/.vault-token (BAO_ADDR is %s)", addr) } - // Mount and prefix are configurable because this repo does not get to invent - // the fleet's secret layout. ops-warden routes API-key needs to - // railiance-platform, whose convention is - // platform/workloads/// -- see - // ops-warden/wiki/CredentialRouting.md. The defaults below are a local - // fallback for development, not the intended production location. - mount := firstNonEmpty(os.Getenv("BAO_MOUNT"), "secret") - prefix := firstNonEmpty(os.Getenv("FLUID_BAO_PREFIX"), "fluid-telegram/"+campaign+"/telegram") + // The fleet convention, confirmed with the owner: + // platform/workloads///, per + // ops-warden/wiki/CredentialRouting.md and railiance-platform. + // + // The campaign sits between the workload and the bundle so that two + // campaigns on one interface cannot read each other's credentials -- the + // bundle then names the secret itself (operator-app, bot-token, ...). + // Both halves stay overridable: the layout is the owner's to change, not + // this repository's. + mount := firstNonEmpty(os.Getenv("BAO_MOUNT"), "platform") + prefix := firstNonEmpty(os.Getenv("FLUID_BAO_PREFIX"), + "workloads/infotech/fluid-telegram/"+campaign) return &Store{ addr: strings.TrimSuffix(addr, "/"), token: token,