The bot's secrets live in Gitea: signed settings travel with the release bundle

POST /deploy-bot may now carry X-Vanguard-Env, base64 JSON of the bot's own settings, and the HMAC covers
that header together with the body so the pair cannot be separated or swapped. dumpd merges only the keys
BOT_ENV_KEYS allows (DISCORD_BOT_TOKEN, DISCORD_GUILD_ID by default) into the stack .env, atomically and
preserving mode and owner, and reports the rest to the CI job as settings_refused. The server keeps what it
generates: a CI job cannot touch the database password or the Authentik keys.

Verified: allowed keys applied, server-owned keys refused while the rest still applied, a settings swap
after signing rejected with 401, and an empty settings header leaving .env untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-11-02 21:37:35 -06:00
parent b05f129bed
commit 1e4c0e88dc
7 changed files with 106 additions and 8 deletions

View File

@@ -253,12 +253,28 @@ HMAC-SHA256 signature over the body, then runs `/usr/local/bin/vanguard-deploy-b
(bind-mounted at `/app`, previous release kept beside it) and restarts the container. The install log goes back
in the HTTP response, so it appears in the CI job.
Two settings, both generated into `.env` and copied to `/etc/vanguard/deploy.env` by `configure.py`:
**The bot's own secrets live in Gitea, not here.** The deploy job also sends the bot's settings, signed with
the bundle, and dumpd writes them into this stack's `.env` — but only the keys `BOT_ENV_KEYS` lists. Anything
else comes back to the CI job as `settings_refused` and is not written, so the database password and the
Authentik keys this repo generates cannot be overwritten from CI. Rotating the Discord token is therefore a
Gitea edit plus a re-run, with no server access.
In Gitea, on the bot repo under Settings → Actions:
| | |
|---|---|
| `BOT_DEPLOY_SECRET` | 64 hex chars. Paste it into Gitea → the bot repo → Settings → Actions → Secrets as **`BOT_DEPLOY_SECRET`**. `./configure.py --show` prints it. |
| `BOT_DEPLOY_AUTO` | `1` (default) accepts CI installs; `0` makes dumpd refuse them with 403 and you install by hand. |
| Secret `BOT_DEPLOY_SECRET` | must equal the server's; `./configure.py --show` prints it |
| Secret `DISCORD_BOT_TOKEN` | the bot token |
| Variable `DISCORD_GUILD_ID` | the server id |
| Variable `VANGUARD_DEPLOY_HOST` | only if the job cannot detect the Docker gateway |
On the server, generated into `.env` and copied to `/etc/vanguard/deploy.env` by `configure.py`:
| | |
|---|---|
| `BOT_DEPLOY_SECRET` | 64 hex chars, the shared signing key |
| `BOT_DEPLOY_AUTO` | `1` (default) accepts CI installs; `0` makes dumpd refuse them with 403 |
| `BOT_ENV_KEYS` | the only `.env` keys CI may set, `DISCORD_BOT_TOKEN,DISCORD_GUILD_ID` by default. Extend it when the bot needs a new setting. |
By hand, any time: