Chiffrement du filesystem en auto-hébergement

J’ai investigué quelques solutions pour chiffrer le filesystem de mes serveurs auto-hébergés. En prenant notamment en compte leurs contraintes particulières : pas d’accès « console » simple, faible puissance et filesystem sur carte SD.

Sommaire

Première solution : chiffrer entièrement le filesystem

Avec dm-crypt / cryptsetup + LUKS, comme proposé par Debian (ou Ubuntu) lors de l’installation.

Cela chiffre également la partition système. C’est clairement le plus sûr, car tout est chiffré.

Saisie de la phrase de passe à distance

Mais cela pose la contrainte de saisir la phrase de passe au démarrage. Or je peux avoir besoin de le faire à distance (après une coupure de courant par exemple). Et il s’agit de machines physiques, pour lesquelles l’accès console requiert une branchement physique dessus…

Dropbear

Heureusement, il est possible de le faire à distance, via un serveur SSH simple (Dropbear), qui se lance suffisamment tôt dans la séquence de démarrage pour être accessible lors de la demande de saisie de phrase de passe.

Source : zcat /usr/share/doc/cryptsetup/README.remote.gz

En résumé, il s’agit de :

  • installer les paquets dropbear et busybox
  • copier les clés SSH publiques des machines qui pourront s’y connecter dans /etc/initramfs-tools/root/.ssh/authorized_keys
  • puis mettre à jour le initramfs avec sudo update-initramfs -u

Ensuite on peut s’y connecter depuis l’extérieur avec un script du type :

#!/bin/bash
echo -n "Quel serveur? "
read serveur
echo -n "Quelle phrase de passe? "
read -s passphrase
ssh -o "UserKnownHostsFile=~/.ssh/known_hosts.initramfs" root@$serveur "echo -ne \"$passphrase\" >/lib/cryptsetup/passfifo"

(NB : noter l’utilisation d’un fichier known_hosts à part, pour éviter que le client SSH ne soit perturbé par le fait qu’un même serveur puisse avoir 2 clés publiques SSH différentes : une avec OpenSSH, l’autre avec Dropbear)

Petit risque de sécurité : la clé privée du serveur Dropbear est (forcément) stockée en clair sur la machine. Quelqu’un qui aurait eu accès au filesystem pourrait ainsi se faire passer pour le serveur qui aurait redémarré, et intercepter la phrase de passe.

Déchiffrement de plusieurs partitions d’un coup

La procédure décrite ci-dessus fonctionne bien s’il n’y a que la partition système à déchiffrer.

Mais, sur mes machines auto-hébergées, j’utilise fréquemment plusieurs partitions sur des devices différents (cartes SD ou microSD, clé USB, voire disque dur). Si je les chiffre et qu’elles sont montées au démarrage, le serveur demande la phrase de passe sur la console, après avoir demandé celle du filesystem principal. Donc il faut ruser un peu pour pouvoir les déchiffrer toutes d’un coup, et à distance.

Normalement, il y a un script decrypt_derived qui fait ça très bien : http://unix.stackexchange.com/questions/110081/decrypt-second-encrypted-lvm-during-headless-server-boot

… sauf qu’il ne fonctionne pas sur Debian Jessie (à cause de systemd d’après ce que j’ai compris) : https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=618862)

Bref, il y a une autre solution (clairement moins sécurisée), qui consiste à mettre dans la partition système (chiffrée) un fichier de clé qui permet de déverrouiller les autres. Évidemment, il faut protéger l’accès à ce fichier.

Création du fichier de clé (avec un contenu aléatoire) :

sudo dd if=/dev/urandom of=/etc/keyfile bs=1024 count=4
sudo chmod 0400 /etc/keyfile

Ajout de ce fichier de clé dans les clés acceptées par la partition chiffrée :

sudo cryptsetup luksAddKey /dev/mmcblk1p1 /etc/keyfile

Ajout de la partition dans /etc/crypttab avec une ligne du type :

nom_2eme_partition_chiffree UUID=uuid_de_la_partition /etc/keyfile luks

(et il faut classiquement rajouter la partition dans /etc/fstab)

Pour plus de détail : http://ubuntuforums.org/showthread.php?t=837416

Autres difficultés

Certains appareils fournissent une image Debian toute prête (et customisée) de l’OS, et on ne peut pas toujours utiliser son installeur. Notamment si l’appareil n’est pas encore complètement supporté par le noyau linux. Il est alors plus compliqué de chiffrer le filesystem root après coup. Heureusement, ce n’est pas les cas de mes machines.

Mais, dans mon cas personnel, il y a un autre petit soucis : je n’ai pas toujours accès à un client SSH :

  • soit parce que je suis derrière un proxy HTTP d’entreprise qui ne laisse pas passer le SSH (à l’occasion j’investiguerai SSLH, merci à Genma pour l’idée : http://genma.free.fr/?SSH-derriere-un-proxy-Sslh)
  • soit parce que mon téléphone (sous Firefox OS) n’a pas de client SSH

Pour toutes ces raisons, on peut avoir besoin d’une autre solution :

Deuxième solution : chiffrer uniquement une partition de données

C’est clairement moins sûr, mais peut fonctionner sur n’importe quel Linux déjà installé. Et surtout, après un redémarrage, on peut directement avoir accès aux services qui n’utilisent pas la partition chiffrée (AJaxterm, par exemple, patché comme dans un précédent article).

Si les données chiffrées sont accédées par un service lancé au démarrage (ex: MySQL), il échouera avec des messages d’erreur au démarrage. Il faut donc ensuite se connecter en SSH, monter manuellement la partition chiffrée (en saisissant sa phrase de passe), puis redémarrer les services qui ont besoin de l’être. Exemple :

sudo cryptsetup luksOpen /dev/nom_device_partition partition_chiffree
sudo mount /dev/mapper/partition_chiffree /mnt/partition_chiffree
sudo systemctl restart mysql

Sauvegardes

Faire des sauvegardes régulières est toujours indispensable, quel que soit le contexte.

Mais, en l’occurrence, quand on utilise des partitions chiffrées, il y a une sauvegarde supplémentaire à faire : les entêtes LUKS de la partition, qui peuvent être extrêmement précieuses. Si ces quelques octets sont corrompus sur le filesystem, il serait complètement impossible d’accéder aux données.

Pour sauvegarder :

sudo cryptsetup luksHeaderBackup --header-backup-file luksHeaderBackup-nom_device_partition /dev/nom_device_partition

Performances

Les machines qui hébergent mes services sont des petites machines à très faible consommation. Donc la puissance CPU a besoin d’être économisée.

L’impact du chiffrement sur les performances mérite donc d’être surveillé. Pour cela, l’accélération matérielle du chiffrement peut rendre service.

Accélération matérielle du chiffrement

  • La Sheevaplug est le matériel le plus ancien et le moins puissant. Par contre, l’accélération matérielle du chiffrement est bien supportée par le noyau linux (depuis la version 2.6.32 a priori)
  • L’Olinuxino A20 est plus puissant, mais la prise en charge du chiffrement matériel dans le noyau linux est plus récente : il faut au minimum un noyau 4.3. Cf http://sunxi.montjoie.ovh/

Mes serveurs tournent sur Debian Jessie (noyau Linux 3.16 par défaut) donc pas de problèmes pour la Sheevaplug, mais il faudrait mettre à jour le noyau sur Olinuxino A20 pour avoir l’accélération matérielle. Je préférerais éviter car ça obligerait ensuite à le mettre à jour manuellement quand il y a des failles de sécurité.

Quoi qu’il en soit, pour que l’accélération matérielle du chiffrement fonctionne, il faut à la fois que le logiciel utilisé sache l’exploiter, et qu’il utilise un algorithme supporté par le matériel. D’où l’importance de vérifier :

Performances brutes du chiffrement

Sur Sheevaplug

Avec une installation par défaut

cryptsetup benchmark sur Sheevaplug (Debian Jessie, noyau 3.16.0-4-kirkwood) :

 PBKDF2-sha1        64503 iterations per second
 PBKDF2-sha256      48188 iterations per second
 PBKDF2-sha512       5665 iterations per second
 PBKDF2-ripemd160   56109 iterations per second
 PBKDF2-whirlpool    4768 iterations per second
 #  Algorithm | Key |  Encryption |  Decryption
     aes-cbc   128b    20.4 MiB/s    20.9 MiB/s
 serpent-cbc   128b    10.8 MiB/s    11.8 MiB/s
 twofish-cbc   128b    12.4 MiB/s    13.3 MiB/s
     aes-cbc   256b    19.6 MiB/s    19.9 MiB/s
 serpent-cbc   256b    11.4 MiB/s    11.8 MiB/s
 twofish-cbc   256b    12.9 MiB/s    13.3 MiB/s
     aes-xts   256b    13.9 MiB/s    13.9 MiB/s
 serpent-xts   256b    11.7 MiB/s    11.8 MiB/s
 twofish-xts   256b    13.1 MiB/s    13.3 MiB/s
     aes-xts   512b    11.0 MiB/s    10.9 MiB/s
 serpent-xts   512b    11.9 MiB/s    11.8 MiB/s
 twofish-xts   512b    13.4 MiB/s    13.3 MiB/s

L’algorithme CBC est bien plus rapide que les autres sur cette machine. Certainement parce que c’est le seul de la liste qui est accéléré matériellement, ce qui semble confirmé par un cat /proc/crypto : certains algorithmes sont implémentés par un driver mv-* (mv comme Marvell, je suppose : le fabricant du microprocesseur) :

$ cat /proc/crypto | grep mv-
driver : mv-cbc-aes
driver : mv-cbc-aes
driver : mv-ecb-aes

Pas de bol : par défaut, cryptsetup utilise l’algorithme aes-xts. Donc si on installe Debian avec chiffrement, il n’est (par défaut) pas accéléré matériellement sur cet appareil…

En spécifiant l’algorithme AES-CBC

Heureusement, on peut choisir l’algorithme de chiffrement (cipher) lors de l’installation. Sauf qu’il faut pour cela faire un partitionnement complètement manuel : créer la partition chiffrée, le LVM dedans, et les deux partitions root et swap à l’intérieur. On ne peut hélas pas demander à l’installeur un partitionnement automatique, puis revenir le modifier (pour être précis : si, on peut. Mais il refuse de modifier la partition chiffrée, donc ça ne nous sert à rien en l’occurrence).

Bref, en partitionnant manuellement, on peut utiliser l’un des algorithmes aes-cbc-essiv:sha256 ou aes-cbc-plain.

Sauf qu’une faiblesse a été trouvée dans cet algorithme CBC : voir paragraphe 5.14 de https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions.

Sur Olinuxino A20

cryptsetup benchmark avec l’image Debian Jessie fournie par le fabricant (3.4.103-00033-g9a1cd03-dirty) :

PBKDF2-sha1        86231 iterations per second for 256-bit key
PBKDF2-sha256      60681 iterations per second for 256-bit key
PBKDF2-sha512      28006 iterations per second for 256-bit key
PBKDF2-ripemd160   80908 iterations per second for 256-bit key
PBKDF2-whirlpool    6869 iterations per second for 256-bit key
#  Algorithm | Key |  Encryption |  Decryption
     aes-cbc   128b    14.9 MiB/s    16.4 MiB/s
 serpent-cbc   128b    11.3 MiB/s    12.9 MiB/s
 twofish-cbc   128b    17.5 MiB/s    19.5 MiB/s
     aes-cbc   256b    12.3 MiB/s    12.8 MiB/s
 serpent-cbc   256b    11.7 MiB/s    13.0 MiB/s
 twofish-cbc   256b    17.8 MiB/s    19.5 MiB/s
     aes-xts   256b    16.1 MiB/s    16.3 MiB/s
 serpent-xts   256b    11.9 MiB/s    12.7 MiB/s
 twofish-xts   256b    18.0 MiB/s    18.5 MiB/s
     aes-xts   512b    12.3 MiB/s    11.9 MiB/s
 serpent-xts   512b    11.8 MiB/s    12.3 MiB/s
 twofish-xts   512b    18.1 MiB/s    18.6 MiB/s

/proc/crypto ne semble indiquer aucun driver matériel.

Avec le noyau de l’installeur de Jessie (3.16.0-4-armmp-lpae), les résultats sont similaires.

Avec un noyau 4.4.1 patché (cf mon autre article), on peut exploiter l’accélération matérielle :

PBKDF2-sha1        80908 iterations per second for 256-bit key
PBKDF2-sha256      57487 iterations per second for 256-bit key
PBKDF2-sha512      26425 iterations per second for 256-bit key
PBKDF2-ripemd160   76204 iterations per second for 256-bit key
PBKDF2-whirlpool    6527 iterations per second for 256-bit key
#  Algorithm | Key |  Encryption |  Decryption
     aes-cbc   128b    25.5 MiB/s    25.5 MiB/s
 serpent-cbc   128b           N/A           N/A
 twofish-cbc   128b           N/A           N/A
     aes-cbc   256b    25.4 MiB/s    25.4 MiB/s
 serpent-cbc   256b           N/A           N/A
 twofish-cbc   256b           N/A           N/A
     aes-xts   256b           N/A           N/A
 serpent-xts   256b           N/A           N/A
 twofish-xts   256b           N/A           N/A
     aes-xts   512b           N/A           N/A
 serpent-xts   512b           N/A           N/A
 twofish-xts   512b           N/A           N/A

et /proc/crypto indique bien des drivers adaptés au matériel :

$ cat /proc/crypto | grep sun4i
driver : ecb-des3-sun4i-ss
driver : cbc-des3-sun4i-ss
driver : ecb-des-sun4i-ss
driver : cbc-des-sun4i-ss
driver : ecb-aes-sun4i-ss
driver : cbc-aes-sun4i-ss
driver : sha1-sun4i-ss
driver : md5-sun4i-ss

Comme sur Sheevaplug, on peut utiliser le CBC, mais pas le XTS. Par contre, le CBC accéléré apporte sur le papier un gain de performance notable.

Hélas, je n’ai pas eu le temps d’aller au bout de la mise en œuvre de cette accélération matérielle sur Olinuxino A20 (il doit me manquer des options de compilation du noyau qui permettent l’utilisation réelle par dm-crypt). Tant pis, sur les Olinuxino A20, j’en bénéficierai avec la prochaine version de Debian.

Performances réelles

Les services que je fais tourner sur mes machines ne font que très peu d’I/O disques. Donc je n’ai pas vu de différence par rapport au filesystem non chiffré. Il est probable qu’il y ait une différence sur le temps de démarrage, mais ça n’a pas grande importance dans mon contexte (machines allumées 24h/24).

J’ai commencé quelques mesures en AES-CBC : sur Sheevaplug, j’atteins autour de 10Mo/s en écriture (mais le chiffrement consomme 80% de CPU malgré l’accélération matérielle). Sur Olinuxino A20, 18Mo/s (sans accélération matérielle, mais il utilise 100% des 2 coeurs du CPU).

Alors que, sans chiffrement, j’atteins 30Mo/s (en USB2, avec 30 à 40% d’utilisation du CPU) sur les 2 appareils.

Si je trouve un peu de temps, je ferai des mesures plus complètes dans un autre article.

Conclusion dans mon cas particulier

On voit bien qu’il n’y a pas de solution universelle. Tout est affaire de compromis entre les contraintes qu’on veut accepter (dépannage à distance, complexité d’installation/administration), l’exigence de sécurité (chiffrement ou pas de tout le filesystem, avec quel algorithme), et les performances (vitesse des I/Os disque, consommation de CPU). Et cela peut dépendre de l’appareil au niveau de l’accélération matérielle du chiffrement.

Dans mon cas de figure, il me paraissait crucial de pouvoir dépanner mes serveurs à distance (après une coupure de courant, par exemple), et sans devoir passer par un client SSH. Quitte à faire des (petits) compromis sur la sécurité.

Donc j’ai chiffré tout les filesystems de mes serveurs sauf un, sur lequel tourne un nginx + ajaxterm (patché comme dans un précédent article), pour permettre de m’y logger en HTTPS (après saisie d’un login/mot de passe). Sur ce serveur, il y a plein d’autres services (Apache, notamment) dont la configuration et les données sont sur une partition chiffrée (non montée au démarrage). Donc, au démarrage, leur démarrage échoue. Ce n’est qu’après m’être loggé (via SSH ou Ajaxterm) que je déverrouille le filesystem, arrête nginx, et les relance. Et ensuite je peux déverrouiller tous les autres serveurs à travers lui, en SSH.

5 réflexions sur « Chiffrement du filesystem en auto-hébergement »

  1. Salut,

    Bon article, merci. J’ai prévu d’utiliser dropbear moi aussi.
    Par contre je ne vois pas pourquoi la clef est (forcément) en clair. Et sur quelle machine ? Le serveur ou le client qui veut déverrouiller le serveur ?
    Encore merci.

    Fabien

    1. Je parlais de la clé privée du serveur ssh dropbear (qui permet de déverrouiller à distance une partition système chiffrée). Elle est stockée dans l’initramfs du serveur, en général dans /boot, en tous cas en-dehors de la partition système chiffrée puisque cet initramfs a besoin d’être lu avant tout montage de filesystem.
      Donc cette clé privée de dropbear pourrait être récupérée par quelqu’un qui aurait eu un accès physique au filesystem (contrairement à la clé privée du serveur openssh lancé plus tard, puisqu’elle se trouve dans la partition chiffrée).
      Ca peut donner des pistes de piratage si cette clé est compromise (en se faisant passer pour ton dropbear, et en t’incitant à rentrer ta phrase de passe pour déverrouiller ton filesystem). Alors que, si on n’active pas ce dropbear, toute clé privée reste dans la partition chiffrée et ne peut donc pas être compromise par un accès physique au filesystem.
      Cela dit, on est déjà sur des scenario de piratage assez complexes à réaliser, je trouve.

    1. Merci!

      J’avais vu passer l’information du chiffrement intégré à ext4, mais je n’ai pas du tout testé pour l’instant.
      Dm-crypt fait tout ce dont j’avais besoin dans ce contexte, est éprouvé depuis longtemps et supporté par l’installeur, sait exploiter l’éventuelle accélération matérielle et est disponible dans le kernel par défaut de Debian Jessie.
      Cela dit, ce serait intéressant de voir ce que ça donne dans ext4. Il faudra que je jette un oeil.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *