Rotate secrets
Periodic rotation of Olympus secrets
Olympus has several secrets that should be rotated periodically. Rotation cadence depends on your threat model, but a sensible baseline:
| Secret | Cadence | Difficulty |
|---|---|---|
| Database passwords | 90 days | Medium |
| Kratos session cookie key | 180 days | Easy (overlap supported) |
| Kratos cipher key | Per ADR 0006 | Hard (data re-encryption) |
| Hydra system secret | 90 days | Easy (overlap supported) |
| OAuth2 client secrets | Per client need | Medium |
| Encryption key | See encryption-key-rotation | Hard |
| TLS certs | Auto (Caddy) | None |
Database passwords
Postgres passwords for kratos, hydra, athena users.
- Generate new password:
openssl rand -base64 32 - Add to Postgres:
ALTER USER kratos PASSWORD 'NEW_PASS'; - Update
.env:KRATOS_DB_PASSWORD=NEW_PASS - Restart container:
podman-compose restart ciam-kratos
If you don't want downtime, use Postgres MD5 rotation (less ideal) or have two users with overlap.
Kratos session cookie key
This signs the ory_kratos_session cookie. Rotating invalidates existing sessions (users re-login) unless overlapped.
Kratos supports an array, the first key is used to sign, all are tried for verify.
# kratos.yml
secrets:
cookie:
- NEW_KEY
- OLD_KEYAfter 24h (longest session), drop OLD_KEY.
Hydra system secret
Hydra's system secret encrypts client secrets, etc., in DB.
# hydra.yml
secrets:
system:
- NEW
- OLD
cookie:
- NEW
- OLDSame overlap pattern.
OAuth2 client secrets
For your apps. Rotate when:
- A team member leaves who had access.
- You suspect leakage.
- Periodically (180d?).
# Add new secret without removing old (Hydra supports both during transition)
hydra update client <id> --secret NEW_SECRET --keep-old-secret
# Roll your app to use NEW_SECRET
# Then:
hydra update client <id> --secret NEW_SECRET # removes oldEncryption keys
See Cookbook, Rotate encryption key, this is the most operationally complex rotation.
TLS certs
Caddy auto-renews. Nothing to do.
For pinned certs (rare), manual replacement.
Automation
Scripted rotation:
#!/bin/bash
# rotate-cookie-secret.sh
NEW_KEY=$(openssl rand -base64 32)
OLD_KEY=$(grep KRATOS_SECRETS_COOKIE .env | cut -d= -f2)
cat > .env.new << EOF
KRATOS_SECRETS_COOKIE=${NEW_KEY},${OLD_KEY}
EOF
cp .env.new .env
podman-compose restart ciam-kratos
# Schedule a cleanup in 24h
at "now + 1 day" << EOF
sed -i 's/,${OLD_KEY}//' /path/to/.env
podman-compose restart ciam-kratos
EOFInventory
Keep a secrets register: name, vault path, last rotated, next due. Update on each rotation.
# secrets-register.yml
secrets:
- name: kratos_cookie
vault: secret/olympus/kratos/cookie
last_rotated: 2026-02-15
next_due: 2026-08-15
rotation_runbook: docs/cookbook/secrets-rotation.mdx#kratos-session-cookie-keyWhat NOT to rotate
- Identity user passwords (users do that themselves).
- OAuth2 access tokens (short-lived; rotation via refresh).
- ID tokens (they expire).
- Refresh tokens (one-shot rotation on use).
These rotate organically.