Suppression de tous les exemples de code pour garder uniquement les descriptions techniques : ADR-023 (Architecture Modération) : - Diagramme Mermaid → description flux textuelle - Exemples SQL/Redis → description workflow - Interface Go → description abstraction - Dépendances → liste concise ADR-024 (Monitoring et Observabilité) : - Diagramme Mermaid → architecture textuelle - Exemples PromQL → description métriques - Config YAML alertes → liste alertes avec seuils - Commandes bash WAL-E → description backup - Runbooks → étapes sans commandes ADR-025 (Sécurité et Secrets) : - Diagramme Mermaid → flux secrets textuel - Commandes bash Vault → description process - Code Go encryption → architecture encryption - Schéma SQL → contraintes textuelles - Config Nginx → configuration TLS - Code Go rate limiting → paramètres middleware ADR restent 100% techniques et complets sans code concret. Cohérence avec ADR-022 (même approche). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
10 KiB
10 KiB
ADR-025 : Sécurité - Secrets Management et Encryption
Statut : Accepté Date : 2026-02-01
Contexte
RoadWave manipule des données sensibles nécessitant une protection renforcée :
- Secrets applicatifs : JWT signing key, DB credentials, Mangopay API keys
- PII utilisateurs : Positions GPS précises, emails, données bancaires (via Mangopay)
- Conformité : RGPD (minimisation données, encryption at rest), PCI-DSS (paiements)
- Souveraineté : Self-hosted requis (ADR-015)
Contrainte : OWASP Top 10 mitigation obligatoire pour sécurité applicative.
Décision
Stratégie secrets management + encryption at rest + HTTPS avec stack self-hosted.
Stack Sécurité
| Composant | Technologie | Licence | Justification |
|---|---|---|---|
| Secrets management | HashiCorp Vault (open source) | MPL-2.0 | Standard industrie, rotation auto, audit logs |
| Encryption PII | AES-256-GCM (crypto/aes Go) | BSD-3 | NIST approuvé, AEAD (authenticated) |
| HTTPS/TLS | Let's Encrypt (Certbot) | ISC | Gratuit, renouvellement auto, wildcard support |
| CORS/CSRF | Fiber middleware | MIT | Protection XSS/CSRF intégrée |
| Rate limiting | Redis + Token Bucket (Fiber) | MIT/Apache | Protection brute-force, DDoS |
| SQL injection | sqlc (prepared statements) | MIT | Parameterized queries (ADR-011) |
Architecture Secrets
Environnements :
- Développement : Fichier .env local (non versionné)
- Production : HashiCorp Vault (self-hosted)
Flux :
- Vault stocke secrets sensibles (JWT signing key, DB credentials, Mangopay API key, encryption master key)
- Backend API récupère secrets depuis Vault au démarrage
- Encryption layer : AES-256-GCM pour PII, TLS 1.3 pour transport
- Stockage : PostgreSQL (data encrypted at rest), Redis (TLS enabled)
Secrets Management avec Vault
Initialisation Vault (one-time setup) :
- Init Vault : génération 5 unseal keys + root token (Shamir secret sharing)
- Unseal : 3 clés parmi 5 requises pour déverrouiller Vault
- Login root + activation KV-v2 engine (path :
roadwave/)
Secrets stockés :
- JWT signing key : Paire RS256 privée/publique
- Database credentials : Host, port, user, password (généré aléatoire 32 caractères)
- Mangopay API : Client ID, API key, webhook secret
Récupération depuis Backend Go :
- Utilisation SDK
hashicorp/vault/api - Authentification via token Vault (variable env VAULT_TOKEN)
- Récupération secrets via KVv2 engine
Encryption PII (Field-level)
Données chiffrées (AES-256-GCM) :
- GPS précis : lat/lon conservés 24h puis réduits à geohash-5 (~5km²) (Règle 02)
- Email : chiffré en base, déchiffré uniquement à l'envoi
- Numéro téléphone : si ajouté (Phase 2)
Architecture encryption :
- Utilisation bibliothèque standard Go
crypto/aesavec mode GCM (AEAD) - Master key 256 bits (32 bytes) récupérée depuis Vault
- Chiffrement : génération nonce aléatoire + seal GCM → encodage base64
- Stockage : colonne
email_encrypteden base PostgreSQL
Contraintes :
- Index direct sur champ chiffré impossible
- Solution : index sur hash SHA-256 de l'email chiffré pour recherche
HTTPS/TLS Configuration
Let's Encrypt wildcard certificate :
- Méthode : Certbot avec DNS-01 challenge (API OVH)
- Domaines couverts :
roadwave.fr+*.roadwave.fr(wildcard) - Renouvellement : automatique via cron quotidien (30j avant expiration)
Nginx TLS configuration :
- Protocol : TLS 1.3 uniquement (pas de TLS 1.2 ou inférieur)
- Ciphers : TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384
- HSTS : max-age 1 an, includeSubDomains
- Security headers : X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin
Alternatives considérées
Secrets Management
| Option | Coût | Hébergement | Rotation auto | Audit | Verdict |
|---|---|---|---|---|---|
| Vault (OSS) | 0€ | Self-hosted | ✅ Oui | ✅ Oui | ✅ Choisi |
| Vault Enterprise | 150$/mois | Self-hosted | ✅ Oui | ✅ Oui | ❌ Overkill MVP |
| Kubernetes Secrets | 0€ | K8s only | ❌ Non | ⚠️ Limité | ⚠️ Phase 2 (K8s) |
| Variables env (.env) | 0€ | VM/container | ❌ Non | ❌ Non | ❌ Insécure prod |
| AWS Secrets Manager | 0.40$/secret/mois | Cloud AWS | ✅ Oui | ✅ Oui | ❌ Souveraineté |
Encryption Library
| Option | Performance | AEAD | FIPS 140-2 | Verdict |
|---|---|---|---|---|
| crypto/aes (Go std) | ⭐⭐⭐ Rapide | ✅ GCM | ✅ Approuvé | ✅ Choisi |
| age (filippo.io/age) | ⭐⭐ Moyen | ✅ ChaCha20 | ❌ Non | ⚠️ Moins standard |
| NaCl/libsodium | ⭐⭐⭐ Rapide | ✅ Poly1305 | ❌ Non | ⚠️ CGO dependency |
TLS Certificate
| Option | Coût | Renouvellement | Wildcard | Verdict |
|---|---|---|---|---|
| Let's Encrypt | 0€ | Auto (90j) | ✅ Oui (DNS-01) | ✅ Choisi |
| OVH SSL | 5€/an | Manuel | ✅ Oui | ❌ Coût inutile |
| Cloudflare SSL | 0€ | Auto | ✅ Oui | ⚠️ Proxy Cloudflare |
Justification
HashiCorp Vault
- Standard industrie : utilisé par 80% Fortune 500
- Rotation automatique : credentials DB renouvelés toutes les 90j
- Audit logs : qui a accédé à quel secret, quand
- Unseal ceremony : sécurité maximale (3/5 clés requises)
- Coût 0€ : version open source MPL-2.0
AES-256-GCM
- NIST approuvé : standard gouvernement US (FIPS 140-2)
- AEAD : Authenticated Encryption with Associated Data (pas de tampering)
- Performance : hardware acceleration (AES-NI CPU)
- Bibliothèque std Go : pas de dépendance externe
Let's Encrypt
- Gratuit : économie 50-200€/an vs certificat commercial
- Automatique : Certbot renouvelle 30j avant expiration
- Wildcard : 1 certificat pour *.roadwave.fr (tous sous-domaines)
- Adopté massivement : 300M+ sites web
Conséquences
Positives
- ✅ Conformité RGPD : encryption at rest PII, minimisation données
- ✅ PCI-DSS : secrets paiement isolés (Mangopay API key dans Vault)
- ✅ OWASP Top 10 : SQL injection (sqlc), XSS/CSRF (Fiber), rate limiting
- ✅ Coût 0€ : stack complète open source
- ✅ Audit trail : logs Vault tracent tous accès secrets
Négatives
- ⚠️ Vault unseal : nécessite 3/5 clés au redémarrage serveur (procédure manuelle)
- ⚠️ Performance encryption : +0.5-2ms latency par champ chiffré (acceptable)
- ❌ Complexité opérationnelle : Vault à maintenir (backups, upgrades)
- ❌ Recherche email impossible : chiffrement empêche
WHERE email = 'x'(utiliser hash)
OWASP Top 10 Mitigation
| Vulnérabilité | Mitigation RoadWave | Implémentation |
|---|---|---|
| A01: Broken Access Control | JWT scopes + RBAC | Zitadel roles (ADR-008) |
| A02: Cryptographic Failures | AES-256-GCM + TLS 1.3 | crypto/aes + Let's Encrypt |
| A03: Injection | Prepared statements (sqlc) | ADR-011 |
| A04: Insecure Design | Threat modeling + ADR reviews | Process architecture |
| A05: Security Misconfiguration | Vault secrets + hardened config | ADR-025 |
| A06: Vulnerable Components | Dependabot + go mod tidy | GitHub Actions |
| A07: Auth Failures | Zitadel + rate limiting | ADR-008 + Fiber middleware |
| A08: Software Integrity | Code signing + SBOM | Phase 2 |
| A09: Logging Failures | Loki centralisé + audit Vault | ADR-024 |
| A10: SSRF | Whitelist URLs + network policies | Fiber middleware |
Rate Limiting (Protection DDoS/Brute-force)
Configuration :
- Middleware Fiber
limiteravec backend Redis - Limite : 100 requêtes par minute par IP (global)
- Clé de limitation : adresse IP client
- Réponse limitation : HTTP 429 "Too many requests"
Rate limits par endpoint :
/auth/login: 5 req/min/IP (protection brute-force)/moderation/report: 10 req/24h/user (anti-spam)- API générale : 100 req/min/IP
Rotation des Secrets
Politique de rotation :
| Secret | Rotation | Justification |
|---|---|---|
| JWT signing key | 1 an | Compromission = invalidation tous tokens |
| DB credentials | 90 jours | Best practice NIST |
| Mangopay API key | À la demande | Rotation manuelle si compromission |
| Encryption master key | Jamais (re-encryption massive) | Backup sécurisé uniquement |
Process rotation DB credentials :
- Vault génère automatiquement nouveau password
- Vault met à jour PostgreSQL avec nouveau password
- Application récupère nouveau password au prochain accès Vault
- Ancien password invalide après grace period de 1h
Métriques de Succès
- 0 fuite secrets en production (audit logs Vault)
- 100% traffic HTTPS (HTTP → HTTPS redirect)
- Rate limiting < 0.1% false positives
- Encryption overhead < 2ms p95
Migration et Rollout
Phase 1 (MVP - Sprint 2-3)
- Deploy Vault (Docker single-node)
- Migrer secrets .env → Vault
- Encryption emails (AES-256-GCM)
- HTTPS Let's Encrypt (api.roadwave.fr)
- Rate limiting Fiber (100 req/min global)
Phase 2 (Post-MVP - Sprint 6-8)
- Vault HA (3 nodes Raft)
- Rotation automatique credentials
- Field-level encryption GPS (après 24h)
- WAF (Web Application Firewall) : ModSecurity
- Penetration testing externe (Bug Bounty)
Références
- ADR-008 : Authentification (Zitadel, JWT)
- ADR-011 : Accès données (sqlc, prepared statements)
- ADR-015 : Hébergement (OVH France, souveraineté)
- ADR-024 : Monitoring (Audit logs)
- Règle 02 : Conformité RGPD
- HashiCorp Vault Documentation
- OWASP Top 10 2021
- NIST SP 800-175B (Cryptography)