| name | secret-management |
| description | Secret management — env vars, vaults, rotation, no secrets in code. |
Never-Do Table
| Anti-pattern | Why it's dangerous |
|---|
| Hardcode secrets in source code | Committed to git history; visible to anyone with repo access |
Commit .env files with real values | Permanent exposure even after deletion (git history) |
| Log secrets (even partially) | Log aggregators, third-party services, and crash reports may store them |
| Use the same secret across environments | Dev breach compromises production |
| Pass secrets as CLI arguments | Visible in process list (ps aux), shell history |
| Store in environment variables of public CI runs | Forked PR pipelines can exfiltrate them |
Detecting Secrets Already in Git History
git log --all -S "sk-" --oneline
git log --all -S "AKIA" --oneline
git log --all -S "ghp_" --oneline
git log --all -S "password" --oneline
trufflehog git file://. --only-verified
gitleaks detect --source . --log-level warn
If a secret is found in history: rotate it immediately, then use git filter-repo or BFG to purge — but assume the secret is already compromised.
Vault Options
| Tool | When to use |
|---|
| HashiCorp Vault | Self-hosted; complex access policies; dynamic secrets; multi-cloud |
| AWS Secrets Manager | AWS-native workloads; built-in rotation for RDS/Redshift/DocumentDB |
| GCP Secret Manager | GCP-native workloads; IAM-controlled access; regional replication |
| Azure Key Vault | Azure-native workloads; HSM-backed secrets; certificate management |
| Doppler / Infisical | SaaS option; easy local dev sync; team-friendly; multi-cloud |
| 1Password Secrets Automation | Teams already using 1Password; low operational overhead |
Prefer managed services (AWS/GCP/Azure) when already in that cloud — less infra to maintain and automatic audit trails.
Rotation Policy
| Secret Type | Rotation Frequency | Rotate Immediately If |
|---|
| Application secrets (JWT, API keys) | Every 90 days | Suspected exposure or team member offboarding |
| Database credentials | Every 90 days | Developer leaves or breach suspected |
| Infrastructure credentials (cloud IAM) | Every 30 days | Any security incident |
| Service-to-service tokens | Every 30 days | Service is decommissioned |
| Human user passwords | Every 180 days | Phishing, breach notification, or MFA reset |
Rotate immediately on any confirmed or suspected exposure — do not wait for the scheduled cycle.
Environment Variable Rules
.env — real values, never committed; add to .gitignore
.env.example — template with placeholder values, always committed
.env.test — test-only values (no production secrets); can be committed if values are non-sensitive stubs
- CI/CD — use the platform secret store (GitHub Actions secrets, GitLab CI variables, Doppler integration)
.gitignore minimum:
.env
.env.local
.env.*.local
*.pem
*.key
secrets/
Loading pattern (12-factor):
import os
from dotenv import load_dotenv
load_dotenv()
DATABASE_URL = os.environ["DATABASE_URL"]
Checklist