Secrets Rotation Runbook
Secret Inventory
| Secret | File | Type | Rotation Cadence |
|---|---|---|---|
pg_uri | secrets/pg_uri | PostgreSQL password | Quarterly |
session_key | secrets/session_key | HMAC key (32 bytes hex) | Quarterly |
cache_hmac | secrets/cache_hmac | Cache HMAC key (32 bytes hex) | Quarterly |
kms_local_key | secrets/kms_local_key | Ed25519 private key (32 bytes raw) | Semi-annually |
vendor_public_key | pkg/license/zz_keys.go | Ed25519 public key (64 hex chars) | Per vendor rotation |
Rotation Procedures
Session Key / Cache HMAC
# Generate new 32-byte random keys
openssl rand -hex 32 > deploy/secrets/session_key
openssl rand -hex 32 > deploy/secrets/cache_hmac
# Restart services to pick up new secrets
docker compose restart gateway admin loggerd
Note: Rotating session_key will invalidate all active sessions. Notify users.
Rotating cache_hmac will evict cached data (rebuilds automatically).
PostgreSQL Password
- Log into the database:
docker compose exec postgres psql -U yabanin - Create new password:
ALTER USER yabanin WITH PASSWORD 'newpassword'; - Update
secrets/pg_uriwith the new password - Restart all services:
docker compose restart
KMS Local Key
# Generate new 32-byte raw key (Ed25519 private key)
head -c 32 /dev/urandom > deploy/secrets/kms_local_key
# Verify it's exactly 32 bytes
wc -c deploy/secrets/kms_local_key
# Expected: 32
# Restart services that use KMS
docker compose restart gateway loggerd kms-signer
Warning: Rotating kms_local_key invalidates all previously signed license keys. You must regenerate vendor-signed license keys after this rotation.
Vendor Public Key (zz_keys.go)
The vendor public key is embedded in Go source (pkg/license/zz_keys.go). To rotate it:
- Obtain the new Ed25519 public key from the vendor
- Update
const VendorPublicKey = "<64-char hex>"inzz_keys.go - Run
go generate ./pkg/license/...to regenerate if needed - Commit and redeploy
Emergency Rotation
If a secret is suspected to be compromised:
- Immediately rotate the affected secret using procedures above
- Restart all affected services:
docker compose restart - For session_key or pg_uri — notify users of service disruption
- Audit logs for unauthorized access:
docker compose logs gateway | grep -i "unauthorized\|forbidden"