Secret Rotation
debt(d8/e7/b5/t5)
Closest to 'silent in production until users hit it' (d9), but secret managers like aws-secrets-manager/vault/doppler can report stale secrets and rotation age, so slightly better at d8. Without those tools, lack of rotation is invisible until breach.
Closest to 'cross-cutting refactor across the codebase' (e7). Implementing rotation requires inventorying all secrets, updating every consumer to support overlap, automating the rotation pipeline, and coordinating revocation — spans many files and infra.
Closest to 'persistent productivity tax' (b5). Per applies_to (web, cli), rotation policy affects multiple deployment contexts and adds ongoing operational overhead to every service consuming secrets, but doesn't define the system's shape.
Closest to 'notable trap most devs eventually learn' (t5). The misconception is that rotation requires downtime; the documented gotcha is forgetting the overlap window and updating all consumers before revoking the old secret — a classic learned lesson.
Also Known As
TL;DR
Explanation
Secrets that never rotate are permanent liabilities — a leaked key from 3 years ago is still valid if it was never rotated. Rotation strategies: scheduled (every 90 days), event-driven (on team member departure, suspected breach), and zero-downtime (new key deployed alongside old, then old revoked). AWS Secrets Manager and HashiCorp Vault can automate rotation for database credentials, rotating the password and updating all application references without downtime.
Common Misconception
Why It Matters
Common Mistakes
- Manual rotation that gets deferred — automate rotation; manual processes are always delayed.
- Rotating the secret without updating all consumers — causes outages when the old secret is revoked.
- No secret inventory — cannot rotate what you cannot find; maintain a registry of all secrets and their consumers.
- Using the same secret across environments — a compromised dev secret should not be valid in production.
Code Examples
# Hardcoded secret, never rotated:
# .env (committed to git 3 years ago):
DB_PASSWORD=super_secret_2021
API_KEY=sk_live_abc123
# Same values used for 3 years
# Leaked in git history — still valid
# Former employee knows them — still valid
# Automated rotation with AWS Secrets Manager:
# aws secretsmanager create-secret --name prod/db-password
# aws secretsmanager rotate-secret --secret-id prod/db-password
# --rotation-lambda-arn arn:aws:lambda:...
# --rotation-rules AutomaticallyAfterDays=30
# Application reads secret at startup (not hardcoded):
$secret = json_decode(
Aws\SecretsManager\SecretsManagerClient::getSecretValue(['SecretId' => 'prod/db-password'])['SecretString'],
true
);
$pdo = new PDO('mysql:host=' . $secret['host'], $secret['username'], $secret['password']);