La souveraineté dans le Cloud par le chiffrement tierce-partie – Partie 2

Temps de lecture : 15 minutes

Dans la première partie de cette série d’articles, nous avons considéré Sovereign Keys comme une « boîte noire” pour nous concentrer sur ce qu’elle apporte d’un point de vue fonctionnel, sans (trop) nous embarrasser des détails.

Dans cette deuxième partie, nous allons parler des détails. Cela nous permettra de poser de bonnes bases pour discuter de deux faiblesses incontournables du chiffrement tierce-partie :

  • l’interception de la clé en transit
  • l’authentification de l’instance EC2

Cet article est destiné à des architectes AWS avec au minimum le niveau “associate”. Je vais faire de mon mieux pour toujours faire ressortir les concepts importants, mais si vous n’êtes pas à l’aise avec les principaux services AWS et leurs usages, l’article risque de vous paraître difficile.

Un oeil dans la boîte noire

Pour commencer, regardons rapidement dans la boîte noire, histoire de nous faire une idée de ce qui nous attend.

Côté Cloud AWS, on repère les icônes de Lambda, EC2, API Gateway et S3. Nous y reviendrons un peu plus loin. Ce qui est intéressant ici, c’est le côté “Datacenters client” qui contient un “Hardware Security Module (HSM)”.

Un Hardware Security Module, ou HSM, est un équipement matériel (d’où le “hardware”) spécialisé pour la protection de secrets. Sans rentrer dans des détails qui dépassent mes compétences, soulignons l’intérêt qu’un tel équipement a pour nous.

Protection des clés de chiffrement

Protéger des secrets c’est compliqué. Imaginez que j’ai un secret crucial, dans la mémoire d’une application, sur un serveur “normal”. Question légitime : est-il en sécurité ?

C’est difficile à dire :

  • L’application est-elle correctement codée ? A-t-elle des bugs ? Sont-ils de nature à permettre l’extraction du secret ?
  • Et le système d’exploitation (OS) ? Mêmes questions, mais dans un contexte où l’audit est beaucoup plus complexe.
  • Qui administre le serveur ? Comment les actions de cet administrateur sont contrôlées et auditées ?
  • Est-ce que mon serveur est une VM ? Si oui, qui administre l’hyperviseur ?
  • Qui a accès physiquement à mon serveur ? Cela change-t-il quelque chose ? (Oui).
  • Et le processeur ? Et la RAM ? Et le réseau ? Et l’alimentation électrique ? Et les LED extérieures du serveur ? Etc…

Le fait est qu’un serveur “normal” a une surface d’attaque énorme car, au global, c’est un système extrêmement complexe dont personne au monde ne maîtrise le fonctionnement de bout en bout. C’est un assemblage de tas de composants physiques avec des tas de composants logiques.

Un HSM, en premier lieu, est un système beaucoup plus simple. L’objectif est de réduire au maximum la surface d’attaque, en proposant le minimum possible de features et en définissant des interfaces très cadrées ; ce qui diminue la complexité globale et donc améliore la maîtrise de bout en bout. Ça ne garantit pas l’inviolabilité absolue, bien entendu, les erreurs d’implémentation (hardware ou software) restent possibles. Mais c’est déjà très nettement mieux qu’un serveur “normal”.

Pour Sovereign Keys, qui doit protéger des clés de chiffrement (on verra ça plus loin), l’utilisation d’un HSM est un gage d’une plus grande sécurité.

Implémentation correcte des algorithmes cryptographiques

Si vous vous intéressez à la cryptographie, vous savez que c’est compliqué. Je ne parle pas de la complexité mathématique qui sous-tend les algorithmes (bien réelle ceci dit) mais de leur complexité d’implémentation.

Les fondements mathématiques de nos algorithmes modernes sont solides, AES est presque unanimement admis comme inviolable en tant qu’algorithme mathématique. Mais l’implémentation de ces algorithmes est un chemin semé d’embûches avec mille façons de faire n’importe quoi.

L’embûche la plus connue est le concept de “side-channel attack”. Décrite de manière simpliste, l’idée consiste à deviner un secret en observant les fluctuations de fréquence, voltage, temps de traitement ou autre qui se produisent lorsque ce secret passe dans la moulinette de chiffrement. Pour éviter ça, il est crucial d’avoir une implémentation qui s’assure de ne pas produire ce genre de fluctuations. Et c’est dur.

Pour Sovereign Keys, l’utilisation d’un HSM pour les opérations cryptographiques permet de déléguer cette implémentation à un équipement spécialisé, conçu par des gens dont c’est le métier. Et là encore, c’est un gage d’une plus grande sécurité pour les données que Sovereign Keys protège.

De fait, la “boite noire” Sovereign Keys est très nettement coupée en deux :

  • d’un côté les HSM, qui assurent ultimement la protection des secrets et la bonne exécution des opérations cryptographiques et qui peuvent être localisés en dehors du Cloud AWS ;
  • de l’autre les divers éléments permettant de fournir une interface exploitable pour rendre le service attendu, forcément dans AWS eux.

Voyons maintenant le côté AWS.

L’architecture côté AWS

Construisons le schéma côté AWS pas-à-pas.

Un Autoscaling Group

Sovereign Keys est en grande partie du software permettant de faire le lien entre les instances clientes, qui consomment des secrets pour chiffrer leurs données, et les HSM, dont on a vu qu’ils sont responsables de toutes les opérations de chiffrement internes de Sovereign Keys.

Un premier schéma est donc celui-ci :

Nous avons un AutoScaling Group (ASG) d’instances EC2 dans des subnets privés. Ces instances portent le software de Sovereign Keys et permettent d’opérer les HSM (“Do Magic” sur le schéma).

L’ASG n’est pas là pour des raisons de scalabilité (il n’y a pas besoin car les HSM sont en réalité le facteur limitant pour les performances) mais pour des raisons de self-healing. Les instances Sovereign Keys ne sont pas “juste” 3 instances portant un software : elles composent en fait un cluster et il est important de toujours avoir une majorité absolue de noeuds en bonne santé. Lorsqu’une instance tombe en panne pour une raison quelconque, il faut donc rapidement revenir à 3 instances, ce que l’ASG assure.

Un cluster Sovereign Keys de 3 nœuds peut donc tolérer la perte d’un nœud ou d’une AZ (dans un cluster de 3 nœuds, on doit toujours en avoir minimum 2) et se répare tout seul en quelques minutes. On peut augmenter le nombre de nœuds le cas échéant.

Ce cluster est porté par etcd. La raison de sa présence est de permettre d’avoir :

  • un partage d’informations entre les instances (le password des HSM, par exemple) ;
  • une possibilité de “verrous” inter-instance pour empêcher deux instances d’utiliser le même numéro de log (voir le premier article) quand elles reçoivent chacune une requête au même moment.

Etcd apporte les deux.

Sur le schéma, le lien réseau entre les instances Sovereign Keys et les HSMs n’est pas détaillé : c’est parce qu’il est libre et sans grande importance. Si vous utilisez CloudHSM, les HSM seront probablement dans le même VPC ou dans un autre via VPC-peering ; si vous utilisez vos propres HSMs on-premises, on passera peut-être par un VPN ou un Direct Connect. En fait, peu importe le moyen technique utilisé, l’important c’est que la connectivité soit possible.

Reste à voir comment établir la connectivité entre les instances Sovereign Keys et les instances clientes.

Une API Gateway privée

Comme les instances Sovereign Keys sont dans un VPC et que les instances clientes aussi (puisque Sovereign Keys s’adresse exclusivement aux clients AWS), on est tenté d’utiliser Private Link.

Sur le principe, il suffirait donc de mettre nos instances derrière un Network Load Balancer (NLB) et de créer un “Service Endpoint” dessus. Mais en faisant ça, on expose directement les instances Sovereign Keys aux VPCs clients. Et de fait, c’est un risque de sécurité non négligeable, notamment pour tout ce qui est DDoS (Distributed Denial of Service).

Du coup, nous faisons plutôt ça :

Plutôt que d’exposer directement le NLB de Sovereign Keys, on utilise une API Gateway privée accessible via Private Link via un VPC endpoint et cette API utilise à son tour un autre Private Link pour contacter les instances au travers du NLB. L’authentification de l’instance cliente est faite par une fonction Lambda (Lambda Authorizer).

Parmi les avantages de la solution, on peut déléguer la responsabilité du throttling et de l’authentification à API Gateway. De fait, les instances Sovereign Keys ne sont exposées qu’à du trafic déjà authentifié et à un rythme maximum supportable. API Gateway étant un composant complètement managé par AWS, on ne s’inquiète pas de sa protection contre le DDoS.

Aussi, cette solution permet de n’avoir aucune adhérence entre l’adressage IP choisi pour le VPC Sovereign Keys et celui des VPC clients, un élément important si on veut faire de Sovereign Keys un service managé ou si on subit déjà de nombreuses contraintes autour de cette question !

Enfin, la solution permet d’avoir un nombre illimité de “VPC client” puisqu’il suffit de créer un VPC Endpoint pour API Gateway (qui s’appelle execute-api). Et avant même la lambda d’authentification, on peut aisément restreindre les VPC autorisés à contacter Sovereign Keys en utilisant la policy IAM de l’API Gateway.

Les autres éléments

À ce stade, le coeur de l’architecture est déjà révélé, on peut donc présenter le schéma complet avec les annotations sur les interactions :

Lien vers l’image en grand format

Comme dit précédemment, on peut avoir plusieurs comptes/VPC clients. Trois sont représentés pour souligner cela.

Ensuite, la lambda d’authentification requiert la présence d’un rôle IAM dans le compte AWS de l’instance (nous détaillerons l’authentification dans le 4ème article) pour pouvoir en vérifier l’identité. Notons que la Lambda d’authentification doit pouvoir trouver le rôle pour l’assumer.

Par ailleurs, le client peut créer un bucket S3 pour récupérer les logs relatifs à son VPC (Customer 1 Log Bucket sur le schéma). Là encore, il faut que Sovereign Keys puisse trouver le nom du bucket.

D’où la présence d’une base DynamoDB pour stocker ces informations et les mettre à disposition de Sovereign Keys.

Le compte AWS de Sovereign Keys a également un bucket de log central appelé “Sovereign Keys Log bucket”.

Finalement, reste à expliquer le bucket S3 signalé par “EKT Storage”.

La hiérarchie de clés

En cryptographie on parle souvent de hiérarchie de clés ou de chiffrement d’enveloppe (enveloppe encryption). L’idée romantique d’avoir une clé de chiffrement unique qui chiffre toutes nos données n’est pas réaliste. En pratique, on a plutôt une clé, qui chiffre d’autres clés, qui elles-mêmes chiffrent d’autres clés, qui chiffrent des données.

Dit comme ça, ça fait un peu usine à gaz. Mais il y a d’excellentes raisons.

Les raisons d’avoir une hiérarchie de clés

Risque sécuritaire

En cryptographie, on n’aime pas réutiliser la même clé encore et encore. Dans certaines circonstances spécifiques, on sait que ça diminue, voire annihile complètement, la protection des données (exemple de risque pour AES-GCM). Mais même quand il n’y a aucune attaque connue, il reste préférable de limiter la réutilisation d’une clé car, si il existe un moyen de compromettre la protection des données, alors la réutilisation de la même clé ne peut qu’empirer la situation. C’est une première raison de mettre en place des hiérarchies de clés.

Par ailleurs, on peut se convaincre que plus on utilise une clé de chiffrement, et plus le risque qu’elle soit compromise augmente. C’est logique : dès lors que la probabilité de compromission lors d’une utilisation individuelle est supérieure à zéro ; alors plus on utilise la clé, plus le risque cumulé de compromission augmente. Hors, personne ne peut affirmer que cette probabilité est égale à zéro donc il faut partir du principe qu’elle est supérieure à zéro. C’est imparable. En multipliant les clés, on étale le risque. Deuxième raison.

Aussi, en multipliant les clés, la compromission d’une clé expose une quantité limitée de données, on limite donc le “blast-radius”. Troisième raison.

Réalité technique

Sur une approche beaucoup plus terre à terre, un HSM ça coûte cher. Très cher. Et un seul HSM ne peut pas stocker des millions de clés de chiffrement, et le stockage est difficile à passer à l’échelle en multipliant les HSM (trop cher, trop de contraintes sur la synchronisation entre les HSM).

Dans le même esprit, un HSM dispose d’une bande passante limitée, là encore difficile à passer à l’échelle. On ne peut donc pas faire passer toutes nos données par lui pour les chiffrer : on doit trouver un compromis prenant en compte l’impossibilité de tout chiffrer via le HSM et le désir de ne jamais faire sortir les clés de chiffrement du HSM (parce que c’est la meilleure protection possible).

Sovereign Keys rend ce besoin encore plus flagrant parce qu’on a vu dans le précédent article que le chiffrement des données à proprement parler est de la responsabilité de l’instance client elle-même (via Bitlocker ou LUKS). On doit donc distinguer des data keys, qui sont fournies aux instances, et des master keys, qui protègent les data keys et sont protégées par les HSM.

La hiérarchie de Sovereign Keys

Sovereign Keys utilise une hiérarchie à 3 niveaux :

  1. La Domain Key est au sommet de la hiérarchie, elle ne quitte jamais les HSM et il n’y en a qu’une seule pour tout Sovereign Keys.
  2. Les Customer Master Key sont protégées par la Domain Key, elles ne peuvent exister en clair que dans le HSM et, par défaut, il y en a une pour chaque VPC client.
  3. Les Instance Secret sont protégés par une Customer Master Key et existent en clair dans la RAM d’une instance ou dans le HSM et il y en a autant que de volumes à protéger.

Pour aider, deux visualisations complémentaires sont utiles.

D’abord, la relation entre chaque clé et sa protectrice résume visuellement ce qu’on vient d’écrire :

Notez qu’on appelle la version chiffrée d’une Customer Master Key un Encrypted Key Token, ou EKT en acronyme. Comme le nom d’un certain bucket S3 qu’il restait à expliquer.

Ensuite, le schéma des “lieux de résidence” de chaque clé sous ses différentes formes permet de mieux apprécier comment s’articule la protection :

La Domain Key n’existe que dans la mémoire permanente des HSM, et j’ajoute que dans le cas de Sovereign Keys elle ne peut pas en être extraite (c’est une garantie fournie par le HSM, on dit qu’elle est “non exportable”).

La Customer Master Key n’existe que du côté “Sovereign Keys” : en clair dans le HSM durant une opération et chiffrée (EKT) dans le bucket S3 dédié au stockage des EKT. C’est le fameux “EKT Storage” du schéma d’architecture.

L’Instance Secret est la seule clé qui existe du côté client. Sa version chiffrée est stockée sur le volume qu’il protège. Pour le déchiffrer, il faut utiliser la Customer Master Key, donc l’opération ne peut se faire que dans le HSM, côté Sovereign Keys. Une fois déchiffrée, la clé est utilisée par l’instance pour faire ses opérations (Bitlocker/LUKS) et donc elle est présente dans la RAM de l’instance.

Le schéma montre aussi le partitionnement d’un volume protégé par Sovereign Keys. Il est en fait divisé en 2 partitions : une toute petite (1 méga-octet) pour stocker l’Encrypted Instance Secret ; et tout le reste du volume pour contenir les données chiffrées.

Sécurité de la hiérarchie

La “beauté” de ce genre de construction, c’est que la sécurité des deux premiers niveaux de la hiérarchie (Domain Key et Customer Master Key) est équivalente à ce qu’on obtiendrait si toutes ces clés ne sortaient jamais du HSM. Mais en même temps, en mettant en place ce mécanisme d’EKT stockés dans S3, on gagne la possibilité d’avoir un nombre illimité de Customer Master Keys.

Certains me diront peut-être “Mais si AES peut être cassé par la NSA ce que tu dis est faux”. Sauf que nous avons déjà établi dès le premier article que, correctement implémenté, AES-256 est incassable et le restera.

Durabilité des données

En exposant cette hiérarchie, on note que le seul endroit où est stocké l’Encrypted Instance Secret, c’est sur un volume d’instance cliente. Que se passe-t-il si on perd ce volume ? On perd les données, évidemment. Pour éviter ça, on connaît la technique : il faut faire des backups ! Chiffrer les données assure leur confidentialité, pas leur durabilité !

Il est logique que la durabilité de l’Instance Secret soit complètement corrélée à celle des données. Mais quid de la durabilité des Customer Master Keys ? Et de celle de la Domain Key ? Ce sont des questions pertinentes parce que perdre ces clés revient à perdre tout ce qui est en dessous dans la hiérarchie !

C’est pourquoi la durabilité des EKT (et donc des Customer Master Keys) est assurée par S3, avec la feature Object Lock activée. Une réplication vers une autre région, voire carrément hors d’AWS, peut également être mise en place : mieux vaut avoir trop de réplicat que pas assez.

Du côté de la Domain Key, tout dépend de vous ! Elle est stockée dans vos HSM et c’est donc votre pleine et entière responsabilité ! La plupart des HSM ont un mécanisme de backup. En complément, on peut également avoir une réplication entre plusieurs HSM. 

Concernant le “Sovereign Keys managé” de Devoteam Revolve, nous avons les deux : backup des HSM et 2 HSM en cluster.

Cinématique d’une demande de déchiffrement

Résumons ce qu’on a appris sur le fonctionnement de Sovereign Keys (SK) dans cet article :

  • C’est un système avec une partie software qui pilote des HSM.
  • Les HSM sont des équipements spécialisés qui assurent la protection des clés de chiffrement et les opérations de chiffrement à proprement parler.
  • La partie software de SK est hautement disponible et résistante aux attaques type DDoS.
  • La hiérarchie de clés permet d’adresser les enjeux de performance, de limiter le “blast-radius” d’une éventuelle compromission, sans compromettre la sécurité délivrée par les HSM.
  • La durabilité des clés du “haut” de la hiérarchie est assurée.

Avant de libérer mes lecteurs, faisons un dernier schéma permettant d’expliquer ce qui se passe lorsqu’une instance cliente démarre et souhaite déchiffrer son volume de données. Il servira à la fois de résumé de ce que nous venons de voir et d’introduction pour la suite :

Lien vers l’image en grand format

  1. L’instance cliente initie un appel “decrypt” vers l’API Gateway privée, au travers de son VPC endpoint ; elle transmet notamment son instance ID et le secret qu’elle veut déchiffrer (on verra ça plus en détail au prochain article)
  2. API Gateway appelle la Lambda d’authentification
  3. La Lambda extrait l’ID du VPC appelant de la requête et s’en sert pour trouver l’entrée correspondante dans DynamoDB et récupérer l’ARN du rôle IAM
  4. Elle assume le rôle et vérifie l’adresse IP de l’instance auprès de l’API EC2 pour vérifier que c’est bien celle qui a envoyé la requête (on verra ça plus en détail au quatrième article)
  5. Une fois l’authentification faite, la requête est transmise via Private Link à une des instances SK
  6. L’instance récupère dans la table DynamoDB le nom de l’EKT et, le cas échéant, du bucket de log client (Customer1 Log Bucket sur le schéma)
  7. L’instance récupère l’EKT dans S3
  8. L’instance importe dans un HSM l’EKT (qui redevient une Customer Master Key) puis l’instance Secret (plus de détail d’ici la fin de la série, patience !)
  9. L’instance envoie le(s) log(s) de l’opération avant de renvoyer la réponse
  10. L’instance renvoie la réponse à l’instance, qui peut donc déverrouiller son volume.

Dans le prochain article, nous parlerons de la protection de l’Instance Secret en transit et des défis que cela pose dans un contexte Cloud !


Sovereign Keys est disponible en version Open Source : GitHub Sovereign Keys


Commentaires :

A lire également sur le sujet :