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.
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
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.
Salute,
Sacré article, merci ! Pour info il a été remonté sur le Jdh : https://www.journalduhacker.net/s/pdf41c/chiffrement_du_filesystem_en_auto-h_bergement
Je n’ai pas encore regardé cela de plus près mais le chiffrement est pris en charge par ext4 depuis la version 4.1 du noyau (https://linuxfr.org/news/sortie-du-noyau-linux-4-1#ext4), tu as regardé ?
Merci, Tcho !
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.