Secrets Management
Problème
Les secrets (API keys, DB passwords, private keys) hardcodés dans le code ou les .env files sont une vulnérabilité persistante et répandue. Repository scanning tools trouvent régulièrement des credentials actifs dans des repos publics et privés.
Solution
Stratégie multi-niveau pour gérer les secrets sur tout le cycle de vie.
1. Hiérarchie de stockage
| Niveau | Méthode | Usage |
|---|---|---|
| Production | HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager | Runtime, service accounts, managed identities |
| Staging | Vault ou cloud secrets manager (env séparé) | Idem prod mais isolé |
| Development | .env (gitignored) + .env.example (template sans valeurs) |
Local dev uniquement |
| Jamais | Hardcode dans code, commit dans repo | Anti-pattern [[KNOW-ANT-002]], [[KNOW-ANT-007]] |
2. Pre-commit hooks (dernière ligne de défense)
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
- repo: https://github.com/trufflesecurity/trufflehog
rev: v3.80.0
hooks:
- id: trufflehog
# Alternative simple — git-secrets
git secrets --install
git secrets --register-aws
git secrets --add 'password\s*=\s*.*'
git secrets --add 'api_key\s*=\s*.*'
3. Séparation server-only vs public
// Next.js — server-only secrets
import { serverOnlySecret } from '@/lib/secrets'; // pas exporté au client
// Variables publiques (NEXT_PUBLIC_*) — peuvent aller au client
// Variables server-only — jamais exposées au client
4. Rotation des secrets
# Politique de rotation
API_KEYS:
rotation_period: 90_days
overlap: 7_days # ancien + nouveau valides pendant 7j
DB_PASSWORDS:
rotation_period: 180_days
JWT_SECRET:
rotation_period: 30_days
strategy: dual_secret # ancien + nouveau pendant overlap
5. Vault pattern (production)
// HashiCorp Vault — récupération au startup
const vault = require('node-vault')({
apiVersion: 'v1',
endpoint: process.env.VAULT_ADDR
});
await vault.kubernetesLogin({ role: 'my-app' });
const { data } = await vault.read('secret/data/myapp/db');
const dbPassword = data.data.password;
// Pas de secret en mémoire plus longtemps que nécessaire
// Rotate via Vault dynamic secrets si possible
6. Checklist
- Aucun secret dans le code (grep
password=,api_key=,secret=) -
.envdans.gitignore -
.env.exampleavec noms de variables mais pas de valeurs - Pre-commit hook actif (detect-secrets ou trufflehog)
- Production : Vault ou cloud secrets manager
- Rotation des secrets documentée et automatisée
- Séparation server-only vs public values
- Audit log pour accès aux secrets
- Pas de secrets dans les logs applicatifs
- Pas de secrets dans les images Docker (multi-stage build, args sans persist)
Anti-patterns associés
- [[KNOW-ANT-002]] — Clés d'accès hardcodées
- [[KNOW-ANT-007]] — Secrets hardcodés dans .env
- [[KNOW-ANT-010]] — Secrets JWT par défaut
Références
- [[KNOW-REF-044]] — OWASP Proactive Controls C8 (Protect Data)
- [[KNOW-REF-046]] — NIST SSDF PS (Protect the Software)
- [[KNOW-REF-048]] — DevSecOps Guideline (secret scanning)
- [[KNOW-PAT-220]] — Secure SDLC Checklist
- [[KNOW-PAT-222]] — DevSecOps Pipeline Setup
- [[KNOW-PAT-224]] — Secure Auth Implementation