PD-36 — Retour d'expérience¶
Navigation User Story
| Document | | | ---------- | -- | | [Spécification](PD-36-specification.md) | | | [Plan d'implémentation](PD-36-plan.md) | | | [Critères d'acceptation](PD-36-acceptability.md) | | | **Retour d'expérience** | *(ce document)* | [Retour à crypto-proof](../PD-189-epic.md) · [Index User Story](index.md)1. Résumé exécutif¶
PD-36 implémente un client HSM Cloud PKCS#11 pour le backend NestJS de ProbatioVault, permettant les opérations cryptographiques sensibles (signature, vérification, mTLS) sans jamais exposer les clés privées hors du HSM.
Bilan quantitatif¶
| Métrique | Valeur |
|---|---|
| Fichiers créés/modifiés | 8 |
| Tests unitaires | 66 (100% pass) |
| Écarts identifiés | 4 |
| Écarts résolus | 4/4 |
| Verdict final | ACCEPTÉ |
Écarts traités¶
| ID | Niveau | Description | Résolution |
|---|---|---|---|
| E-01 | BLOQUANT | mTLS PKCS#11 signing non opérationnel | OpenSSL ENGINE API avec URI PKCS#11 RFC 7512 |
| E-02 | MAJEUR | CSR uniquement ECDSA, pas RSA | Détection automatique du type de clé, RSA-PSS SHA-384 |
| E-03 | MAJEUR | Pas de pool de sessions HSM | HsmSessionPool avec timeout et renouvellement |
| E-04 | MINEUR | Validation config HSM tardive | Fail-fast dans validateHsmConfig() |
2. Points fluides¶
2.1 Architecture modulaire NestJS¶
L'intégration avec le lifecycle NestJS (OnModuleInit/OnModuleDestroy) s'est avérée naturelle et robuste. La séparation Provider/Operations/Service facilite les tests et la maintenance.
src/modules/crypto/hsm/
├── hsm.module.ts # Module NestJS
├── hsm.service.ts # Service principal (facade)
├── hsm.config.ts # Configuration + validation
├── interfaces/
│ └── pkcs11.interface.ts # Types PKCS#11
└── providers/
└── cloudhsm-pkcs11.provider.ts # Provider + Operations
2.2 Chargement dynamique de pkcs11js¶
Le chargement dynamique (await import('pkcs11js')) évite les erreurs de compilation native en CI/test où CloudHSM n'est pas disponible.
2.3 Tests unitaires avec mocks¶
La stratégie de mock complet du provider PKCS#11 permet une couverture de 100% sans dépendance au HSM réel. Les 66 tests couvrent tous les scénarios incluant les 22 tests E-01 pour mTLS.
3. Points difficiles¶
3.1 E-01 : mTLS avec signature HSM (BLOQUANT)¶
Problème : Node.js ne permet pas de fournir une clé privée "opaque" pour TLS. L'implémentation initiale tentait d'utiliser directement le certificat sans déléguer la signature au HSM.
Solution : Utilisation de l'API OpenSSL ENGINE via tls.createSecureContext() :
const secureContextOptions: tls.SecureContextOptions = {
cert: certBuffer,
privateKeyEngine: engineName, // 'cloudhsm' ou 'pkcs11'
privateKeyIdentifier: pkcs11Uri, // pkcs11:token=cavium;object=key-label;type=private
};
Complexité : Cette API est marquée @deprecated dans Node.js (OpenSSL ENGINE API deprecated in 3.0), mais reste la seule option viable. Un commentaire NOSONAR documente cette décision.
3.2 E-02 : Support RSA dans CSR et export public key¶
Problème : L'implémentation initiale ne supportait que ECDSA pour la génération de CSR et l'export de clé publique.
Solution : Ajout de la détection automatique du type de clé (CKK_RSA vs CKK_EC) et construction du SPKI approprié :
- ECDSA : Export direct de
CKA_EC_POINT - RSA : Construction manuelle du SPKI via
buildRsaSpki(modulus, publicExponent)
3.3 Construction ASN.1/DER manuelle¶
PKCS#11 ne fournit pas de génération CSR native. L'implémentation manuelle des structures DER (SEQUENCE, SET, BIT STRING, OID encoding) a nécessité une attention particulière aux détails de la spécification X.509.
4. Hypothèses révélées tardivement¶
4.1 OpenSSL ENGINE requis côté système¶
L'utilisation de privateKeyEngine nécessite que l'engine CloudHSM soit installé et configuré côté système (/etc/cloudhsm/cloudhsm_client.cfg). Cette dépendance n'était pas explicitement documentée dans la spécification.
Impact : Documentation d'installation mise à jour, variable CLOUDHSM_OPENSSL_ENGINE ajoutée à la configuration.
4.2 CloudHSM SDK 5 vs SDK 3¶
Les templates de génération de clé diffèrent entre SDK 3 et SDK 5. Le SDK 5 dérive implicitement CKA_CLASS/CKA_KEY_TYPE du mécanisme, et ajouter ces attributs explicitement provoque CKR_ATTRIBUTE_VALUE_INVALID.
Impact : Templates simplifiés, commentaires explicatifs ajoutés.
5. Invariants complexes¶
5.1 INV-1 : Clés non-extractables¶
Les clés privées ne doivent JAMAIS quitter le HSM.
Cet invariant est garanti par CloudHSM (CKA_EXTRACTABLE=FALSE implicite). L'implémentation mTLS via OpenSSL ENGINE respecte cet invariant car la signature TLS est déléguée au HSM.
Vérification : Aucun appel à C_WrapKey ou export de clé privée dans le code.
5.2 INV-2 : Sessions HSM proprement fermées¶
Les sessions HSM doivent être fermées proprement après usage.
Garanti par :
OnModuleDestroyqui appellefinalize()HsmSessionPool.closeAll()qui ferme toutes les sessions poolées- Try/catch systématique avec logging des erreurs de fermeture
6. Dette technique¶
6.1 DT-01 : OpenSSL ENGINE API deprecated¶
| Élément | Valeur |
|---|---|
| Localisation | hsm.service.ts:buildMtlsAgent() |
| Nature | API privateKeyEngine deprecated (OpenSSL 3.0) |
| Risque | Retrait futur dans Node.js |
| Mitigation | NOSONAR documenté, veille sur évolutions Node.js |
| Action recommandée | Migrer vers OSSL_PROVIDER quand supporté par Node.js |
6.2 DT-02 : Parsing ASN.1 simplifié¶
| Élément | Valeur |
|---|---|
| Localisation | cloudhsm-pkcs11.provider.ts:parseCertificate() |
| Nature | Parsing DER manuel vs bibliothèque dédiée |
| Risque | Cas limites non gérés (certificats complexes) |
| Mitigation | Fallback vers valeurs par défaut si parsing échoue |
| Action recommandée | Envisager @peculiar/asn1-x509 pour parsing robuste |
7. Risques résiduels¶
7.1 Disponibilité HSM¶
| Risque | Indisponibilité temporaire du HSM (réseau VPN, maintenance AWS) |
|---|---|
| Probabilité | Faible |
| Impact | Élevé (blocage des opérations crypto) |
| Mitigation actuelle | Pas de fallback mock (HSM obligatoire), erreurs explicites |
| Recommandation | Monitoring applicatif, alertes sur erreurs HSM |
7.2 Expiration de sessions longues¶
| Risque | Sessions HSM expirées pendant opérations longues |
|---|---|
| Probabilité | Faible (pool avec renouvellement) |
| Impact | Moyen (échec opération en cours) |
| Mitigation actuelle | HsmSessionPool renouvelle avant expiration (marge 30s) |
| Recommandation | Tests de charge avec opérations longues |
8. Améliorations de processus¶
8.1 Spécification mTLS plus explicite¶
La spécification initiale mentionnait "authentification mTLS" sans détailler le mécanisme de délégation de signature. Une section dédiée aux contraintes techniques (OpenSSL ENGINE, PKCS#11 URI) aurait évité l'écart E-01.
Suggestion : Ajouter une section "Contraintes d'implémentation" dans le template de spécification pour les US touchant à des APIs système.
8.2 Tests d'intégration CloudHSM¶
Les tests unitaires avec mocks sont exhaustifs, mais ne valident pas le comportement réel du HSM. La stratégie on-demand CloudHSM (annexe PD-36) permet des tests d'intégration périodiques.
Suggestion : Pipeline CI dédié "HSM Integration" exécuté hebdomadairement.
9. Enseignements clés¶
Pour le projet¶
-
mTLS avec HSM : L'API OpenSSL ENGINE reste la seule option viable en Node.js pour mTLS avec clé HSM. Documenter cette contrainte pour les futures US.
-
PKCS#11 URI (RFC 7512) : Standard essentiel pour identifier les objets HSM. Format :
pkcs11:token=<token>;object=<label>;type=private. -
Pool de sessions : Indispensable pour éviter les timeouts sur applications long-running. Le pattern acquire/release est robuste.
Pour l'équipe¶
-
Validation fail-fast : Les erreurs de configuration doivent être détectées au démarrage, pas à l'exécution d'une opération.
-
Tests mocks vs intégration : Les mocks permettent une couverture rapide, mais ne remplacent pas les tests d'intégration périodiques.
-
Documentation API deprecated : Documenter explicitement (NOSONAR + commentaires) les usages d'API deprecated avec justification et plan de migration.
Annexes¶
- CloudHSM On-Demand CI/CD — Stratégie on-demand pour réduire les coûts CloudHSM DEV
- CRYPTO-GOV-01 — Gouvernance cryptographique (algorithmes autorisés)