# Secrets Management This directory documents the secrets required for each Docker Swarm stack. ## How It Works ``` Secret values live in Woodpecker (encrypted) → pipeline reads them at deploy time Docker Swarm secret store (encrypted Raft DB, replicated across all nodes) → mounted into containers at runtime /run/secrets/ ``` ## Files in This Directory Each `.secrets.example` file documents: - **Which keys are secrets** (sensitive — must go in Woodpecker) - **Which keys are non-secrets** (config values — can live in compose file or .env) - **The Woodpecker secret name** to use for each value - **What the value is used for** These files contain **NO actual values** — they are safe to commit to Git. ## How to Add a Secret to Woodpecker 1. Go to **https://woodpecker.bryanmail.net** 2. Navigate to `homelab/compose-files` → **Settings** → **Secrets** 3. Click **Add Secret** 4. Set the **Name** exactly as shown in the `.secrets.example` file 5. Paste the **Value** from the corresponding `.env` file on the host 6. Save ## How to Migrate a Stack ### Step 1 — Add secrets to Woodpecker UI Use the stack's `.secrets.example` file as your checklist. ### Step 2 — Add the stack's case to `.woodpecker.yml` In the `provision-secrets` step, add a case for the stack that calls `create_or_update_secret` for each secret. (Or, preferred for new migrations: add an entry to `secrets/secrets-map.yaml` + a `.env.template` and call `deploy/provision-stack.py ` instead — see the `ai` and `traefik` entries for the current pattern.) ### Step 3 — Test by pushing a trivial change to the stack's yaml file Watch the pipeline run: provision-secrets → validate → deploy → verify → notify. ### Step 4 — Remove the `.env` file from the host (optional) Once the pipeline is managing secrets, the host-side `.env` file is redundant. Keep it as a backup until you're confident. ## Secret Naming Convention Docker secret names use underscores and lowercase. The convention used here is: ``` _ ``` Examples: - `git_db_password` - `ai_aws_secret_access_key` - `security_crowdsec_api_key` ## Important Notes - **Docker cannot update a secret in-place.** The `deploy/create-secrets.sh` helper handles this by removing and recreating changed secrets automatically. Services using the secret will continue running with the old value until the stack is redeployed. - **Woodpecker cannot manage its own secrets.** The `woodpecker` stack must always be managed manually. See `woodpecker.secrets.example` for details. - **PostgreSQL is highest risk.** Its master password is used by nearly every other stack. Migrate it last. - **Never commit a rendered env file, even by accident.** `traefik/traefik.env` was committed to git for a period (discovered/fixed 2026-09-12) with a literal "***REDACTED***" placeholder as KEEPALIVED_PASSWORD, which was silently restored every time the file was deleted or the checkout resynced from git — causing a real VRRP auth outage. `.gitignore` blanket-excludes `*.env`, but that rule does NOT retroactively untrack a file already committed before the rule existed. If you ever see a stack's `.env` file show up in `git status` as tracked, stop and untrack it (`git rm --cached`) before doing anything else. ## Migration Status | Stack | Secrets in Woodpecker | Pipeline Step Added | .env Removed | |-------|------------------------|----------------------|---------------| | 3dprint | ⏳ | ⏳ | ⏳ | | ai | ⏳ | ⏳ | ⏳ | | auth | ⏳ | ⏳ | ⏳ | | entertainment | ⏳ | ⏳ | ⏳ | | gamma | ⏳ | ⏳ | ⏳ | | git | ⏳ | ⏳ | ⏳ | | guacamole | ⏳ | ⏳ | ⏳ | | homeassistant | ⏳ | ⏳ | ⏳ | | maintenance | ✅ N/A (no secrets) | ✅ N/A | ⏳ | | media | ✅ N/A (no secrets) | ✅ N/A | ⏳ | | mealie | ⏳ | ⏳ | ⏳ | | meshcentral | ⏳ | ⏳ | ⏳ | | n8n | ⏳ | ⏳ | ⏳ | | postgresql | ⏳ | ⏳ | ⏳ | | productivity | ⏳ | ⏳ | ⏳ | | security | ⏳ | ⏳ | ⏳ | | traefik | ✅ (manifest-driven, 2026-09-12) | ✅ (manifest-driven, 2026-09-12) | ⏳ | | unifi | ✅ N/A (no secrets) | ✅ N/A | ⏳ | | vaultwarden | ⏳ | ⏳ | ⏳ | | woodpecker | ⏳ Manual only | ⏳ N/A | ⏳ |