Files
roadwave/docs/adr/025-securite-secrets.md
jpgiannetti 81ccbf79e6 refactor(adr-023/024/025): retirer exemples de code et scripts
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>
2026-02-01 17:12:07 +01:00

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 :

  1. Vault stocke secrets sensibles (JWT signing key, DB credentials, Mangopay API key, encryption master key)
  2. Backend API récupère secrets depuis Vault au démarrage
  3. Encryption layer : AES-256-GCM pour PII, TLS 1.3 pour transport
  4. Stockage : PostgreSQL (data encrypted at rest), Redis (TLS enabled)

Secrets Management avec Vault

Initialisation Vault (one-time setup) :

  1. Init Vault : génération 5 unseal keys + root token (Shamir secret sharing)
  2. Unseal : 3 clés parmi 5 requises pour déverrouiller Vault
  3. 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/aes avec 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_encrypted en 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 limiter avec 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)

  1. Deploy Vault (Docker single-node)
  2. Migrer secrets .env → Vault
  3. Encryption emails (AES-256-GCM)
  4. HTTPS Let's Encrypt (api.roadwave.fr)
  5. Rate limiting Fiber (100 req/min global)

Phase 2 (Post-MVP - Sprint 6-8)

  1. Vault HA (3 nodes Raft)
  2. Rotation automatique credentials
  3. Field-level encryption GPS (après 24h)
  4. WAF (Web Application Firewall) : ModSecurity
  5. Penetration testing externe (Bug Bounty)

Références