Playbook: Encryption Key Rotation (Last Resort — Confirmed Exposure Only)
Covers: SUPABASE_JWT_SECRET · IAM_ENC_KEY · N8N_ENCRYPTION_KEY · WEBHOOK_SECRET
THESE ARE LAST-RESORT ROTATIONS.
Do NOT rotate on schedule. These keys are designated static per
credential-rotation-policy.md. Rotate only on confirmed exposure (value seen in logs, committed to git, or exposed in chat).Impact of rotation:
SUPABASE_JWT_SECRET/IAM_ENC_KEY— all user sessions invalidated immediatelyN8N_ENCRYPTION_KEY— all n8n stored credentials become unreadable; all workflows haltWEBHOOK_SECRET— webhook HMAC validation fails until both producer and consumer are updated
Overview
| Key | SOPS file | Impact |
|---|---|---|
SUPABASE_JWT_SECRET | whatsup | All signed JWTs for p24-wa-a invalidated; users logged out |
IAM_ENC_KEY | whatsup | All IAM-encrypted tokens become undecryptable |
N8N_ENCRYPTION_KEY | n8n-bms4 | All n8n stored credentials (OAuth tokens, API keys) unreadable |
WEBHOOK_SECRET | whatsup | In-flight webhook calls fail HMAC validation |
Tier: ❌ Tier 3 Manual — keys are generated locally but require a maintenance window and coordinated rollout.
Pre-rotation requirements (all keys)
- Open a GH issue:
sec: rotate KEY_NAME — confirmed exposure YYYY-MM-DD(label:critical) - Maintenance window scheduled and stakeholders notified
- Rollback plan confirmed before making any change
- For
N8N_ENCRYPTION_KEY: n8n credential vault exported (see Step 1 below)
SUPABASE_JWT_SECRET / IAM_ENC_KEY
Effect: All active p24-wa-a user sessions are immediately terminated. Users must re-authenticate.
Steps
-
Schedule maintenance window — notify users: “All sessions will terminate at
<time>.” -
Generate new keys:
# 32-byte random values — never print these variables
$env:NEW_JWT = [Convert]::ToBase64String([Security.Cryptography.RandomNumberGenerator]::GetBytes(32))
$env:NEW_IAM = [Convert]::ToBase64String([Security.Cryptography.RandomNumberGenerator]::GetBytes(32))
# Store to .env.local for handoff; clear $env:NEW_* after SOPS update-
Distribute: Update
secrets/whatsup.env.sops— keys:SUPABASE_JWT_SECRET,IAM_ENC_KEY. Followdocs/playbooks/sops-edit-operations.md. -
Deploy: Commit → merge →
secrets-sync.yml→ restart all JWT-signing consumers:
docker compose restart p24-wa-a # or equivalent service name-
Verify: New user login succeeds. Old session tokens return
401. -
Rollback if broken:
git revertthe SOPS commit → re-merge →secrets-sync.yml→ restart.
N8N_ENCRYPTION_KEY
Effect: All stored n8n credentials become unreadable. Every workflow using a stored credential fails immediately. This is a major operation requiring full credential re-entry.
Steps
- Export credential vault BEFORE changing the key:
ssh root@100.86.202.85
docker exec -it n8n n8n export:credentials --all \
--output=/home/node/creds-backup-$(date +%Y%m%d).json
docker cp n8n:/home/node/creds-backup-*.json /opt/backups/Keep this backup — it is encrypted with the OLD key.
- Generate new encryption key:
NEW_KEY=$(openssl rand -hex 16) # 32-char hex — never echo-
Update
secrets/n8n-bms4.env.sops— key:N8N_ENCRYPTION_KEY. Followdocs/playbooks/sops-edit-operations.md. -
Deploy and restart n8n:
ssh root@100.86.202.85 "cd /opt/n8n && docker compose stop n8n && docker compose up -d n8n"-
Re-enter all credentials in n8n UI. All existing credentials will show as broken. Use the exported JSON (decryptable with the old key) as a reference for the original values. Re-enter each credential manually via n8n UI → Credentials.
-
Verify: Trigger each critical workflow manually; confirm credentials load without errors.
-
Rollback if n8n fails to start: Revert SOPS commit → redeploy → credentials from backup.
WEBHOOK_SECRET
Effect: All in-flight webhook calls fail HMAC validation until producer and consumer are both updated.
Steps
-
Identify all producer and consumer endpoints for this secret before proceeding.
-
Generate new secret:
$env:NEW_WH = ([BitConverter]::ToString([Security.Cryptography.RandomNumberGenerator]::GetBytes(32))).Replace("-","").ToLower()-
Coordinate atomic rollout — during low-traffic window:
- Update
secrets/whatsup.env.sops— key:WEBHOOK_SECRET - Restart consumer first, then producer to minimize validation failures
- Update
-
Verify: Send a test webhook and confirm successful HMAC validation.
Log rotation
| YYYY-MM-DD HH:MM UTC | #ISSUE | N8N_ENCRYPTION_KEY | confirmed exposure | radieu | n8n-bms4.env.sops — full credential migration completed |
References
secret-rotation-access-matrix.md— Tier 3 danger notesdocs/playbooks/sops-edit-operations.md— SOPS write patterndocs/playbooks/static-api-key-incident-rotation.md— exposure incident responsedocs/playbooks/credential-rotation-policy.md— why these keys are static