Gestion des secrets
Statut : draft. Cette page documente comment Nex stocke, distribue, fait tourner et audite les secrets de la plateforme. Décision architecturale : ADR-0008.
1. Principes
- Aucun secret en clair dans Git, dans les images Docker, ni dans les fichiers de config K8s versionnés.
- Source de vérité unique : Doppler (projet
paywithnex, configsdev,stg,prd). - Distribution automatisée vers les environnements via External Secrets Operator (K8s) et
dopplerCLI (CI, local). - Accès tracé via les logs Doppler natifs.
- Rotation planifiée pour les secrets critiques.
2. Architecture
3. Inventaire des secrets
| Catégorie | Exemples |
|---|---|
| Base de données | POSTGRES_PASSWORD_<service>, host RDS, ports |
| Cache | REDIS_PASSWORD, host Redis |
| Auth | JWT secret, Firebase service account (JSON), clés signing internal-service-jwt |
| Providers Mobile Money | API keys, client_id, client_secret, IP allowlist webhooks |
| Apentis (KYC) | API key, endpoints |
| Cloudflare | DNS / WAF tokens (gestion via REST API) |
| Notifications | SMS provider API key, Firebase Messaging server key, email provider (Brevo, SendGrid…) |
| File service | Firebase service account (storage), bucket credentials |
| Monitoring | Grafana Cloud API key, push key |
| CI / Deploy | Wrangler Pages token (Cloudflare), GitLab Deploy Tokens, registry creds |
Liste complète à maintenir dans Doppler (les noms de variables sont la source de vérité).
4. Politique d'accès Doppler
| Rôle Doppler | Personnes | Configs accessibles |
|---|---|---|
| Admin | [À CONFIRMER : 2 personnes max — RSSI + CTO] | dev, stg, prd |
| Developer | équipe plateforme | dev, stg |
| Read-only prd | tech-ops on-call | prd (lecture seule pour debug) |
| CI | service token GitLab CI | dev, stg, prd (selon le job) |
- MFA obligatoire pour tous les utilisateurs humains Doppler.
- Service tokens CI : scopés à une config et un service spécifique.
- Aucun accès Doppler ne doit être partagé entre humains (un compte = une personne).
5. Rotation des secrets
| Type de secret | Fréquence cible | Procédure | État actuel |
|---|---|---|---|
| Mots de passe DB PostgreSQL | 90 j | Rotation via Doppler + restart pods | [À DOCUMENTER procédure complète] |
| API keys providers Mobile Money | Selon le provider (≤ 12 mois) | Rotation hors-bande + Doppler update | [À DOCUMENTER] |
| JWT signing secret | 180 j | Dual-key rollover (acceptance des 2 clés pendant la transition) | [À CONCEVOIR] |
| Firebase service accounts | 12 mois | Rotation Firebase + Doppler update | [À CONFIRMER] |
| Tokens CI (GitLab, Cloudflare) | 12 mois | Régénération + update Doppler | [À CONFIRMER] |
| Mots de passe utilisateurs humains | Selon politique entreprise | Outil de gestion mot de passe | [À CONFIRMER] |
| Secrets compromis (incident) | Immédiat | Procédure d'urgence (cf. IRP) | OK runbook IRP |
6. Provisioning d'un nouveau secret
- Identifier le nom canonique (
UPPER_SNAKE_CASE). - Décider de la scope :
- Variable d'environnement de service → Doppler
<service>(ex :auth,ledger-wallets). - Cross-service / global → Doppler
_global.
- Variable d'environnement de service → Doppler
- Créer dans Doppler
devd'abord, propager versstg, puisprdaprès validation. - Mettre à jour
.env.example(sans la valeur, juste le nom + commentaire) si pertinent. - Référencer dans le service via
process.env.MY_SECRET. - Vérifier que External Secrets Operator a bien synchronisé (
kubectl get externalsecret -n nex-staging).
7. Bonnes pratiques côté code
- Ne jamais logguer un secret. Les loggers doivent appliquer un masquage automatique des champs sensibles (
Authorization,password,pin,secret,token). - Ne jamais commit une valeur de secret, même dans un test. Utiliser des fixtures de test génériques.
- Pas de secret dans une image Docker : toujours via env var injectée au runtime par le runtime cloud (K8s secret, ECS task definition…).
- Pas de secret dans une URL : utiliser des headers, JSON body, ou form data.
- Pas de secret dans les query params de logs (ils fuitent via Grafana / Loki). À masquer.
8. Bonnes pratiques côté ops
- Audit Doppler trimestriel : revue de la liste des utilisateurs et leurs scopes, retrait des accès dormants.
- Liste des secrets critiques maintenue à jour avec leur owner et leur date de dernière rotation.
- Détection de fuites : intégrer
gitleaksou équivalent en pre-commit + CI.
9. Procédure d'urgence (secret compromis)
- Identifier : quel secret, comment compromis.
- Révoquer côté provider (régénérer une nouvelle valeur côté source).
- Mettre à jour dans Doppler (
prden premier). - Forcer la synchronisation External Secrets :
kubectl annotate externalsecret <name> -n <ns> force-sync=$(date +%s) --overwrite. - Restart les pods consommateurs si nécessaire (
kubectl rollout restart deployment/<service>). - Vérifier : tester un appel via le nouveau secret.
- Documenter dans le RCA IRP (cf. /operations/incident-response).
- Lessons learned : pourquoi le secret a-t-il fui ? Quelle défense renforcer ?
10. Conformité
- PCI-DSS (si scope card) : exige une gestion des clés sécurisée (Req 3.5, 3.6) → Doppler + ESO satisfont.
- ISO 27001 Annex A.8.24 : gestion de la cryptographie → encryption Doppler + rotation documentée requise.
- SOC 2 CC6 : restriction accès → RBAC Doppler.
11. Gaps connus
- Procédures de rotation non encore formalisées pour la plupart des secrets — à compléter dans la table §5.
- Pas de détection automatique de fuites de secrets dans Git (gitleaks non intégré en CI).
- MFA Doppler : à confirmer pour tous les comptes.
- JWT signing key rollover : pas de support dual-key actuel.
Cf. /security/known-gaps.