Gestion des secrets
Bonnes pratiques pour stocker, rotationner et protéger les secrets (clés API, mots de passe, tokens) dans un projet de développement.
Principes fondamentaux
Ne jamais commiter de secret dans un dépôt Git. Un secret dans Git reste dans l’historique même après suppression du fichier.
Règle d’or : un secret ne doit exister que dans trois endroits :
- La machine du développeur (variable d’environnement ou gestionnaire de secrets local)
- Le serveur de production (variables d’environnement du déploiement)
- Un gestionnaire de secrets dédié (Vault, AWS Secrets Manager, etc.)
Fichiers .env
Structure recommandée
# .env (jamais commité !)
DATABASE_URL=postgresql://user:***@localhost:5432/app
JWT_SECRET=a1b2c3d4e5f6...
API_KEY_SK=sk_liv...xxxx
# .env.example (commité — modèle sans valeurs réelles)
DATABASE_URL=postgresql://user:***@localhost:5432/app
JWT_SECRET=<votre_secret_jwt>
API_KEY_SK=<votre_clé_api>.gitignore
# Secrets — jamais commités
.env
.env.local
.env.production
*.key
*.pem
secrets/Validation d’un fichier .env
# Vérifier que les variables requises sont définies (script shell)
required_vars=("DATABASE_URL" "JWT_SECRET" "API_KEY_SK")
for var in "${required_vars[@]}"; do
if [ -z "${!var}" ]; then
echo "ERREUR: $var n'est pas défini"
exit 1
fi
done
echo "Toutes les variables sont présentes."Rotation des secrets
Stratégie de rotation
- Définir une politique de rotation : 90 jours pour les mots de passe, 180 jours pour les clés API
- Générer le nouveau secret (voir CLI Security)
- Déployer le nouveau secret avec la possibilité de cohabiter l’ancien et le nouveau pendant une fenêtre de bascule
- Révoquer l’ancien secret après la fenêtre de cohabitation
Rotation automatisée (exemple cron)
# Cron quotidien — génère un nouveau JWT_SECRET et redémarre l'appli
0 3 * * * /opt/scripts/rotate-secrets.sh >> /var/log/secret-rotation.log 2>&1#!/bin/bash
# /opt/scripts/rotate-secrets.sh
NEW_SECRET=$(openssl rand -hex 32)
echo "Nouveau JWT_SECRET généré à $(date)" >> /var/log/secret-rotation.log
# Mettre à jour dans le fichier de config ou la variable d'environnement
export JWT_SECRET="$NEW_SECRET"
# Redémarrer l'application (systemd)
systemctl restart mon-appGit-secrets — Prévenir les fuites
Git-secrets scanne les commits pour détecter les patterns de secrets avant qu’ils ne soient envoyés à distance.
# Installation macOS
brew install AWS/git-secrets/git-secrets
# Installation Linux
sudo apt-get install git-secrets
# Initialiser dans le dépôt
git secrets --install
git secrets --register-aws
# Ajouter des patterns personnalisés
git secrets --add 'sk_live_[0-9a-zA-Z]+'
git secrets --add '-----BEGIN (RSA |EC )?PRIVATE KEY-----'
git secrets --add 'AWS_SECRET_ACCESS_KEY\s*=\s*["\047][0-9a-zA-Z/+=]{40}["\047]'
# Scanner l'historique existant
git secrets --scan --historyHook pre-commit
#!/bin/bash
# .git/hooks/pre-commit
git secrets --scan
if [ $? -ne 0 ]; then
echo "ERREUR : des secrets potentiels ont été détectés dans les fichiers modifiés."
echo "Annulation du commit."
exit 1
fiCI/CD — Secrets dans les pipelines
GitHub Actions
# .github/workflows/deploy.yml
name: Déploiement
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
steps:
- uses: actions/checkout@v4
- name: Déploiement
run: ./scripts/deploy.shNe jamais afficher les secrets dans les logs CI/CD. Utiliser echo "::add-mask::$SECRETS" dans GitHub Actions pour masquer automatiquement les valeurs sensibles.
Variable d’environnement masquée (GitHub Actions)
steps:
- name: Masquer les secrets dans les logs
run: |
echo "::add-mask::${{ secrets.DATABASE_URL }}"
echo "::add-mask::${{ secrets.JWT_SECRET }}"Environnements protégés
Utiliser les environnements protégés GitHub Actions pour limiter l’accès aux secrets de production :
jobs:
deploy-prod:
environment: production # Nécessite une approbation manuelle
runs-on: ubuntu-latestGestionnaires de secrets dédiés
HashiCorp Vault (aperçu)
Vault centralise les secrets avec rotation automatique, audit logging, et accès via API ou CLI.
# Installation
# Voir https://developer.hashicorp.com/vault/install
# Démarrer un serveur Vault en développement (usage local uniquement)
vault server -dev
# Authentification
export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=hvs.xxx
# Lire un secret
vault kv get secret/app-config
# Écrire un secret
vault kv put secret/app-config jwt_secret="nouveau_secret_ici" database_url="postgresql://..."
# Rotation automatique (API)
curl --request POST \
--header "X-Vault-Token: $VAULT_TOKEN" \
--data '{"type":"rotation","period":"720h"}' \
http://127.0.0.1:8200/v1/secret/data/rotate/jwt_secretAWS Secrets Manager (aperçu)
# Récupérer un secret depuis AWS
aws secretsmanager get-secret-value \
--secret-id production/JWT_SECRET \
--query SecretString --output textChecklist de sécurisation des secrets
-
.envprésent dans.gitignore -
.env.exampleprésent dans le dépôt (sans valeurs réelles) - Variables d’environnement requises validées au démarrage de l’application
- Git-secrets ou hook pre-commit installé
- Secrets dans la CI/CD via des variables protégées (pas de hardcodage)
- Secrets d’origine masqués dans les logs (
::add-mask::) - Politique de rotation définie (90 jours minimum)
- Secret existant jamais compilé dans le code binaire ou les assets