Aller au contenu

PD-8 — Retour d'expérience


📚 Navigation User Story | Document | | | ---------- | -- | | 📋 [Spécification](PD-8-specification.md) | | | 🛠️ [Plan d'implémentation](PD-8-plan.md) | | | ✅ [Critères d'acceptation](PD-8-acceptability.md) | | | 📝 **Retour d'expérience** | *(ce document)* | [← Retour à infrastructure-souveraine](../PD-193-epic.md) · [↑ Index User Story](index.md)

1. Résumé exécutif

La User Story PD-8 visait à configurer HashiCorp Vault sur OVH pour la gestion centralisée des secrets (credentials PostgreSQL, OVH, AWS, tokens API, CI/CD). L'implémentation fournit un rôle Ansible complet avec installation Vault, backend PostgreSQL TLS, secrets engines (KV v2 + Database), AppRoles avec TTL courts, policies least-privilege et audit logging fichier. Cependant, 2 écarts MAJEURS sont identifiés : audit syslog désactivé (spec §7.7) et certificat autosigné avec proxy_ssl_verify off (spec §7.1), ainsi que 3 écarts MINEURS : policy worker avec bootstrap api-backend, chemin database/ au lieu de db/, et backup pg_dump local sans upload S3. Verdict : ACCEPTÉ AVEC RÉSERVES.


2. Points fluides

  • Vault installé : version 1.15.4 via playbook Ansible avec service systemd
  • Backend PostgreSQL : vault_storage avec connexion TLS (sslmode=require)
  • TLS 1.3 : listener Vault configuré avec tls_min_version = "tls13"
  • KV v2 activé : secrets engine à /kv avec versioning (max 10 versions)
  • Database secrets engine : credentials dynamiques PostgreSQL (TTL 1h, Max TTL 24h)
  • AppRoles créés : api-backend (30m/2h), worker (20m/1h), ci (5m/10m)
  • SecretIDs single-use : secret_id_num_uses: 1 pour AC4 compliance
  • Policies least-privilege : api-backend, worker, ci, vault-observer
  • Audit fichier : /var/log/vault/audit.log avec logrotate 90 jours
  • HMAC accessor : masquage des accessors dans les logs d'audit
  • Nginx reverse proxy : Let's Encrypt avec TLS 1.2/1.3 + HSTS
  • Health check script : /opt/vault/scripts/vault-health-check.sh
  • Backup automatisé : pg_dump quotidien avec rétention 30 jours
  • Shamir 5/3 : initialisation avec distribution multi-opérateurs
  • mlock activé : disable_mlock = false pour sécurité mémoire
  • Prometheus telemetry : métriques exposées pour monitoring
  • Réseau restreint : accès limité à localhost + VPN (10.10.10.0/24)
  • Variables chiffrées : credentials dans vault.yml (ansible-vault)

3. Points difficiles

Difficulté Contexte
Certificat autosigné Vault Spec demande "certificat valide", implémentation génère cert autosigné avec nginx proxy_ssl_verify off
Audit syslog désactivé Spec demande fichier + syslog, code a vault_audit_syslog_enabled: false
Chemin database engine Spec attend db/pv-postgres, code monte sur database/ avec config pv-postgres
Bootstrap cross-role Policy worker autorise génération SecretID api-backend (pattern Prefect)
Backup S3 Plan prévoit snapshots S3 chiffrés + tests, implémentation = pg_dump local
Auto-unseal Plan prévoit AWS KMS, non activé dans config dev (Shamir manuel)

4. Hypothèses révélées tardivement

Hypothèse initiale Réalité découverte
Raft storage backend FAUX — PostgreSQL choisi pour consistance avec stack existante
AWS KMS auto-unseal en dev FAUX — Shamir 5/3 manuel, KMS optionnel via vault_seal_type
Certificat CA pour Vault FAUX — Autosigné, Nginx vérifie via Let's Encrypt côté client
Secrets engines isolés PARTIELLEMENT — Worker peut bootstrap api-backend SecretIDs
Backup Raft snapshots FAUX — pg_dump sur PostgreSQL backend

5. Invariants complexes à implémenter

Invariant Complexité
AppRole TTL courts SecretID 2-5min single-use nécessite orchestration Prefect pour bootstrap
Bootstrap cross-role Worker génère SecretIDs pour api-backend avant démarrage backend
PostgreSQL backend HA ha_enabled disponible mais non activé en mono-instance
Audit obligatoire Vault refuse de démarrer si audit device échoue
TLS end-to-end Nginx TLS + Vault TLS avec validation désactivée entre les deux
Policies read-only Principe appliqué mais worker a create pour SecretIDs

6. Dette technique

Dette Impact Priorité
Certificat autosigné + proxy_ssl_verify off Pas de validation TLS Nginx→Vault, risque MITM interne HAUTE
Audit syslog absent Centralisation logs limitée, SIEM non alimenté MOYENNE
Chemin database divergent Documentation/consommateurs à aligner sur database/ vs db/ BASSE
Backup sans upload S3 Résilience limitée au disque local MOYENNE
Test restauration absent Procédure de recovery non validée automatiquement MOYENNE
Root token révocation Rappelé mais non automatisé post-configuration BASSE

7. Risques résiduels

Risque Probabilité Impact Mitigation suggérée
Perte clés unseal Faible CRITIQUE Distribution 5 opérateurs, coffre physique
MITM Nginx→Vault Faible MOYEN Remplacer par cert PKI interne ou mutual TLS
Fuite SecretID CI Faible ÉLEVÉ TTL 2min + single-use, network isolation
Backup corrompu Moyenne ÉLEVÉ Ajouter vérification intégrité + test restore
Policy trop permissive Faible MOYEN Audit régulier des accès via audit log
Secrets engine désynchronisé Faible MOYEN Monitoring connexion database engine

8. Améliorations processus

Amélioration Bénéfice attendu
Activer audit syslog Centralisation logs pour SIEM/alerting
PKI interne pour Vault TLS Validation certificat Nginx→Vault (mutual TLS)
Aligner chemin database db/ au lieu de database/ ou MAJ documentation
Upload backup S3 chiffré Résilience offsite avec versioning
Test restauration automatisé Validation mensuelle de la procédure de recovery
Rotation root token Générer token limité post-setup, révoquer root
Monitoring AppRole usage Alertes sur échecs d'authentification

9. Enseignements clés

  1. PostgreSQL backend vs Raft — Le choix PostgreSQL plutôt que Raft (embedded) simplifie les backups (pg_dump standard) et s'intègre à la stack existante, au prix d'une dépendance externe. Pour un setup mono-instance, c'est un compromis acceptable.

  2. TLS end-to-end nécessite attention — La combinaison Nginx Let's Encrypt (externe) + Vault autosigné (interne) avec proxy_ssl_verify off crée une zone de confiance implicite. Un cert PKI interne ou mutual TLS améliorerait la posture de sécurité.

  3. Bootstrap AppRole cross-role est un pattern accepté — Permettre au worker de générer des SecretIDs pour api-backend (pattern Prefect) évite les credentials statiques au démarrage. Ce trade-off est documenté et limité au périmètre bootstrap.

  4. Audit syslog = centralisation obligatoire pour conformité — L'audit fichier seul ne suffit pas pour une architecture avec SIEM. L'activation syslog permettrait l'agrégation et l'alerting temps réel sur les accès sensibles.

  5. Les backups Vault nécessitent tests de restoration — Un pg_dump quotidien sans test de restore automatisé est insuffisant pour garantir le RTO. Un job périodique de validation (restore sur instance test) sécuriserait la continuité.