n8n Secrets Audit — SOPS Centralisation

Implements: is-232 Centralise n8n SOPS Last updated: 2026-05-27

This document records the gap analysis between env vars referenced by n8n workflow JSONs (infra-src/n8n-workflows/) and what is currently stored in secrets/vps-h1.sops.yaml. Goal: vps-h1.sops.yaml is the single source of truth for all env vars consumed by n8n via $env.VARIABLE_NAME.


Audit results (2026-05-27)

Env vars in use (extracted from workflow JSONs)

VariableWorkflow(s)Status
SUPABASE_SERVICE_KEYalertmanager-to-incidents, fleet-update-v2-batch, wa-ai-to-inbox, wa-group-sync, wa-processing-watchdog, wa-routerIn SOPS (supabase_service_key)
WAHA_API_KEYwa-group-syncIn SOPS (waha_api_key)
GITHUB_TRIGGER_SECRETgithub-auto-triggerIn SOPS (github_trigger_secret)
GH_TOKENgh-actions-monitor, sentry-to-githubIn SOPS (gh_token)
DISCORD_WEBHOOK_URLsentry-to-github, wa-processing-watchdogMissing from SOPS
CLAUDE_PROXY_SECRETwa-ai-to-inboxMissing from SOPS
ATRAX_CLIENT_IDfleet-update-v2-batchMissing from SOPS
ATRAX_CLIENT_SECRETfleet-update-v2-batchMissing from SOPS
ATRAX_PASSWORDfleet-update-v2-batchMissing from SOPS
ATRAX_USERNAMEfleet-update-v2-batchMissing from SOPS

Already in SOPS (non-n8n env vars)

These are in vps-h1.sops.yaml or shared.sops.yaml and shipped to /root/.env but consumed by other services (Traefik TLS, WAHA, Promtail, n8n core config):

domain_name, evolution_api_key, generic_timezone, loki_basic_auth_password, ssl_email, subdomain, supabase_url


What was done in is-232

hostinger/docker-compose.yml — n8n service environment: block — added pass-throughs for all 6 missing variables so that when SOPS adds them, they are automatically available to n8n:

- DISCORD_WEBHOOK_URL=${DISCORD_WEBHOOK_URL}
- CLAUDE_PROXY_SECRET=${CLAUDE_PROXY_SECRET}
- ATRAX_CLIENT_ID=${ATRAX_CLIENT_ID}
- ATRAX_CLIENT_SECRET=${ATRAX_CLIENT_SECRET}
- ATRAX_PASSWORD=${ATRAX_PASSWORD}
- ATRAX_USERNAME=${ATRAX_USERNAME}

These pass-throughs are no-ops if the vars are absent from /root/.env — they pass empty strings, which is safe and will not break existing behaviour.


Human action required — add secrets to SOPS

The 6 missing secrets must be added to secrets/vps-h1.sops.yaml by a human with the AGE private key.

Step 1 — edit SOPS file

# On local dev machine (radieu) with AGE key at ~/.age/personal.key
SOPS_AGE_KEY_FILE=~/.age/personal.key sops edit secrets/vps-h1.sops.yaml

Or on vps-i1 (the GHA runner has the AGE key):

# Via GitHub Actions — edit secrets file and push to main
# The secrets-sync.yml workflow runs automatically

Step 2 — add the following keys

Add these lines to the decrypted content (sops will encrypt on save):

discord_webhook_url: "<value from 1Password / DISCORD_WEBHOOK_URL GitHub Secret>"
claude_proxy_secret: "<value from 1Password / CLAUDE_PROXY_SECRET GitHub Secret>"
atrax_client_id: "<ATRAX API client ID>"
atrax_client_secret: "<ATRAX API client secret>"
atrax_password: "<ATRAX account password>"
atrax_username: "<ATRAX account username>"

Source references:

  • DISCORD_WEBHOOK_URL — GitHub Secret DISCORD_WEBHOOK_URL in radieu/p24-infra
  • CLAUDE_PROXY_SECRET — GitHub Secret CLAUDE_PROXY_SECRET in radieu/p24-infra
  • ATRAX credentials — in 1Password under “ATRAX API” or on the Hostinger VPS in the existing n8n Credentials store

Step 3 — commit and push to main

git add secrets/vps-h1.sops.yaml
git commit -m "feat(secrets): add discord/atrax/claude-proxy secrets for n8n #is-232"
git push origin main

secrets-sync.yml triggers automatically, decrypts, converts to env, ships to /root/.env on vps-h1, and runs docker compose up -d.

Step 4 — verify

ssh root@72.60.32.61 'grep -c DISCORD_WEBHOOK_URL /root/.env'  # expect: 1
ssh root@72.60.32.61 'docker compose exec n8n printenv DISCORD_WEBHOOK_URL | wc -c'  # expect: >1

Rotation procedure

To rotate any of these secrets in future:

  1. SOPS_AGE_KEY_FILE=~/.age/personal.key sops edit secrets/vps-h1.sops.yaml — update value
  2. Commit + push to main
  3. secrets-sync.yml ships within ~2 min
  4. Append row to docs/secrets-rotation-log.md