Gestion des Secrets
Guide pour la gestion des secrets et de la configuration sensible de MyTelevision API.
Vue d'ensemble
La gestion correcte des secrets est critique pour la securite. Ce guide couvre les bonnes pratiques pour le traitement des secrets dans tous les environnements.
Categories de secrets
| Categorie | Exemples | Rotation |
|---|---|---|
| Authentication | JWT secrets, API keys | Trimestrielle |
| Database | Connection strings, passwords | Trimestrielle |
| Services externes | TMDb, Firebase, Stripe | Annuelle |
| Encryption | DRM keys, storage keys | Annuelle |
| Monitoring | Alert webhooks, tokens | Annuelle |
Approches par environnement
Development
Utiliser des fichiers .env (gitignored) :
# .env (developpement local)
JWT_SECRET=dev-secret-min-32-characters-here
DATABASE_URL=postgresql://mytv:password@localhost:5432/mytv
REDIS_PASSWORD=redis-dev-password
attention
Ne jamais commiter les fichiers .env dans le controle de version.
Staging
Utiliser Docker secrets ou des variables d'environnement :
# docker-compose.staging.yml
services:
api:
environment:
- JWT_SECRET=${JWT_SECRET}
- DATABASE_URL=${DATABASE_URL}
Les secrets sont charges depuis les variables d'environnement CI/CD.
Production
Utiliser Docker secrets montes en fichiers :
# docker-compose.production.yml
services:
api:
secrets:
- jwt_secret
- db_password
- redis_password
- firebase_private_key
environment:
- JWT_SECRET_FILE=/run/secrets/jwt_secret
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
jwt_secret:
external: true
db_password:
external: true
redis_password:
external: true
firebase_private_key:
external: true
Docker Secrets
Creer des secrets
# Creer des secrets depuis des valeurs
echo "your-jwt-secret-min-32-chars" | docker secret create jwt_secret -
echo "your-database-password" | docker secret create db_password -
# Creer un secret depuis un fichier
docker secret create firebase_private_key ./firebase-key.json
# Lister les secrets
docker secret ls
Utilisation dans le code
import { readFileSync, existsSync } from 'fs';
function getSecret(name: string, envVar: string): string {
// Verifier d'abord le secret base fichier (production)
const secretPath = `/run/secrets/${name}`;
if (existsSync(secretPath)) {
return readFileSync(secretPath, 'utf8').trim();
}
// Fallback sur la variable d'environnement (developpement)
const envValue = process.env[envVar];
if (envValue) {
return envValue;
}
// Verifier le pattern suffixe _FILE
const fileEnvVar = `${envVar}_FILE`;
const filePath = process.env[fileEnvVar];
if (filePath && existsSync(filePath)) {
return readFileSync(filePath, 'utf8').trim();
}
throw new Error(`Secret ${name} not found`);
}
// Utilisation
const jwtSecret = getSecret('jwt_secret', 'JWT_SECRET');
const dbPassword = getSecret('db_password', 'DB_PASSWORD');
Kubernetes Secrets
Creer des secrets
# Depuis des valeurs litterales
kubectl create secret generic mytv-api-secrets \
--from-literal=JWT_SECRET='your-jwt-secret' \
--from-literal=DB_PASSWORD='your-db-password' \
-n mytv-production
# Depuis un fichier
kubectl create secret generic firebase-credentials \
--from-file=firebase-key.json=./firebase-service-account.json \
-n mytv-production
Utilisation dans un Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: mytv-api
spec:
template:
spec:
containers:
- name: api
envFrom:
- secretRef:
name: mytv-api-secrets
volumeMounts:
- name: firebase-creds
mountPath: /etc/secrets/firebase
readOnly: true
volumes:
- name: firebase-creds
secret:
secretName: firebase-credentials
Sealed Secrets (GitOps)
Pour stocker des secrets chiffres dans Git :
# Installer le CLI kubeseal
brew install kubeseal
# Creer un sealed secret
kubectl create secret generic mytv-secrets \
--from-literal=JWT_SECRET='secret' \
--dry-run=client -o yaml | \
kubeseal --format yaml > sealed-secrets.yaml
# Appliquer le sealed secret
kubectl apply -f sealed-secrets.yaml
Rotation des secrets
Rotation du JWT Secret
- Generer un nouveau secret
- Ajouter le nouveau secret a la configuration (garder l'ancien temporairement)
- Deployer avec les deux secrets (valider les deux pendant la transition)
- Apres la periode de grace, supprimer l'ancien secret
- Deployer avec uniquement le nouveau secret
// Support de plusieurs JWT secrets pendant la rotation
const jwtSecrets = [
process.env.JWT_SECRET,
process.env.JWT_SECRET_OLD, // Supprimer apres la rotation
].filter(Boolean);
function verifyToken(token: string): JwtPayload {
for (const secret of jwtSecrets) {
try {
return jwt.verify(token, secret) as JwtPayload;
} catch (e) {
continue;
}
}
throw new UnauthorizedException('Invalid token');
}
Rotation du mot de passe database
- Creer un nouvel utilisateur database avec un nouveau mot de passe
- Mettre a jour l'application pour utiliser les nouvelles credentials
- Deployer et verifier
- Supprimer l'ancien utilisateur database
-- PostgreSQL
CREATE USER mytv_new WITH PASSWORD 'new-password';
GRANT ALL PRIVILEGES ON DATABASE mytv TO mytv_new;
-- Apres deploiement
DROP USER mytv_old;
Inventaire des secrets
| Secret | Stockage | Rotation |
|---|---|---|
JWT_SECRET | Docker/K8s secret | Trimestrielle |
JWT_REFRESH_SECRET | Docker/K8s secret | Trimestrielle |
DATABASE_URL | Docker/K8s secret | Trimestrielle |
REDIS_PASSWORD | Docker/K8s secret | Trimestrielle |
FIREBASE_PRIVATE_KEY | Docker/K8s secret | Annuelle |
TMDB_API_KEY | Docker/K8s secret | Annuelle |
STRIPE_SECRET_KEY | Docker/K8s secret | Annuelle |
R2_SECRET_ACCESS_KEY | Docker/K8s secret | Annuelle |
SMTP_PASSWORD | Docker/K8s secret | Annuelle |
Generation de secrets
Generer des secrets forts
# Generer un secret aleatoire de 32 bytes
openssl rand -hex 32
# Generer un secret base64
openssl rand -base64 32
# Generer un UUID
uuidgen
Complexite des mots de passe
| Type | Exigences |
|---|---|
| JWT Secrets | 32+ caracteres aleatoires |
| Database | 16+ chars, majuscules/minuscules, chiffres, symboles |
| API Keys | Generes par le fournisseur |
| Redis | 16+ caracteres aleatoires |
Monitoring et audit des secrets
Logs d'acces aux secrets
Surveiller l'acces aux secrets :
# Kubernetes audit policy
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
resources:
- group: ''
resources: ['secrets']
Alertes
Configurer des alertes pour :
- Acces aux secrets depuis des sources inattendues
- Tentatives echouees de recuperation de secrets
- Rappels de rotation des secrets
- Certificats expires
Procedures d'urgence
Reponse a une compromission de secret
- Identifier - Determiner quels secrets sont compromis
- Revoquer - Faire la rotation des secrets compromis immediatement
- Deployer - Mettre a jour les applications avec les nouveaux secrets
- Investiguer - Analyser comment la compromission s'est produite
- Remedier - Corriger les vulnerabilites qui ont mene a la compromission
- Documenter - Creer un rapport d'incident
Commandes de rotation rapide
# Rotation immediate du JWT secret
NEW_SECRET=$(openssl rand -hex 32)
docker secret rm jwt_secret
echo "$NEW_SECRET" | docker secret create jwt_secret -
docker service update --secret-rm jwt_secret --secret-add jwt_secret mytv-api
# Ou pour Kubernetes
kubectl create secret generic mytv-api-secrets \
--from-literal=JWT_SECRET="$NEW_SECRET" \
--dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart deployment/mytv-api -n mytv-production
Bonnes pratiques de securite
A faire
- Utiliser la gestion de secrets (Docker secrets, K8s secrets)
- Faire la rotation des secrets regulierement
- Utiliser des secrets differents par environnement
- Chiffrer les secrets au repos
- Limiter l'acces aux secrets (principe du moindre privilege)
- Auditer l'acces aux secrets
- Utiliser des secrets forts, generes aleatoirement
A ne pas faire
- Commiter des secrets dans le controle de version
- Logger des secrets
- Passer des secrets en arguments de ligne de commande
- Partager des secrets par chat/email
- Hardcoder des secrets dans le code
- Utiliser les memes secrets entre environnements
- Utiliser des secrets faibles ou previsibles