Rotating the encryption key
Re-encrypted: the per-report key wrappers, confidential identity and contact, secure e-mail, TOTP secrets, identity-reveal reasons. Report content and attachments are not touched. Back up the database first.
- Set
ENCRYPTION_KEY_PREVIOUSto the key in use: the oldENCRYPTION_KEY, orSECRET_KEYon an install that never set one. - Set
ENCRYPTION_KEYto a new value (openssl rand -hex 32) and recreate the container:docker compose up -d(a restart keeps the old environment). - Run
docker compose exec app python scripts/rotate_encryption_key.py. It writes nothing unless every value can be re-encrypted; otherwise it lists the rows by id. Safe to run twice. - Empty
ENCRYPTION_KEY_PREVIOUSand recreate the container again:docker compose up -d.
At every start, before migrating, the app checks one stored report key and one TOTP
secret. If no key opens them, it refuses to start and writes nothing; the log line names
ENCRYPTION_KEY_PREVIOUS. That happens, for example, when
ENCRYPTION_KEY is set on an existing install without step 1, or removed again.
Helm: before step 3, wait until every pod runs with the new environment
(kubectl rollout status). During the rolling update, old pods cannot read data
that new pods write.
Until step 3 has succeeded, removing it leaves data unreadable. Afterwards, keep it safe
as long as any backup from before the rotation is kept. To restore such a backup, put the
old key back into ENCRYPTION_KEY_PREVIOUS and run the script.