Aller au contenu

PD-40 — Retour d'expérience (REX)

User Story : PD-40 — Rotation de clés HSM et re-signature probatoire Epic : PD-189 — CRYPTO Date du REX : 2026-01-05 Verdict d'acceptabilité : ✅ ACCEPTÉ


1. Résumé exécutif

Objectif initial : Implémenter une procédure de rotation de clés Ed25519 gérées par HSM, avec re-signature additive append-only, promotion atomique des signatures CANDIDATE→ACTIVE, et journalisation d'audit immuable (WORM).

Résultat obtenu : Le périmètre PD-40 est intégralement implémenté. L'architecture finale comprend 6 services (RotationOrchestratorService, HsmKeyManagerService, EventSelectorService, ResigningService, PromotionService, RotationAuditLoggerService), 3 repositories et 3 entités. Les 10 invariants (INV-1 à INV-10) et 7 critères d'acceptation (CA1 à CA7) sont couverts par des tests automatisés.

État des tests contractuels : - Suites Jest/Vitest : 144 suites, 2551 tests, 100% PASS - Tests contractuels additionnels : 92 tests (canonicalization, error-scenarios, performance, robustness), 100% PASS - Couverture branches : ~80%

Écarts identifiés et résolus : - E-01 (MAJEUR) : Tests TC-CANON-* manquants → RÉSOLU - E-02 (MAJEUR) : Tests TC-ERR-* manquants → RÉSOLU - E-03 (MINEUR) : Test TC-PERF-LOAD manquant → RÉSOLU - E-04 (MINEUR) : Tests TC-ROBUST-* manquants → RÉSOLU


2. Points fluides

2.1 Spécification claire et complète

La spécification PD-40 était exhaustive et non ambiguë : - Définition précise de l'ensemble E (§5) avec critères déterministes - Modèle de données explicite (EventToSign, SignatureEntry) - Invariants numérotés et testables (INV-1 à INV-10) - Critères d'acceptation formulés de manière vérifiable (CA1 à CA7)

2.2 Modèle append-only bien anticipé

Le choix du modèle append-only avec promotion d'état (CANDIDATE→ACTIVE) a simplifié la gestion des échecs : - Pas de suppression de données en cas d'échec - Rollback = absence de promotion (pas de transaction complexe) - Signatures orphelines ignorées par vérification (filtre state=ACTIVE)

2.3 Tests contractuels pré-définis

Le document PD-40-tests.md fournissait une matrice complète TC-* facilitant l'implémentation : - Chaque test avait des préconditions et résultats attendus explicites - La couverture minimale était définie (≥90%) - Les criticités étaient classifiées (BLOQUANTE, HAUTE, MOYENNE, BASSE)

2.4 Canonicalisation RFC 8785

L'utilisation de la bibliothèque canonicalize (npm) a rendu triviale la conformité RFC 8785 : - Tri alphabétique des clés automatique - Encodage déterministe et reproductible - Intégration simple avec le flux de signature


3. Points difficiles

3.1 Tests d'intégration avec base de données

L'exécution des tests nécessitant une infrastructure PostgreSQL a posé des difficultés : - Configuration setupTestDatabase / cleanupTestDatabase complexe - Conflits de lock entre tests parallèles - Temps d'exécution accru par les migrations

3.2 Tests TC-ERR-* initialement absents

Lors de la revue d'acceptabilité, les tests de scénarios d'erreur (TC-ERR-*) étaient absents bien que la matrice PD-40-tests.md les marquait comme PASS. La matrice était aspirationnelle et non factuelle à ce stade.

3.3 Tests de performance à 100k événements

Le test TC-PERF-LOAD-FULL (100 000 événements) est intrinsèquement long (~83 minutes théoriques avec HSM) et incompatible avec l'exécution CI standard. Solution : tests unitaires de calculs de performance + test complet marqué it.skip().

3.4 Simulation des erreurs HSM

La simulation des timeouts et erreurs HSM pour les tests TC-ERR-HSM-UNREACHABLE a nécessité des mocks spécifiques : - Mock avec compteur pour échec après N signatures - Mock avec délai configurable pour timeout


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

4.1 Matrice de tests aspirationnelle vs factuelle

La matrice de couverture (§9 de PD-40-tests.md) indiquait des statuts PASS avant implémentation effective des tests. Ce format peut induire en erreur lors de la revue d'acceptabilité.

Recommandation : Distinguer clairement "à implémenter" vs "implémenté et passant".

4.2 Tests purs vs tests d'intégration

Certains tests contractuels (TC-ROBUST-*, TC-PERF-LOAD) ont été initialement conçus comme tests d'intégration avec base de données. La conversion en tests unitaires purs a été nécessaire pour l'exécution CI.

Recommandation : Spécifier explicitement le type de test (unit/integration) dans PD-XX-tests.md.


5. Invariants complexes

5.1 INV-3 : Unicité stricte de la clé active

Référence : Spec §7, TC-INV-03

Complexité : Garantir qu'à tout instant, exactement une clé a status=ACTIVE nécessite : - Contrainte UNIQUE INDEX sur (status) WHERE status='ACTIVE' - Transaction atomique lors de la promotion (UPDATE new → ACTIVE, UPDATE old → ARCHIVED)

Risque de régression : Toute modification du flux de promotion peut violer INV-3.

5.2 INV-8 : Atomicité par promotion d'état

Référence : Spec §7, TC-INV-08

Complexité : La promotion doit être tout-ou-rien : - Toutes les signatures CANDIDATE d'un rotation_id promues ensemble - Changement de statut des clés dans la même transaction

Mécanisme : Transaction PostgreSQL SERIALIZABLE englobant les 3 UPDATE (signatures, nouvelle clé, ancienne clé).

5.3 INV-10 : Journalisation WORM

Référence : Spec §10.3, TC-INV-10

Complexité : Garantir l'immutabilité des logs d'audit : - Trigger PostgreSQL BEFORE UPDATE OR DELETE levant exception - Aucune API d'update/delete exposée

Risque : Un DBA avec accès superuser peut désactiver le trigger.


6. Dette technique

6.1 Tests de performance en mode SKIP

Le test TC-PERF-LOAD-FULL avec 100 000 événements est marqué it.skip() en raison de sa durée (~2h). L'exécution complète nécessite un environnement dédié.

Impact : Pas de validation automatisée du temps de traitement réel avec HSM.

6.2 Tests unitaires vs intégration HSM réel

Les tests HSM utilisent des mocks. Aucun test d'intégration avec un HSM réel (AWS CloudHSM, Azure Managed HSM, Thales Luna) n'est automatisé.

Impact : La conformité PKCS#11/KMIP n'est pas validée en CI.

6.3 Export audit JSON_CANONICAL non testé bout-en-bout

L'export en format RFC 8785 est testé unitairement, mais pas en scénario complet (export → archivage externe → ré-import).


7. Risques résiduels

7.1 Performance HSM réelle

Les estimations de performance (100k × 50ms ≈ 83 min) dépendent du débit HSM réel. Un HSM sous-dimensionné peut dépasser le budget temps de 2h.

Mitigation : Monitoring rotation_duration_seconds, alertes si > 2h.

7.2 Signatures CANDIDATE orphelines

En cas d'échec après re-signature mais avant promotion, des signatures CANDIDATE persistent. Le cleanup automatique (après 7 jours) n'est pas testé en production.

Mitigation : Job de cleanup planifié, monitoring candidate_signatures_orphaned_total.

7.3 Concurrence de rotations

La protection contre rotations simultanées repose sur la vérification d'état en base. Un lock distribué (Redis) offrirait une garantie plus forte.

Impact : Faible en pratique (rotations rares, ~1/an).


8. Améliorations de processus

8.1 Matrice de tests avec statut factuel

Problème : La matrice §9 de PD-40-tests.md contenait des statuts PASS avant implémentation.

Proposition : Utiliser un statut explicite À IMPLÉMENTER / IMPLÉMENTÉ / PASS avec date de dernière vérification.

8.2 Séparation tests unitaires / intégration dans PD-XX-tests.md

Problème : Certains tests contractuels nécessitent une infrastructure lourde.

Proposition : Ajouter une colonne "Type" (UNIT / INTEGRATION / E2E) dans la matrice, avec exigences d'exécution.

8.3 Revue d'acceptabilité systématique des preuves d'exécution

Problème : Les écarts E-01 à E-04 ont été détectés tardivement lors de la revue d'acceptabilité.

Proposition : Inclure un "spot check" des tests contractuels en cours d'implémentation (CI gate sur TC-* critiques).

8.4 Template REX plus tôt dans le cycle

Proposition : Créer le fichier PD-XX-rex.md dès le début de l'implémentation pour noter les difficultés au fil de l'eau.


9. Enseignements clés

9.1 Le modèle append-only simplifie la gestion d'erreurs

La décision architecturale d'utiliser des états de signature (CANDIDATE/ACTIVE) plutôt que des suppressions a rendu le code de rollback trivial : il n'y a pas de rollback, juste une absence de promotion.

9.2 Les invariants numérotés facilitent la traçabilité

Chaque INV-* a un test TC-INV-* correspondant. Cette correspondance 1:1 rend la revue d'acceptabilité mécanique et réduit le risque d'oubli.

9.3 Les tests purs sont préférables pour CI

Convertir les tests d'intégration (avec DB) en tests unitaires purs a accéléré l'exécution CI de ~10x et éliminé les problèmes de concurrence.

9.4 La canonicalisation RFC 8785 est essentielle pour les signatures probatoires

Sans canonicalisation déterministe, le hash du payload varie selon l'ordre des clés JSON, rendant les signatures non reproductibles. L'utilisation de canonicalize doit être systématique.

9.5 La documentation aspirationnelle doit être distinguée de la documentation factuelle

Marquer des tests comme PASS avant leur implémentation crée une fausse impression de complétude. Les statuts doivent refléter l'état réel vérifié.


Fin du REX PD-40