From a4e48a7bca3b576e44d68b25bc6b8a7c27f21e51 Mon Sep 17 00:00:00 2001 From: atlas Date: Tue, 27 Oct 2026 12:02:44 +0100 Subject: [PATCH] store the forge webhook secret and grafana's secret key in bao, seeded from the existing files --- docs/agent-lifecycle/persistence.md | 13 +- docs/swarm/credentials-reference.md | 82 ++-- .../glue-bao-readers-policy-order.nix | 8 +- .../glue-bao-readers-store-order.nix | 1 + nix/host-modules/swarm-bao.nix | 22 +- nix/host-modules/swarm-grafana.nix | 183 ++++++--- nix/module-eval/bao-grants.nix | 46 ++- nix/module-eval/grafana.nix | 31 ++ nix/module-eval/swarm-services-switch.nix | 5 +- swarm-controller/README.md | 4 +- swarm-controller/src/main.rs | 8 +- swarm-controller/src/startup.rs | 4 +- swarm-controller/src/webhook.rs | 367 ++++++++++++++++-- swarm-secret-client/src/forge.rs | 36 ++ swarm-secret-client/src/lib.rs | 29 ++ 15 files changed, 697 insertions(+), 142 deletions(-) diff --git a/docs/agent-lifecycle/persistence.md b/docs/agent-lifecycle/persistence.md index 99edfcbe..1838fed4 100644 --- a/docs/agent-lifecycle/persistence.md +++ b/docs/agent-lifecycle/persistence.md @@ -497,13 +497,16 @@ Only present on the one host running so it survives restarts and redeploys. - `webhook-secret` — the HMAC key Forgejo signs the swarm's forge webhooks - with. **Keep it.** It's handed to Forgejo when swarm-controller registers a hook, - so replacing the file means every subsequent delivery fails - verification until the hook is re-registered with the new value. It's - generated automatically on first start; there's nothing to configure. + with, as it was before the swarm secret store held it. **Keep it.** The + controller stores its value in the swarm secret store at + `swarm/controller/swarm-controller/forge/webhook-secret` the first time it + starts with that path empty, and reads the store from then on. The file is the + fallback while the store is unreachable or its policy doesn't grant the path + yet, and nothing else reads or removes it. A host with neither the file nor a + store value gets a new secret in the store, with nothing to configure. -If the file is unreadable at startup the daemon still starts and logs +If the store can't answer and the file is unreadable or missing at startup, the daemon still starts and logs `webhook secret unavailable`; the webhook endpoint then answers 503 rather than accepting deliveries it can't verify. Everything else the controller serves is unaffected. diff --git a/docs/swarm/credentials-reference.md b/docs/swarm/credentials-reference.md index dadc9075..93349050 100644 --- a/docs/swarm/credentials-reference.md +++ b/docs/swarm/credentials-reference.md @@ -14,33 +14,35 @@ the rest of the cell says how. -| store path | minter | reader | automatic re-mint | automatic re-pull | -| ----------------------------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `swarm/agents//matrix/main` | `swarm-controller`, at agent creation and every 5 minutes | the agent | ✅ when missing or rejected by the homeserver | ✅ the daemon restarts within 5 minutes of a rejection | -| `swarm/agents//matrix/` | `swarm-controller`, from a credential you hand it | the agent | must be stated | ✅ retried within 2 to 16 minutes after a rejection | -| `swarm/agents//matrix-recovery/` | `swarm-controller`, a random passphrase per account | the agent | ❌ never replaced: the account's key backup opens only with this passphrase | ❌ read when the account comes up | -| `swarm/controller/swarm-controller/matrix/appservice-token` | `swarm-matrix-ctl` in `hive-matrix`, once | `swarm-controller` | ❌ minted once | ✅ read every 5 minutes | -| `swarm/controller/swarm-controller/oidc/client` | authelia, first boot | `swarm-controller` | ❌ minted once; `swarm-secret-publish` republishes a re-mint | ✅ re-read when authelia refuses it | -| `swarm/controller/swarm-controller/forge/token` | the forge, once | `swarm-controller` | ❌ minted once; delete `/var/lib/forgejo/swarm-controller-token-name` in the forge container to mint a new one | ✅ re-read on a 401 | -| `swarm/controller/swarm-controller/grafana/token` | `swarm-bao-grafana-controller-token` on Grafana's host | `swarm-controller` | ✅ every 10 minutes, when Grafana refuses it or none is stored | ✅ re-read on a 401 | -| `swarm/agents//bao-mtls` | the store's agent PKI mount (`deploy.bao.agentPkiMountPath`), at agent creation | `hive-c0re`, then the agent | ✅ re-issued every 5 minutes once past half its 7-day validity | ✅ the agent re-reads every 10 minutes; it renews only while its current leaf is valid | -| `swarm/agents//queue` | `swarm-controller`, at agent creation | the agent; the queue, log and metrics auth services | ✅ re-minted at 45 days; skipped for `Destroyed` agents, whose path is deleted | ✅ read on every reconnect; an open connection keeps the old secret for up to an hour; the log and metrics stores honour a replaced secret for up to `deploy.victorialogs.authVerdictTtl` and `deploy.victoriametrics.agentAuthVerdictTtl` (60 s by default) | -| `swarm/agents//forge-token` | `swarm-controller`, at agent creation and every 5 minutes | the agent | ✅ when missing or no longer matching the forge | ✅ every 10 minutes | -| `swarm/agents//forge/