Clustering¶
Note
Cette fonctionnalité est actuellement en avant-première technique et comporte les limitations temporaires suivantes :
En cas de perte d’un cluster (perte du quorum), le seul moyen de récupération est la réinitialisation en usine + la restauration. Veillez à effectuer des sauvegardes fréquentes. Les prochaines versions incluront des moyens de récupérer des données sur disque.
La configuration active/passive pour prendre en charge les clusters à deux nœuds, en utilisant etcd Learner ou Mirror, n’est pas encore disponible.
L’heure du système entre les nœuds doit être synchronisée manuellement pour l’instant. Une prochaine version inclura la synchronisation automatique de l’horloge.
Le NetHSM 4.0 et les versions ultérieures prennent en charge la mise en grappe pour synchroniser directement les données entre plusieurs NetHSM. Cela permet une fréquence élevée de génération de clés, une haute disponibilité et un équilibrage de la charge. Un cluster NetHSM est basé sur etcd qui utilise l’algorithme de consensus Raft pour une cohérence forte. Cela garantit que les données (par exemple les clés) sont correctes dans tous les NetHSM à tout moment.
Avant de mettre en place un cluster NetHSM familiarisez-vous avec cette technologie et ses contraintes afin d’éviter les pannes accidentelles et les pertes de données. En complément de ce document, vous pouvez consulter la documentation de etcd.
Operational Redundancy¶
Nous appellerons « nœud » un NetHSM censé faire partie d’une grappe. Une grappe de nœuds N continuera à fonctionner tant qu’au moins (N/2)+1 nœuds sont sains et accessibles. Ce nombre minimal de nœuds sains et joignables est appelé quorum.
Cela implique les scénarios suivants.
Un nœud tombe en panne et le quorum est toujours atteint¶
Dans un cluster à trois nœuds, si un nœud tombe en panne (ou devient inaccessible en raison des conditions du réseau), les deux autres nœuds continueront à fonctionner et à répondre aux demandes.
Si le nœud défaillant est encore sain (par exemple, s’il s’agit simplement d’un problème de réseau), il sera inopérant lorsqu’il sera isolé (même pas en lecture seule).
Toutefois, si le nœud se rétablit, il se resynchronisera proprement avec le reste de la grappe et redeviendra opérationnel, sans perdre de données.
S’il ne se rétablit jamais, il doit être retiré de la grappe (voir la section suivante), réinitialisé en usine et reprendre le processus de jonction depuis le début.
Une partition du réseau se produit et le quorum est toujours atteint¶
Il s’agit d’une généralisation du scénario précédent. Dans une grappe de 5 nœuds où, par exemple, 3 nœuds se trouvent à un emplacement physique A et 2 nœuds à un autre emplacement B, un problème de réseau isolant A et B se traduirait par ce qui suit :
Les 3 nœuds de l’emplacement A atteignent le quorum (3 dans ce cas), ils continuent donc à fonctionner.
** Les 2 nœuds de l’emplacement B sont **et n’atteignent pas le quorum (toujours 3), ils cesseront donc de fonctionner (même en lecture seule).
Si le problème de réseau est résolu, les 2 nœuds rejoindront proprement les 3 autres.
Le quorum est durablement perdu¶
Une panne entraînant la perte du quorum dans tous les sous-ensembles de la grappe entraînera la perte totale de la grappe et de ses données, à moins que la panne ne soit résolue. Dans ce cas, les nœuds doivent être réinitialisés en usine et une sauvegarde doit être restaurée.
Cela peut se produire, par exemple, si un seul nœud tombe en panne dans un cluster à 2 nœuds (où le quorum est de 2). Dans ce cas, le nœud défaillant ne peut pas être supprimé proprement de la grappe après coup, car le nœud sain restant est déjà inopérant puisqu’il a perdu le quorum.
Il est donc conseillé de toujours avoir un nombre impair de nœuds dans une grappe et de faire des sauvegardes fréquentes.
Pour être clair, temporairement perdre le quorum (par exemple, si vous redémarrez tous les nœuds d’un cluster ensemble, ou si une panne de réseau temporaire isole les nœuds) n’est pas un problème : une fois que suffisamment de nœuds sont reconnectés (sans avoir à se reconnecter manuellement) pour atteindre le quorum, le cluster reprendra son fonctionnement normal. Seules les pannes permanentes, telles que les partitions de réseau, les mauvaises configurations de réseau, les problèmes d’authentification ou les pannes matérielles, nécessiteront une action manuelle.
Pour plus d’informations, voir la FAQ de etcd.
Grappe à 2 nœuds¶
Un cluster actif/passif à deux nœuds n’est pas encore supporté et sera ajouté dans une prochaine version. Nous recommandons d’introduire un troisième nœud, soit un troisième NetHSM, soit un « témoin » etcd qui pourrait être exploité sur n’importe quel hôte. Voir la section suivante « Témoin ».
Témoin¶
La nature du clustering avec etcd le rend d’autant plus fiable qu’il y a de nœuds dans le cluster. Comme expliqué dans la section Operational Redundancy, les clusters devraient idéalement avoir au moins 3 noeuds pour avoir la possibilité de tomber en panne, puisqu’un cluster à 2 noeuds tombera entièrement en panne si un seul tombe en panne.
Cependant, la conception de cette fonctionnalité est telle que vous n’avez pas besoin d’ajouter un véritable dispositif NetHSM à votre cluster pour atteindre un nombre stable de nœuds. Au lieu de cela, vous pouvez déployer et ajouter vous-même un nœud « témoin ». Un tel noeud est juste une instance de etcd tournant sur la machine de votre choix (ou dans un conteneur), et connecté au cluster. Il sera reconnu comme un nœud normal par les appareils réels du cluster, et recevra toutes les données et mises à jour des appareils (mais bien sûr vous ne pourrez pas effectuer d’opérations HSM avec lui - il ne fait que stocker des données).
Security Considerations¶
Le nœud témoin (ou toute personne y ayant accès) a un accès direct au backend de stockage de tous les nœuds de la grappe (par exemple, vous pouvez vider toutes les entrées et les valeurs correspondantes avec etcdctl get "/" "0").
Cependant, à l’exception de la version de configuration (/config/version, qui devrait toujours être « 1 »), toutes les valeurs sont strictement cryptées (avec une clé de périphérique pour les valeurs spécifiques au nœud ou les clés de domaine pour les autres), ce qui garantit la confidentialité des données sensibles.
Notez toutefois qu’un nœud malveillant peut :
écrire des déchets comme valeur pour n’importe quelle entrée du magasin, ce qui fera échouer le décryptage des nœuds (ce qui peut conduire à des plantages pour certaines entrées du système).
la liste des noms d’entrée tels que les utilisateurs, les espaces de noms et les clés, que vous pouvez considérer comme sensibles.
Creating a Cluster¶
Toute grappe démarre initialement avec un seul nœud. Les nouveaux nœuds rejoindront la grappe un par un.
Preparing Nodes¶
Le trafic réseau entre les nœuds est crypté et authentifié à l’aide de leur certificat TLS.
Tous les nœuds devant faire partie du même cluster doivent d’abord installer une autorité de certification (CA) commune qui leur permettra de vérifier que les autres nœuds sont légitimes.
Dans ce qui suit, nous supposons que tous les nœuds sont fraîchement approvisionnés et opérationnels.
Networking¶
Nodes must first be reconfigured with their expected final network configuration using the /config/network endpoint (refer to the API documentation).
Création et installation d’une AC¶
Les utilisateurs doivent créer une AC par leurs propres moyens et selon leurs propres contraintes opérationnelles, en s’assurant qu’elle autorise au moins l’utilisation de la clé keyCertSign.
Par exemple, une autorité de certification minimale peut être créée avec openssl :
$ openssl genrsa -out CA.key 2048 # create a key
$ openssl req -x509 -new -nodes -key CA.key -sha256 -days 1825 -out CA.pem -addext keyUsage=critical,keyCertSign
Cette autorité de certification doit maintenant être installée sur chaque nœud.
To do this, first generate a Certificate Signing Request (CSR) from the node with the /config/tls/csr.pem endpoint (refer to the API documentation).
Note
Pour authentifier correctement les nœuds, le backend de clustering (etcd) s’attend à ce que chaque nœud dispose d’un certificat dont le champ Subject Alt Names (SAN) est correctement rempli. En particulier, les nœuds qui ne sont accessibles que par leur adresse IP doivent avoir un SAN IP correct dans leur certificat. Les SAN IP peuvent être demandés pour la CSR en préfixant « IP : » aux noms, comme dans openssl :
"subjectAltNames": [ "normalname.org", "IP:192.168.1.1" ]
Étant donné le CSR obtenu (appelons-le nethsm.csr), nous pouvons alors générer un certificat pour lui, prêt à être installé. Par exemple avec openssl :
$ openssl x509 -req -days 1825 -in nethsm.csr -CA CA.pem -copy_extensions copy \
-CAkey CA.key -out new_cert.pem -set_serial 01 -sha256
Then install the obtained new_cert.pem with the /config/tls/cert.pem endpoint (refer to the API documentation).
Enfin, l’autorité de certification (CA.pem) peut maintenant être installée à l’aide du point de terminaison /config/tls/cluster-ca.pem (voir la documentation de l’API ` <https://nethsmdemo.nitrokey.com/api_docs/index.html>` __). Cela n’est possible que lorsque le certificat TLS installé est signé par l’AC. Sinon, l’opération sera rejetée.
Note
Ce processus doit être répété pour chaque nœud.
Synchronisation de l’horloge¶
Assurez-vous que chaque nœud a été provisionné avec une heure système précise. Si ce n’est pas le cas, ajustez leurs horloges avec le point de terminaison /config/time.
Adding a New Node¶
L’ajout d’un nœud à une grappe se fait en deux étapes :
enregistrer l’ajout au groupe (par l’intermédiaire de l’un de ses membres)
indiquer au nouveau nœud de se joindre
Configure a Backup Passphrase¶
Assurez-vous d’abord qu’une phrase de passe de sauvegarde est configurée sur le nœud qui sera utilisé pour enregistrer un nouveau joiner (voir la documentation API du point de terminaison /config/backup-passphrase).
Enregistrement d’un nouveau nœud¶
Avertissement
L’enregistrement d’un nœud introduit immédiatement un nouveau nœud dans le cluster, modifiant le seuil de quorum, même si le nœud n’a pas encore été rejoint. Cela peut rendre les nœuds existants inopérants jusqu’à ce que le nouveau nœud ait effectivement rejoint le cluster. Reportez-vous à la documentation de l’API ` <https://nethsmdemo.nitrokey.com/api_docs/index.html>` __ et à la section Operational Redundancy de ce document.
Ayez à portée de main l’adresse IP du nœud qui vous rejoindra. L’URL complète ** (également appelée peer URL dans la terminologie etcd) de ce nœud sera https://<IP_of_node>:2380 (par exemple https://192.168.1.1:2380). Le port doit être 2380, assurez-vous donc que tout pare-feu entre les nœuds autorise le trafic TCP sur ce port.
Vous pouvez vérifier que l’URL est correcte en appelant GET /cluster/members sur le nœud qui est censé se joindre. La liste ne devrait contenir qu’un seul membre : lui-même.
Enregistrez ensuite l’URL attendue sur n’importe quel nœud existant du cluster (si vous n’avez pas encore de cluster, faites-le sur le NetHSM qui servira de nœud initial du cluster). Cela se fait en utilisant le point de terminaison POST /cluster/members (voir la documentation de l’API ` <https://nethsmdemo.nitrokey.com/api_docs/index.html>` __), en lui transmettant un corps JSON contenant l’URL.
En cas de succès, il renvoie un corps JSON du formulaire :
{
"members": [
{
"name": "",
"urls": [
"https://172.22.1.3:2380"
]
},
{
"name": "9ZVNM2MNWP",
"urls": [
"https://172.22.1.2:2380"
]
}
],
"joinerKit": "eyJiYWNrdXBfc2FsdCI6IkVlUzNPOEhHSEc5NnlNRktrdG1NZmc9PSIsInVubG9ja19zYWx0IjoiU3phMkEvYW13NlhxVWsrdHZMMmFubm5SZFlWd2ZQUjdpZ3IxK1RSdTdVaU14dmh3d0x2NWIvYVNkY2c9IiwibG9ja2VkX2RvbWFpbl9rZXkiOiIyMnNGVlkyelhQUVZ6S1pQenI3MmkwTk1WM3lmQ2k5dGwzeDhUbGtuOXM0WjFOd3JoZkRQTFZIVHp1WVl0YkQxaVZCMlovV3JHUHJlMXlwN0t4U0w4WkxjY2ZUTmUzcFg0WXE4YXNlY0wwREhXNGlIaXlPMlZnPT0ifQ=="
}
qui contient les informations nécessaires pour que le nouveau nœud rejoigne la grappe. En particulier, il dresse la liste de tous les membres de la grappe (le membre dont le nom est vide étant le nouveau membre). Il contient également la clé de domaine cryptée par les phrases de déverrouillage et de sauvegarde - une phrase de sauvegarde doit donc avoir été configurée auparavant.
Conservez cette réponse pour l’étape suivante.
Rejoindre le cluster¶
Prenez la réponse de la dernière étape et ajoutez-y un champ backupPassphrase contenant la phrase de passe de sauvegarde du nœud sur lequel le nouveau membre a été enregistré, et passez ces données à un appel à POST /cluster/join (reportez-vous à la documentation de l’API ` <https://nethsmdemo.nitrokey.com/api_docs/index.html>` __) sur le nœud qui est censé rejoindre.
En supposant que le cluster et le nœud puissent se joindre, cette opération met en œuvre la jonction proprement dite, en effaçant les données du nouveau membre pour synchroniser son état avec celui du cluster.
En fonction des conditions du réseau et de la grappe, cette opération peut prendre quelques dizaines de secondes. Si cette opération échoue immédiatement (par exemple, le cluster n’était pas joignable ou l’authentification a échoué), l’état de ce nœud ne sera pas effacé et la jonction sera annulée. Cependant, dès qu’une première jointure est réussie, cette opération est définitive et ne peut être annulée que par une réinitialisation d’usine.
Si cette jonction réussit, le nœud se retrouve dans l’état Locked et doit être déverrouillé à l’aide de la phrase de passe de déverrouillage du nœud qui a été utilisé pour l’enregistrement. Par la suite, la phrase de déverrouillage peut être modifiée (les phrases de déverrouillage restent spécifiques au nœud et ne sont pas partagées entre les nœuds).
Note
Même après la réussite de la jonction, si la base de données de la grappe est volumineuse ou si la grappe est occupée, il peut s’écouler un certain temps avant que le nouveau membre ne synchronise entièrement son état. Pendant ce temps, tous les nœuds (y compris en particulier le nouvel adhérent) peuvent être moins réactifs ou ne pas l’être. Le nouvel adhérent, en particulier, peut initialement renvoyer des erreurs lorsqu’il tente de se déverrouiller, par exemple. Dans ce cas, donnez-lui un peu de temps et réessayez.
Adding a Witness Node¶
Prepare a Witness¶
Vous aurez besoin d’un environnement avec etcd v3.6 disponible, avec une adresse IPv4 (au moins) accessible par les autres membres de votre cluster. Le trafic TCP vers et depuis le port 2380 doit être autorisé.
Créez un répertoire vide dans lequel etcd stockera ses données, et écrivez son chemin (nous utiliserons /var/etcd/data). Assurez-vous que l’utilisateur qui lancera le processus a le droit de lire et d’écrire dans le répertoire.
Transférez sur la machine le certificat de l’autorité de certification qui sera utilisé pour authentifier les nœuds du cluster. Vous devriez en avoir créé un dans la section Creating and Installing a CA. Nous le stockerons dans /var/etcd/CA.pem.
Vous devrez ensuite créer un certificat pour le témoin et le signer avec l’autorité de certification afin qu’il puisse communiquer avec ses pairs. Cela peut se faire par exemple via openssl :
# Create a key
$ openssl genrsa -out witness.key 2048
# Create a CSR with a SAN that corresponds to the witness's IP or hostname
$ openssl req -new -sha256 -key own.key -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=witness" \
-addext "subjectAltName=IP:172.22.1.3" --out witness.csr
# Sign it
$ openssl x509 -req -days 1825 -in witness.csr -CA CA.pem -copy_extensions copy \
-CAkey CA.key -out witness.pem -set_serial 01 -sha256
Stockez les résultats witness.key et witness.pem dans /var/etcd également.
Register Witness to Cluster¶
Suivez les instructions normales de la section Registering a New Node pour signaler au cluster existant l’ajout d’un nouveau membre avec l’URL donnée.
Notez la réponse du cluster : elle doit contenir la liste des membres du cluster et un kit de l’adhérent (vous n’aurez pas besoin de cette partie).
Configure etcd¶
Contrairement aux NetHSM qui choisissent automatiquement un nom de nœud (à l’aide de l’ID de l’appareil), vous devez choisir un nom pour chaque témoin que vous ajoutez, en veillant à ce que les noms soient uniques. Nous utiliserons « witness1 » dans les exemples suivants.
Avec la réponse du NetHSM à l’enregistrement du témoin, préparer les variables du formulaire :
export ETCD_NAME="witness1"
export ETCD_DATA_DIR="/var/etcd/data"
export ETCD_INITIAL_CLUSTER="peer1=url1,peer1=url2,peer2=url1,peer2=url2,..."
export ETCD_INITIAL_ADVERTISE_PEER_URLS="my_url1,my_url2,..."
En supposant que la réponse du NetHSM soit stockée dans un fichier response.json, vous pouvez générer ces deux dernières variables automatiquement avec les expressions suivantes jq :
export ETCD_INITIAL_CLUSTER=$(jq --raw-output '[.members[] | ["\(if .name == "" then "witness1" else .name end)=\(.urls[])"]] | flatten | join(",")' < response.json)
export ETCD_INITIAL_ADVERTISE_PEER_URLS=$(jq --raw-output '.members[] | select(.name=="") | .urls | join(",")' < response.json)
Par exemple, avec l’exemple de réponse fourni dans la section Registering a New Node, vous aurez :
ETCD_NAME="witness1"
ETCD_DATA_DIR="/var/etcd/data"
ETCD_INITIAL_CLUSTER="witness1=https://172.22.1.3:2380,9ZVNM2MNWP=https://172.22.1.2:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://172.22.1.3:2380"
Enfin, créez un fichier etcd.conf.yml en utilisant le fichier modèle fourni dans docs/etcd_witness.conf.template :
$ envsubst < NETHSM_ROOT/docs/etcd_witness.conf.template > /var/etcd/witness.conf.yml
$ cat witness.conf.yml
Vous obtiendrez ainsi un fichier du formulaire :
name: witness1
data-dir: /var/etcd/data
log-level: warn
log-format: console
listen-peer-urls: https://0.0.0.0:2380
listen-client-urls: http://localhost:2379
initial-advertise-peer-urls: https://172.22.1.3:2380
advertise-client-urls: http://localhost:2379
initial-cluster: witness1=https://172.22.1.3:2380,9ZVNM2MNWP=https://172.22.1.2:2380
initial-cluster-state: 'existing'
peer-transport-security:
cert-file: witness.pem
key-file: witness.key
client-cert-auth: true
trusted-ca-file: CA.pem
skip-client-san-verification: true
Start etcd¶
Démarrez etcd de la manière que vous préférez (manuellement, systemd service, conteneur, etc.), en le faisant pointer vers le fichier de configuration créé à l’étape précédente :
$ cd /var/etcd
$ etcd --config-file witness.conf.yml
Vous devriez le voir démarrer, rejoindre le cluster et rattraper les données. Après un certain temps, vous devriez pouvoir vérifier qu’il est en bonne santé avec le client etcdctl :
etcdctl get /config/version
Cette clé doit exister et contenir « 1 ».
Assurez-vous que ce processus continue à fonctionner, car il est maintenant un membre à part entière de votre cluster. Si vous devez le déclasser, commencez par le supprimer correctement du cluster (voir la section dédiée). Si son IP accessible change, mettez à jour son URL depuis le cluster.
Operating a Cluster¶
Sauvegarde et restauration¶
L’opération de sauvegarde fonctionne de la même manière qu’en l’absence de cluster et peut être demandée à partir de n’importe quel nœud du cluster. Elle sauvegarde les données de l’ensemble de la grappe, y compris les champs spécifiques aux nœuds (bien que ceux-ci soient ignorés si la sauvegarde n’est pas restaurée sur un nœud non provisionné).
Une sauvegarde effectuée sur un cluster peut être restaurée sur le même cluster, même si certains nœuds ont été ajoutés ou supprimés depuis. De telles restaurations effectuées sur des clusters opérationnels n’affecteront pas les valeurs de configuration (seulement les clés, les utilisateurs, les espaces de noms), comme toute autre restauration partielle.
La restauration d’une sauvegarde sur un nœud non provisionné rétablit les champs spécifiques au nœud (comme la configuration du réseau, les certificats, etc.) du nœud utilisé pour créer la sauvegarde.
La restauration d’une sauvegarde volumineuse peut surcharger le cluster pendant un certain temps, le temps que le nœud appliquant la restauration transmette les modifications aux autres nœuds.
Cette opération reste compatible avec les sauvegardes effectuées sur les versions précédentes du NetHSM.
Note
La restauration sur un nœud A d’une sauvegarde effectuée sur un autre nœud Z avec une clé de domaine différente réécrira correctement la clé de domaine de A, comme auparavant. Cependant, si A était dans un cluster avec le noeud B, B deviendra inopérant car la clé de domaine de Z ne sera pas restaurée sur B.
En d’autres termes, n’effectuez une restauration que dans un cluster dont les sauvegardes ont été effectuées dans le même cluster (bien que des nœuds aient pu être supprimés ou ajoutés depuis). Si vous souhaitez restaurer une sauvegarde étrangère sur un nœud, commencez par le retirer en toute sécurité de son cluster, puis réinitialisez-le et restaurez la sauvegarde.
Supprimer proprement un nœud¶
Tant qu’une partie de la grappe atteint le quorum, n’importe lequel de ses membres peut être utilisé pour retirer un autre nœud de la grappe, que ce nœud soit déjà inaccessible ou qu’il le devienne.
Vous devez d’abord connaître l’ID du nœud que vous voulez supprimer, en listant tous les nœuds via GET /cluster/members et en cherchant le bon.
Ensuite, il peut être supprimé en appelant DELETE /cluster/members/<id>. Si le nœud en question était encore sain, cela l’isolera du reste du cluster et le rendra inopérant.
Software Updates in Clusters¶
Les futures mises à jour seront marquées comme « cluster-safe » (ce qui devrait être la majorité) ou « cluster-unsafe ».
Les mises à jour sécurisées peuvent être appliquées aux nœuds qui font partie d’une grappe sans les retirer de la grappe au préalable. Toutefois, comme pour toutes les opérations, il convient de veiller à effectuer cette opération sur un seul nœud à la fois, et dans un cluster où la suppression d’un nœud n’entraîne pas une baisse du quorum (par exemple, si la mise à jour échoue).
Les mises à jour non sécurisées pour les clusters doivent être appliquées à des nœuds isolés. Vous devez démanteler le cluster (en supprimant les nœuds un par un), réinitialiser tous les nœuds sauf un, appliquer la mise à jour à chaque nœud, puis faire en sorte que tous les nœuds réinitialisés rejoignent le nœud restant.
Veillez à effectuer une sauvegarde avant de procéder à de telles opérations.
Reconfiguration d’un cluster existant¶
Changing the Cluster CA¶
Un cluster existant (avec deux nœuds ou plus) ne peut pas changer l’autorité de certification de son cluster en cours de fonctionnement. Si vous devez modifier ce certificat, choisissez un nœud, supprimez tous les autres nœuds, mettez à jour l’autorité de certification, puis demandez aux autres membres de se joindre à nouveau à la grappe.
Changing the Network Configuration of Nodes¶
La modification de la configuration réseau d’un nœud (par exemple, le changement de son IP) informera automatiquement les autres nœuds de la mise à jour. Vous devez toutefois veiller à n’effectuer ces mises à jour que sur un seul nœud à la fois, et dans un cluster où la perte de ce nœud n’entraînerait pas la perte du quorum.