Chiffrement ZFS : sécurité forte sans sacrifier les performances

Cet article vous a aidé ?

Le chiffrement était autrefois quelque chose qu’on activait parce que le service juridique l’exigeait, puis il fallait passer le trimestre suivant à expliquer pourquoi les graphiques de stockage ressemblent à une piste de ski. ZFS a changé cette dynamique : le chiffrement est par dataset, en ligne, et conçu pour garder votre pipeline de stockage prévisible—si vous l’abordez comme de l’ingénierie, pas comme une case à cocher.

Voici le guide de production que j’aurais aimé voir avant le premier incident « on a tout chiffré, pourquoi la base de données pleure ? ». Nous couvrirons ce que fait réellement le chiffrement natif ZFS, d’où vient vraiment le surcoût, comment garder la réplication raisonnable, et comment diagnostiquer rapidement les goulots d’étranglement quand le pager est déjà chaud.

Ce qu’est le chiffrement ZFS (et ce qu’il n’est pas)

Le chiffrement natif OpenZFS est un chiffrement au niveau du dataset. Vous pouvez chiffrer un dataset, laisser un autre en clair, et le pool s’en fiche. Ce n’est pas un accident—c’est une décision opérationnelle intégrée à la fonctionnalité. Le chiffrement intervient sous l’interface du système de fichiers mais au-dessus de la couche vdev. En termes pratiques :

Ce que ça fait

Il chiffre le contenu et les métadonnées du dataset pour ce dataset. Cela inclut les données des fichiers, les attributs de fichier, la structure des répertoires, et la plupart des métadonnées que ZFS stocke pour ce dataset. Un attaquant avec un accès brut aux disques (ou un array volé) ne peut pas lire vos données sans les clés.

Ce que ça ne fait pas

Il ne chiffre pas l’ensemble du pool. Certaines métadonnées au niveau du pool restent visibles (nom du pool, topologie des vdev, certaines informations d’allocation). En général cela n’est pas critique—si quelqu’un a vos disques, vous avez des problèmes plus graves que le fait qu’il sache que vous utilisiez raidz2—mais cela compte pour le modèle de menace.

Il ne remplace pas le contrôle d’accès. Si un attaquant a le root sur une machine en cours d’exécution avec le dataset déverrouillé, le chiffrement est surtout cosmétique. Le chiffrement protège les données au repos, pas les machines compromises. Si quelqu’un peut exécuter zfs send en root, il n’a pas besoin de contourner AES ; il peut simplement exfiltrer les données poliment.

Ce n’est pas une condamnation de performance. Mais ça peut le devenir si vous le combinez avec de petits blocks, des écritures synchrones, un mauvais choix de CPU, et la croyance que « la compression est optionnelle ». Une pile de stockage ne vous punit pas pour le chiffrement ; elle vous punit pour croire que le chiffrement est la seule chose qui se passe.

Blague n°1 : Le chiffrement, c’est comme la ceinture de sécurité—embêtant jusqu’à ce qu’elle vous sauve, et vous ne devriez quand même pas foncer délibérément contre un mur.

Quelques faits et un peu d’histoire importants

Quelques points de contexte courts qui vous aideront à prendre de meilleures décisions :

  1. ZFS est né chez Sun avec l’idée que « le stockage est un système, pas un tas de disques » ; l’écosystème OpenZFS moderne a gardé cette discipline même si les implémentations ont divergé puis convergé.
  2. Le chiffrement natif ZFS est arrivé plus tard que prévu car le faire « à la manière ZFS » implique de préserver la sémantique des snapshots, le comportement send/receive, et la cohérence sur disque.
  3. Le chiffrement ZFS est par dataset, pas par pool. Cela rend l’adoption progressive possible et les migrations moins effrayantes.
  4. Chiffrement et compression coexistent bien dans ZFS parce que la compression intervient avant le chiffrement dans la chaîne—compressing ciphertext is famously pointless.
  5. AES-GCM est courant dans les configurations ZFS modernes car il fournit un chiffrement authentifié (confidentialité + intégrité) avec une bonne accélération matérielle sur la plupart des CPU serveurs.
  6. ZFS send peut transmettre des flux chiffrés bruts (là où c’est supporté) afin que le récepteur stocke des blocs chiffrés sans jamais voir le plaintext—important pour les domaines de sauvegarde.
  7. Le recordsize et la nature de la charge importent plus que le « surcoût du chiffrement » pour beaucoup de systèmes réels ; les E/S aléatoires et les écritures sync dominent bien avant AES.
  8. La gestion des clés est le vrai risque de fiabilité : pas parce que la crypto est difficile, mais parce que les humains oublient des passphrases, font de mauvaises rotations de clés, ou conçoivent le déverrouillage au démarrage comme une réflexion de dernière minute.

Modèle de menace : ce que vous protégez, en pratique

Avant de choisir une stratégie de chiffrement, décidez ce que « sécurisé » signifie dans votre environnement. En production, le modèle de menace le plus pertinent est ennuyeux :

  • Disques perdus ou volés lors de RMA, d’expédition, ou de mise hors service.
  • Serveurs volés (oui, ça arrive encore, surtout en périphérie et dans des succursales).
  • Exposition des médias de sauvegarde—un snapshot répliqué hors site est une fuite de données en attente d’être découverte.
  • Accès mal placé : quelqu’un accède à une baie de stockage, à une console d’hyperviseur, ou à un appliance de sauvegarde où il ne devrait pas être.

Le chiffrement natif ZFS est très efficace pour « les données sont sûres si les disques s’en vont ». Il est moins pertinent pour « quelqu’un a le root sur la machine ». Pour cela, il vous faut durcir, appliquer le principe du moindre privilège, et monitorer. Le chiffrement est une couche, pas un auréole.

Modèle de performance : où vont les cycles

Parlons de la partie « tue les performances ». Dans la pratique, les régressions de performance attribuées au chiffrement proviennent généralement d’un des quatre endroits suivants :

1) Cycles CPU (mais souvent pas là où vous croyez)

Sur des serveurs x86 modernes avec AES-NI (ou accélération équivalente), le chiffrement AES-GCM n’est typiquement pas le goulot d’étranglement pour les charges séquentielles. Où vous le ressentirez :

  • IOPS très élevés avec de petits blocs (métadonnées lourdes, lectures/écritures aléatoires).
  • Systèmes déjà contraints en CPU (compression, checksums, dedup, calculs RAIDZ lourds, SMB signing, etc.).
  • Environnements virtualisés où le « steal » CPU devient le saboteur silencieux.

2) Amplification I/O due au mauvais recordsize

Le chiffrement ne change pas votre recordsize, mais il augmente les enjeux. Si vous exécutez des bases de données sur un dataset avec un recordsize énorme, vous subissez déjà des churns read-modify-write. Ajoutez des écritures sync et soudainement tout le monde pense « le chiffrement l’a fait ». Non—votre stratégie de blocs l’a fait.

3) Écritures synchrones et l’histoire ZIL/SLOG

ZFS respecte la sémantique sync. Si votre charge de travail émet des écritures sync (bases de données, NFS, certains modèles de stockage VM), la latence est dominée par le chemin log. Le surcoût du chiffrement sur le chemin principal devient secondaire si votre SLOG est lent, mal configuré, ou absent.

4) Chargement des clés et orchestration des montages

C’est ce qui mord les équipes opérationnelles : un dataset chiffré qui n’est pas chargé ne se monte pas. Si votre ordre de démarrage, vos services, ou vos règles d’automount supposent que le dataset est toujours présent, vous pouvez transformer un simple reboot en panne. Le graphe de performance peut être correct ; votre graphe de disponibilité ne le sera pas.

Blague n°2 : La bonne chose avec le chiffrement, c’est qu’il rend vos données illisibles pour les attaquants ; la moins bonne, c’est qu’il peut aussi les rendre illisibles pour vous si vous traitez les clés comme « le problème du moi futur ».

Concevoir des datasets chiffrés sans regrets

Les déploiements de chiffrement ZFS les plus intelligents que j’ai vus partagent un schéma : ils n’encryptent pas « le pool ». Ils chiffrent des domaines de données.

Chiffrez aux limites des datasets qui correspondent aux frontières de confiance

Exemples de bonnes délimitations :

  • Datasets par application : pool/app1, pool/app2
  • Datasets par locataire dans un stockage multi-tenant
  • Dataset séparé pour sauvegardes/répliques (souvent avec une gestion des clés différente)
  • Dataset « archives froides » avec des propriétés de performance différentes

Pourquoi c’est important : vous pouvez faire tourner les clés, répliquer, snapshotter et appliquer des quotas par frontière. Et vous pouvez garder un espace de travail à forte rotation non chiffré si votre modèle de risque le permet, économisant des cycles là où ils comptent.

Choisissez les propriétés de chiffrement intentionnellement

Le chiffrement OpenZFS se configure à la création du dataset et s’hérite. Les éléments principaux :

  • encryption : algorithme/mode (couramment aes-256-gcm)
  • keyformat : passphrase ou raw
  • keylocation : où récupérer la clé (prompt, fichier, etc.)

En production, la vraie décision n’est pas « AES-256 vs AES-128 ». C’est : voulez-vous une passphrase humaine (idéale pour le déverrouillage manuel, risquée pour l’automatisation) ou une clé raw dans un fichier (idéale pour l’automatisation, nécessite une forte sécurité OS et une distribution des secrets) ?

La compression est votre alliée, pas votre ennemie

Si vous chiffrez, vous devriez presque toujours activer la compression (typiquement lz4). Elle réduit les E/S disque, réduit la bande passante de réplication, et améliore souvent la performance end-to-end. La compression économise plus de temps que ne coûte le chiffrement sur beaucoup de charges. La seule fois où je désactive régulièrement la compression, c’est quand je sais que les données sont déjà compressées et que le CPU est réellement le goulot—et c’est plus rare qu’on ne le suppose.

Ne confondez pas chiffrement avec checksums et intégrité

Les checksums ZFS détectent la corruption ; le chiffrement empêche la lecture non autorisée. Avec AES-GCM vous avez aussi de l’authentification, ce qui aide à détecter la falsification. Mais les checksums de ZFS font toujours un travail réel, particulièrement sur du hardware, des contrôleurs ou de la RAM instables. Ne désactivez pas les checksums (et n’essayez pas ; ZFS ne vous laissera pas faire comme vous l’espérez).

Gestion des clés qui fonctionne à 3 a.m.

Le succès opérationnel du chiffrement ZFS est surtout le succès du cycle de vie des clés. Voici ce qui marche réellement en production :

Privilégiez un petit nombre de « classes » de clés

Trop de clés uniques transforme chaque restauration en chasse au trésor. Trop peu de clés augmente le rayon d’impact. Un compromis pratique :

  • Une clé par frontière application ou locataire
  • Une clé séparée pour les sauvegardes/cibles de réplication
  • Une clé distincte pour les datasets « infrastructure partagée » (logs, configs) s’ils contiennent des secrets

Décidez comment le déverrouillage se produit

Schémas courants :

  • Déverrouillage manuel après démarrage pour les datasets sensibles (l’opérateur saisit la passphrase). Excellent pour le modèle « serveur volé » ; récupération plus lente.
  • Déverrouillage automatisé via fichier clé stocké sur l’hôte (protégé par la sécurité OS, TPM, ou accès restreint). Récupération plus rapide ; augmente le risque si l’hôte est compromis.
  • Déverrouillage fractionné : les datasets d’infrastructure se déverrouillent automatiquement ; les datasets « joyaux de la couronne » exigent un déverrouillage manuel.

Les pannes les plus douloureuses que j’ai vues n’étaient pas causées par le surcoût du chiffrement—elles étaient causées par un reboot où le système redémarrait « correctement », sauf que les datasets ne se montaient pas parce que personne n’avait pensé à charger les clés dans le graphe de services.

Tâches pratiques (commandes + interprétation)

Les tâches suivantes supposent OpenZFS sur Linux avec les outils standards. Adaptez les chemins et la gestion des services à votre environnement. Les commandes sont montrées comme une vraie session shell ; les sorties sont représentatives.

Task 1: Check what’s encrypted and what isn’t

cr0x@server:~$ zfs list -o name,encryption,keylocation,keystatus,mounted -r tank
NAME                 ENCRYPTION        KEYLOCATION         KEYSTATUS  MOUNTED
tank                 off               none                -          yes
tank/apps             aes-256-gcm      file:///etc/zfs/keys/apps.key  available yes
tank/apps/db          aes-256-gcm      inherit             available yes
tank/backups          aes-256-gcm      prompt              unavailable no

Interprétation : tank/apps est chiffré et utilise un fichier clé ; les enfants héritent. tank/backups nécessite un déverrouillage interactif et est actuellement indisponible, donc il n’est pas monté.

Task 2: Create an encrypted dataset with sane defaults

cr0x@server:~$ sudo install -d -m 0700 /etc/zfs/keys
cr0x@server:~$ sudo dd if=/dev/urandom of=/etc/zfs/keys/app1.key bs=32 count=1 status=none
cr0x@server:~$ sudo chmod 0400 /etc/zfs/keys/app1.key

cr0x@server:~$ sudo zfs create \
  -o encryption=aes-256-gcm \
  -o keyformat=raw \
  -o keylocation=file:///etc/zfs/keys/app1.key \
  -o compression=lz4 \
  -o atime=off \
  tank/app1

Interprétation : Clé raw + fichier clé est adapté à l’automatisation. compression=lz4 et atime=off sont des valeurs par défaut courantes en production pour beaucoup de charges.

Task 3: Create a child dataset for a database with a tuned recordsize

cr0x@server:~$ sudo zfs create -o recordsize=16K -o logbias=latency tank/app1/pgdata
cr0x@server:~$ zfs get -o name,property,value encryption,recordsize,logbias tank/app1/pgdata
NAME              PROPERTY    VALUE
tank/app1/pgdata  encryption  aes-256-gcm
tank/app1/pgdata  recordsize  16K
tank/app1/pgdata  logbias     latency

Interprétation : L’enfant hérite du chiffrement, mais vous avez ajusté le recordsize pour une charge de type base de données et demandé à ZFS d’optimiser la latence synchrone.

Task 4: Load a key and mount an encrypted dataset

cr0x@server:~$ sudo zfs load-key tank/backups
Enter passphrase for 'tank/backups': 
cr0x@server:~$ sudo zfs mount tank/backups
cr0x@server:~$ zfs get -o name,property,value keystatus,mounted tank/backups
NAME         PROPERTY  VALUE
tank/backups keystatus available
tank/backups mounted   yes

Interprétation : Clé chargée, dataset maintenant montable. Si vous oubliez l’étape de montage, vous regarderez un répertoire vide et accuserez l’univers.

Task 5: Unload a key (and what it really does)

cr0x@server:~$ sudo zfs unmount tank/backups
cr0x@server:~$ sudo zfs unload-key tank/backups
cr0x@server:~$ zfs get -o name,property,value keystatus,mounted tank/backups
NAME         PROPERTY  VALUE
tank/backups keystatus unavailable
tank/backups mounted   no

Interprétation : Décharger la clé rend le dataset inaccessible jusqu’à son rechargement. Cela ne « ré-encrypte » pas les blocs existants—ils sont déjà chiffrés au repos.

Task 6: Confirm that replication can stay encrypted end-to-end

cr0x@server:~$ sudo zfs snapshot -r tank/app1@replica-test
cr0x@server:~$ zfs get -H -o value encryption tank/app1
aes-256-gcm

Interprétation : Le snapshot est pris. Que vous puissiez envoyer un flux chiffré brut dépend du support des fonctionnalités aux deux extrémités ; validez dans votre environnement, ne supposez pas.

Task 7: Estimate compression and written throughput impact

cr0x@server:~$ zfs get -o name,property,value compressratio,logicalused,used -r tank/app1
NAME           PROPERTY      VALUE
tank/app1      compressratio 1.62x
tank/app1      logicalused   48.3G
tank/app1      used          29.8G
tank/app1/pgdata compressratio 1.08x
tank/app1/pgdata logicalused 310G
tank/app1/pgdata used        287G

Interprétation : Les données applicatives se compressent bien ; la base de données moins. Cela compte car les gains de compression compensent souvent le surcoût du chiffrement en réduisant les E/S physiques.

Task 8: Check if you’re CPU-bound or I/O-bound during a workload

cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.8.0 (server)  12/25/2025  _x86_64_  (16 CPU)

12:01:10 PM  CPU  %usr %nice %sys %iowait %steal %idle
12:01:11 PM  all  22.1  0.0   7.4    0.6    0.0  69.9
12:01:12 PM  all  78.5  0.0  12.0    0.3    0.0   9.2

Interprétation : Si les CPU sont saturés avec un faible iowait, vous êtes lié par le calcul (le chiffrement peut contribuer, mais la compression, les checksums, RAIDZ, ou l’application peuvent l’être aussi). Si l’iowait grimpe, le chemin de stockage est lent.

Task 9: Observe ZFS I/O behavior live

cr0x@server:~$ sudo zpool iostat -v tank 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        3.21T  6.78T  1.25K  2.10K   210M  355M
  raidz2    3.21T  6.78T  1.25K  2.10K   210M  355M
    sda         -      -    150    260  26.0M  44.3M
    sdb         -      -    155    265  26.5M  45.0M
    ...

Interprétation : Cela vous indique si le pool est occupé et si la bande passante/IOPS correspondent aux attentes. Si le chiffrement « vous a ralenti », vous devriez vérifier si vous saturez les disques, pas deviner.

Task 10: Verify feature flags and compatibility (replication sanity check)

cr0x@server:~$ zpool get all tank | egrep 'feature@|ashift'
tank  ashift                      12                     local
tank  feature@encryption          active                 local
tank  feature@edonr               active                 local

Interprétation : Vous avez besoin de fonctionnalités compatibles entre l’émetteur et le récepteur pour une réplication propre. Si le récepteur n’a pas le support du chiffrement, votre plan change (ou échoue).

Task 11: Confirm dataset key inheritance and avoid surprises

cr0x@server:~$ zfs get -r -o name,property,value,keylocation,encryption keylocation,encryption tank/app1
NAME            PROPERTY    VALUE          SOURCE
tank/app1       encryption  aes-256-gcm    local
tank/app1       keylocation file:///etc/zfs/keys/app1.key local
tank/app1/pgdata encryption aes-256-gcm    inherited from tank/app1
tank/app1/pgdata keylocation file:///etc/zfs/keys/app1.key inherited from tank/app1

Interprétation : L’héritage est votre ami—jusqu’au jour où il ne l’est pas. Confirmez toujours ce que font réellement les enfants avant de faire une rotation de clés ou de changer d’emplacement.

Task 12: Rotate an encryption key (operationally safe version)

C’est là que les équipes deviennent nerveuses, et elles le devraient. Vous devez planifier, snapshotter, et valider.

cr0x@server:~$ sudo dd if=/dev/urandom of=/etc/zfs/keys/app1-new.key bs=32 count=1 status=none
cr0x@server:~$ sudo chmod 0400 /etc/zfs/keys/app1-new.key

cr0x@server:~$ sudo zfs snapshot -r tank/app1@before-key-rotate
cr0x@server:~$ sudo zfs change-key -o keylocation=file:///etc/zfs/keys/app1-new.key tank/app1
cr0x@server:~$ zfs get -o name,property,value keylocation tank/app1
NAME      PROPERTY     VALUE
tank/app1 keylocation  file:///etc/zfs/keys/app1-new.key

Interprétation : Vous avez changé l’emplacement et le matériel de la clé d’enveloppe du dataset. Le snapshot est votre ancre de retour arrière. Ne supprimez pas l’ancienne clé tant que vous n’avez pas prouvé les chemins de reboot, de réplication et de restauration.

Task 13: Measure encryption impact with a controlled write test

cr0x@server:~$ sudo zfs create -o encryption=off -o compression=off tank/test-plain
cr0x@server:~$ sudo zfs create -o encryption=aes-256-gcm -o keyformat=raw -o keylocation=file:///etc/zfs/keys/app1.key -o compression=off tank/test-enc

cr0x@server:~$ sync
cr0x@server:~$ dd if=/dev/zero of=/tank/test-plain/blob bs=1M count=4096 oflag=direct status=progress
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 4.8 s, 895 MB/s

cr0x@server:~$ dd if=/dev/zero of=/tank/test-enc/blob bs=1M count=4096 oflag=direct status=progress
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 5.1 s, 842 MB/s

Interprétation : C’est un instrument brutal, mais il vous donne un ordre de grandeur. Si le delta est énorme, vous êtes probablement limité par le CPU ou vous avez accidentellement changé plus d’une variable (compression, sync, recordsize, etc.).

Task 14: Confirm that the key is not accidentally world-readable

cr0x@server:~$ ls -l /etc/zfs/keys/app1.key
-r-------- 1 root root 32 Dec 25 11:58 /etc/zfs/keys/app1.key

Interprétation : Si ce fichier est lisible par des utilisateurs non-root, vous avez transformé le « chiffrement au repos » en « chiffrement avec snacks ». Verrouillez-le.

Trois mini-histoires du monde corporate

Mini-histoire n°1 : L’incident causé par une mauvaise hypothèse

Ils ont chiffré les datasets sur l’hôte de stockage principal et sont partis chez eux en se sentant responsables. La fenêtre de changement était propre ; l’application est restée en ligne ; la performance semblait à peu près inchangée. L’hypothèse de l’équipe était simple : « si le dataset existe, systemd le montera comme avant ».

Puis est venu une mise à jour du noyau de routine. Reboot. L’hôte est revenu, la supervision indiquait l’OS en ligne, SSH fonctionnait, et la moyenne de charge était suspectement calme. Mais l’application était en panne. Le point de montage existait, vide et joyeux, et l’application a créé un nouvel arbre de répertoires sur le filesystem racine. C’était une de ces pannes qui ne ressemble pas à une panne jusqu’à ce que vous remarquiez que votre base de données fait soudainement 200 Mo et est toute neuve.

La cause racine n’était pas que ZFS soit sournois. C’était le graphe de services. Le dataset chiffré exigeait zfs load-key avant le montage ; la clé était configurée pour demander un prompt, et personne n’était là pour la taper. Le système a démarré « correctement », juste sans les données. L’application n’a pas échoué immédiatement parce que le point de montage existait. Elle a écrit au mauvais endroit et rendu la récupération plus difficile.

La correction a été ennuyeuse et efficace : ils ont fait du montage du dataset une dépendance ferme, ajouté une vérification au démarrage qui refusait de lancer l’application si le dataset n’était pas monté, et ils ont adapté la gestion des clés pour que le dataset corresponde à la réalité (soit déverrouillage manuel avec une étape on-call explicite, soit déverrouillage automatisé avec des contrôles forts sur l’hôte). Ils ont aussi ajouté un garde-fou : un petit fichier sur le dataset que l’application vérifie au démarrage. S’il n’est pas présent, elle refuse de tourner.

La leçon : le chiffrement casse rarement la performance en premier. Il casse d’abord les hypothèses.

Mini-histoire n°2 : L’optimisation qui a mal tourné

Une autre équipe a décidé « d’optimiser » le surcoût du chiffrement en désactivant la compression—sur la théorie que la compression brûle du CPU, et le chiffrement brûle du CPU, donc supprimer la compression économiserait des cycles. C’était beau sur une slide.

En réalité, la compression portait leur charge. Ils stockaient beaucoup de logs textuels, du JSON, et des images VM avec de grandes régions initialisées à zéro. Sans compression, leurs écritures physiques ont augmenté dramatiquement, ce qui a poussé le pool dans une latence soutenue. Les fenêtres de réplication ont augmenté. La cible de sauvegarde a commencé à prendre du retard. Soudain ils faisaient du capacity planning d’urgence parce que « le chiffrement a tout rendu plus grand ». Ce n’était pas le chiffrement—désactiver la compression l’était.

Puis la situation s’est aggravée : l’équipe a essayé de compenser en augmentant recordsize partout pour « réduire l’overhead ». Cela a aidé les écritures séquentielles larges, mais a puni les mises à jour aléatoires et le churn de métadonnées. Quelques services sensibles à la latence de queue (une petite base OLTP et une file) ont commencé à timeouter sous charge. La revue d’incident a été sévère, surtout parce que le changement était fait sous la bannière « sécurité », donc personne ne voulait le questionner jusqu’à ce que la production le fasse.

La récupération a été classique : ils sont revenus à compression=lz4, ont ajusté recordsize par dataset, et ont arrêté de traiter « overhead CPU » comme un seul et même poste. Le chiffrement n’était pas le méchant ; l’optimisation non mesurée l’était.

Mini-histoire n°3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Celle-ci est moins dramatique, ce qui est précisément le point. Un système lié à la finance (données sensibles, contrainte réglementaire) avait le chiffrement natif ZFS avec des datasets par application. La pratique de l’équipe était résolument ennuyeuse : chaque rotation de clé avait un runbook, chaque dataset avait une méthode de déverrouillage documentée, et trimestriellement ils testaien une restauration bare-metal dans un environnement isolé.

Un après-midi une baie de stockage a souffert d’une panne de contrôleur qui a nécessité l’envoi de pièces et le déplacement temporaire des workloads. L’équipe a décidé de basculer vers un hôte de secours. Le standby avait des snapshots répliqués, mais n’avait jamais vraiment été utilisé en conditions réelles. C’est là que la plupart des plans DR meurent.

La bascule a fonctionné—non pas parce que ZFS est magique, mais parce que l’équipe avait répété la gestion des clés. Ils ont chargé les clés dans le bon ordre, confirmé les montages, vérifié que le flux de réplication restait chiffré, et n’ont démarré les services qu’après confirmation des datasets. Ils n’ont pas découvert de fichiers clés manquants, de propriétés mismatched, ou de problèmes d’ordre de montage mystérieux. Tous ces problèmes avaient été résolus des mois plus tôt lors d’un test trimestriel ennuyeux que personne ne voulait vraiment suivre.

Quand le post-mortem est arrivé, c’était presque décevant : pas d’exploits héroïques, pas de hacks de minuit, pas de « on a copié des clés depuis une capture d’écran ». Juste une checklist, exécutée. À mon avis, c’est le plus grand compliment qu’on puisse faire à un système de stockage chiffré : il bascule comme s’il n’était pas chiffré du tout.

Mode opératoire de diagnostic rapide

Voici la séquence que j’utilise quand quelqu’un dit : « Après avoir activé le chiffrement ZFS, la performance est mauvaise. » L’objectif est de trouver rapidement la contrainte dominante, pas de débattre de la crypto sur le principe.

Première étape : confirmer ce qui a changé (et isoler les variables)

  1. Vérifiez l’état du chiffrement et les propriétés sur les datasets affectés : algorithme, compression, recordsize, réglages sync, logbias.
  2. Confirmez que les clés sont chargées et que les datasets sont montés (les problèmes de disponibilité se déguisent souvent en « performance »).
  3. Vérifiez si la charge a aussi changé : nouvelle version d’app, pattern d’I/O différent, horaire de réplication modifié.
cr0x@server:~$ zfs get -o name,property,value -r encryption,compression,recordsize,sync,logbias tank/app1
NAME              PROPERTY     VALUE
tank/app1          encryption   aes-256-gcm
tank/app1          compression  lz4
tank/app1          recordsize   128K
tank/app1          sync         standard
tank/app1          logbias      latency
tank/app1/pgdata   encryption   aes-256-gcm
tank/app1/pgdata   compression  lz4
tank/app1/pgdata   recordsize   16K
tank/app1/pgdata   sync         standard
tank/app1/pgdata   logbias      latency

Deuxième étape : décider CPU-bound vs I/O-bound

  1. Regardez l’utilisation CPU et l’iowait pendant le ralentissement.
  2. Si le CPU est élevé et l’iowait faible : vous êtes limité par le calcul (le chiffrement peut contribuer, mais la compression/checksums/RAIDZ/app aussi).
  3. Si l’iowait est élevé : la latence de stockage est le goulot ; vérifiez le SLOG, la santé des vdevs, la fragmentation, la profondeur de queue, et la charge sync.
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  0      0 821220  88048 7340120   0    0   512  1024  980 2200 22  8 69  1  0
 9  2      0 780112  88120 7310040   0    0  4096  8192 1400 3400 55 15 10 20  0

Troisième étape : vérifier le comportement du pool ZFS et les indices de latence

  1. zpool iostat -v pour voir si les disques sont saturés ou déséquilibrés.
  2. zpool status pour exclure resilvers, erreurs de checksum, ou vdevs dégradés.
  3. Si sync-heavy : validez le SLOG et ses caractéristiques de latence.
cr0x@server:~$ sudo zpool status -x
all pools are healthy

Quatrième étape : valider le chemin de la charge (sync, petits writes, tempêtes de métadonnées)

Si l’app fait des écritures sync et que vous n’avez pas de vrai SLOG (ou qu’il est lent), c’est votre premier suspect. Si l’app est heavy en métadonnées (des millions de petits fichiers), le chiffrement peut augmenter la pression CPU, mais le problème majeur est généralement le chemin IOPS, pas le cipher.

Erreurs courantes, symptômes, corrections

Mistake 1: Encrypting “everything” without dataset boundaries

Symptôme : La rotation des clés devient terrifiante ; la réplication et la restauration sont fragiles ; le dépannage ressemble à « quelle clé déverrouille quoi ? »

Correction : Refactorez en datasets par application/locataire. Utilisez l’héritage pour réduire la dérive de configuration. Documentez quels datasets partagent des clés et pourquoi.

Mistake 2: Assuming encrypted datasets mount automatically after reboot

Symptôme : Après reboot, les services démarrent mais les chemins de données sont vides ; les applications créent de nouvelles données sur le filesystem racine ; comportement de « fresh install » étrange.

Correction : Assurez-vous que les clés se chargent au démarrage (ou exigez un déverrouillage manuel explicite), et faites dépendre les services des montages. Ajoutez des fichiers de garde/vérifications pour que les apps échouent rapidement si le dataset réel n’est pas monté.

Mistake 3: Turning off compression to “save CPU for encryption”

Symptôme : Bande passante du pool en pic, latence en hausse, fenêtres de réplication qui s’allongent, consommation de capacité accélérée.

Correction : Réactivez compression=lz4 et mesurez. Si le CPU est vraiment le goulot, scalez le CPU ou ajustez la charge ; ne compensez pas l’amplification I/O pour un gain CPU théorique.

Mistake 4: Treating recordsize as a universal knob

Symptôme : Les bases de données timeout après l’« optimisation », ou le stockage VM devient instable ; l’amplification d’écriture augmente.

Correction : Définissez le recordsize par dataset selon la charge. Gardez un recordsize large pour les données séquentielles ; réduisez-le pour les charges à mises à jour aléatoires.

Mistake 5: Using passphrases for unattended servers without a plan

Symptôme : Le reboot exige un accès console ; le basculement DR stagne ; l’on-call cherche la seule personne qui « connaît la passphrase ».

Correction : Engagez-vous soit à un déverrouillage manuel avec procédures et personnel explicites, soit utilisez des clés raw avec distribution contrôlée et protections OS strictes. L’hybride est courant : auto-unlock pour les datasets non critiques, unlock manuel pour les joyaux.

Mistake 6: Misunderstanding replication semantics with encryption

Symptôme : Les jobs de réplication échouent, ou les données arrivent décryptées sur le récepteur, ou les restaurations exigent des clés que vous n’avez pas conservées.

Correction : Testez les modes send/receive en labo avec des versions/fonctionnalités qui correspondent à la prod. Confirmez les propriétés du récepteur et la disponibilité des clés. Maintenez un processus d’entiercement des clés conforme à la compliance.

Mistake 7: Leaving key files readable or backed up casually

Symptôme : Constats d’audit, ou pire : des backups « chiffrés » sont déchiffrables parce que les clés sont dans le même jeu de sauvegarde.

Correction : Faites appliquer les permissions, isolez le stockage des clés, et décidez explicitement si les clés sont sauvegardées et où. Si les clés sont sauvegardées, protégez cette sauvegarde comme les données—parce que c’est le cas.

Checklists / plan pas à pas

Checklist A: Rolling out ZFS encryption safely (greenfield or retrofit)

  1. Définissez le modèle de menace : disques volés, hôtes volés, compromission du domaine de sauvegarde, etc.
  2. Choisissez les frontières des datasets : par app/locataire, sauvegardes séparées, archives séparées.
  3. Sélectionnez la stratégie de clés : fichiers clefs raw pour l’automatisation vs passphrases pour le déverrouillage manuel ; décidez par classe de dataset.
  4. Définissez les propriétés de base : compression=lz4, atime=off, recordsize selon la charge, sync/logbias selon besoin.
  5. Créez les datasets et migrez les données avec un plan réversible (snapshots avant et après).
  6. Mettez à jour l’ordre de démarrage et des services : clés chargées, puis montage, puis services. Ajoutez des garde-fous de montage.
  7. Testez la réplication : workflows routiniers et de restauration, y compris la disponibilité des clés en DR.
  8. Effectuez des tests de charge : tests contrôlés plus un canari de charge réelle.
  9. Documentez et répétez : la rotation des clés et la restauration doivent être pratiquées, pas seulement écrites.

Checklist B: Performance tuning sequence (don’t tune blind)

  1. Mesurez CPU vs I/O pendant la période lente (mpstat/vmstat + zpool iostat).
  2. Confirmez que la compression est activée sauf preuve du contraire.
  3. Validez que recordsize correspond aux patterns de la charge.
  4. Vérifiez le chemin d’écriture sync et l’adéquation du SLOG si applicable.
  5. Confirmez la santé du pool et excluez les opérations de fond (resilver/scrub).
  6. Ce n’est qu’alors que vous devriez envisager le « surcoût du chiffrement » comme cause principale—et si oui, validez les capacités CPU et les contraintes de virtualisation.

Checklist C: Key rotation drill (the version that won’t ruin your weekend)

  1. Snapshot des datasets concernés (@before-key-rotate).
  2. Générez et mettez en place les permissions du nouveau matériel de clé.
  3. Changez la clé sur un dataset non critique d’abord (canari), puis procédez.
  4. Rebootez un hôte standby ou testez le flux mount/unlock pour assurer l’automatisation.
  5. Validez la réplication et la restauration avec la nouvelle clé.
  6. Retirez les anciennes clés seulement après avoir prouvé la restauration des snapshots qui en dépendent (si applicable).

FAQ

1) Is ZFS native encryption “full disk encryption”?

Non. C’est un chiffrement au niveau du dataset. Certaines métadonnées du pool restent visibles. Si vous avez besoin de « tout, y compris swap et boot, chiffrés », vous pouvez toujours combiner des stratégies (par exemple, chiffrement OS pour le volume root + chiffrement dataset ZFS pour les données).

2) Should I use ZFS encryption or LUKS?

Ils résolvent des problèmes opérationnels différents. LUKS chiffre des périphériques bloc (frontière simple, large compatibilité OS). Le chiffrement natif ZFS chiffre des datasets (frontières granulaires, aware snapshots/replication). Si vous avez besoin de clés par dataset et de sémantiques de réplication chiffrée, le chiffrement natif ZFS est l’outil. Si vous voulez un modèle « déverrouillez le disque », LUKS peut être plus simple.

3) Does encryption break compression?

Non—ZFS compresse avant de chiffrer. La compression reste efficace et fait souvent la différence entre « le chiffrement passe » et « pourquoi n’avons-nous plus d’IOPS ? »

4) Will encryption slow down my database?

Ça peut, mais les facteurs plus importants sont souvent la latence d’écriture sync, un recordsize mal adapté, et la conception du pool. Si vous êtes déjà proche des limites CPU, le chiffrement peut vous pousser au-delà. Mesurez CPU vs iowait et ajustez les propriétés du dataset pour la charge base de données.

5) Can I replicate encrypted datasets without exposing plaintext to the backup server?

Dans beaucoup de déploiements OpenZFS, oui—des workflows send/receive chiffrés bruts existent où le récepteur stocke des blocs chiffrés sans avoir besoin des clés. Vous devez valider le support des fonctionnalités et tester les restaurations. Ne supposez pas que vos versions émetteur/récepteur se comportent identiquement.

6) What happens if I lose the key?

Vous perdez les données. Il n’y a pas de « backdoor ». C’est le but et le risque. Si votre entreprise ne peut pas tolérer cela, vous avez besoin d’une stratégie d’entiercement des clés avec contrôles stricts et tests périodiques de restauration.

7) Should keys live on the same host as the data?

Parfois, oui—surtout pour des systèmes qui doivent redémarrer sans intervention. Mais vous échangez la protection « disques volés » contre le risque « hôte compromis ». Si un hôte est compromis et que le fichier clé est accessible, l’attaquant peut lire les données. Utilisez le hardening de l’hôte, des permissions restreintes, et envisagez le déverrouillage manuel pour les datasets les plus sensibles.

8) Can I encrypt an existing dataset in place?

Pas par un simple flip de propriété. En pratique, les équipes créent un nouveau dataset chiffré et migrent les données (souvent avec snapshots et envois incrémentaux). Planifiez un workflow de migration et testez le rollback.

9) Does encryption affect scrubs and resilvers?

Les scrubs et resilvers lisent et vérifient toujours les données ; le chiffrement ajoute du travail CPU pour le déchiffrement/l’authentification quand c’est applicable. Dans beaucoup de systèmes, le débit disque reste le limitant, mais sur des hôtes contraints en CPU vous pouvez voir des fenêtres de maintenance plus longues.

10) What’s the single best way to avoid “encryption killed performance” incidents?

Ne changez pas plusieurs choses à la fois. Changez une variable à la fois, gardez compression=lz4 par défaut, ajustez recordsize par charge, et utilisez le mode opératoire de diagnostic rapide pour prouver si vous êtes lié CPU ou I/O.

Conclusion

Le chiffrement natif ZFS est une de ces rares fonctionnalités de sécurité qui peuvent être déployées pragmatiquement : par dataset, avec des performances prévisibles, et des sémantiques de réplication qui respectent réellement la manière dont le stockage est utilisé dans les entreprises. L’inconvénient est qu’il déplace le risque de « données sur disques » vers « clés et opérations ». Ce n’est pas un défaut—c’est tout le jeu.

Si vous voulez une sécurité forte sans sacrifier les performances, traitez le chiffrement comme partie intégrante de la conception système : alignez les frontières des datasets sur les frontières de confiance, laissez la compression activée sauf preuve du contraire, ajustez recordsize par charge, et faites du chargement des clés et du montage une partie de première classe du démarrage et du DR. Quand vous faites cela, le chiffrement devient la partie la moins intéressante de la pile de stockage—exactement là où vous le voulez.

← Précédent
Cases à cocher et boutons radio personnalisés en pur CSS : modèles accessibles qui ne trompent pas
Suivant →
Debian 13 : fuites mémoire dans les services — détecter avec un minimum de perturbations (cas n°43)

Laisser un commentaire