date | 2024/07/31 18:03 |
---|---|
durée | 1/2 journée, voire plus, dépend des données |
temps de lecture | 15 minutes |
difficulté | ★★★★★ |
système | Raspberry PI 5 |
sous ubuntu 24.04 « Noble Numbat » | |
cible | sysadmins |
![]() | Sauvegarde complète nécessaire, tout peut être perdu ! |
Références | https://github.com/brutus-downunder/LUKS-on-Raspberry-Pi4/blob/main/index.md |
https://rr-developer.github.io/LUKS-on-Raspberry-Pi/ | |
https://www.kali.org/docs/arm/raspberry-pi-with-luks-full-disk-encryption-2/ | |
déverouiller un disque luks avec dropbear ssh | |
github : Générer une clé ssh et l'ajouter à l'agent | |
digital ocean: configurer une authentication par clé ssh |
Le raspberry pi 5 dispose d'instructions AES dans son processeur. Cela permet une accélération des opérations de chiffrement déchiffrement telle qu'on peut envisager sereinement d'utiliser un système chiffré. La seule partie qu'on ne peut pas chiffrer est la partition d'amorçage. L'EEPROM du pi ne sachant pas déchiffrer un disque, il faut bien amorcer la pompe à un moment… Mais ce n'est pas bien grave ; au pire qqu'un sait quel noyau vous utilisez.
Cet article décrit une méthode que j'ai mise au point en m'inspirant d'autres, merci donc à vous tous qui avez tenté l'opération avant moi. Je n'aurais pas osé sans vous.
Cet article donne en une seule lecture :
la méthode pour ajouter dropbear ssh dès la phase de boot, ce qui permet de déverrouiller le système chiffré via une connexion ssh, et donc d'avoir un PI sans tête, comprendre sans clavier ni écran
Cet article se concentre sur le chiffrement de la partition racine du système. Si vous avez d'autres disques, des disques de données, ou d'autres partitions sur votre système, ceux là ne seront pas chiffrés. C'est possible de les chiffrer, ça n'est pas bien difficile, mais ce n'est pas l'objet de cet article.
Je profite de cet article pour indiquer les performances relatives des carte raspberry PI 5 et 4 concernant le chiffrement.
sur un raspberry pi 5
root@rpi5:~ (0) # cryptsetup benchmark # Tests are approximate using memory only (no storage IO). PBKDF2-sha1 1134822 iterations per second for 256-bit key PBKDF2-sha256 2101354 iterations per second for 256-bit key PBKDF2-sha512 936228 iterations per second for 256-bit key PBKDF2-ripemd160 613920 iterations per second for 256-bit key PBKDF2-whirlpool 262144 iterations per second for 256-bit key argon2i 4 iterations, 638296 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time) argon2id 4 iterations, 636820 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time) # Algorithm | Key | Encryption | Decryption aes-cbc 128b 988.7 MiB/s 1638.5 MiB/s serpent-cbc 128b 70.7 MiB/s 79.9 MiB/s twofish-cbc 128b 115.9 MiB/s 122.3 MiB/s aes-cbc 256b 814.8 MiB/s 1396.8 MiB/s serpent-cbc 256b 72.8 MiB/s 80.0 MiB/s twofish-cbc 256b 120.0 MiB/s 122.2 MiB/s aes-xts 256b 1365.0 MiB/s 1365.2 MiB/s serpent-xts 256b 74.5 MiB/s 83.3 MiB/s twofish-xts 256b 126.4 MiB/s 129.2 MiB/s aes-xts 512b 1201.8 MiB/s 1203.1 MiB/s serpent-xts 512b 75.9 MiB/s 82.9 MiB/s twofish-xts 512b 128.2 MiB/s 129.2 MiB/s root@rpi5:~ (0) #
Sur un raspberry pi 4
root@rpi4:~ (0) # cryptsetup benchmark # Tests approximatifs en utilisant uniquement la mémoire (pas de stockage E/S). PBKDF2-sha1 248713 itérations par seconde pour une clé de 256 bits PBKDF2-sha256 416763 itérations par seconde pour une clé de 256 bits PBKDF2-sha512 224823 itérations par seconde pour une clé de 256 bits PBKDF2-ripemd160 201030 itérations par seconde pour une clé de 256 bits PBKDF2-whirlpool 57487 itérations par seconde pour une clé de 256 bits argon2i 4 itérations, 289342 mémoire, 4 threads parallèles (CPUs) pour une clé de 256 bits (temps de 2000 ms demandé) argon2id 4 itérations, 293225 mémoire, 4 threads parallèles (CPUs) pour une clé de 256 bits (temps de 2000 ms demandé) # Algorithme | Clé | Chiffrement | Déchiffrement aes-cbc 128b 65,9 MiB/s 86,5 MiB/s serpent-cbc 128b N/D N/D twofish-cbc 128b 24,0 MiB/s 61,5 MiB/s aes-cbc 256b 64,8 MiB/s 67,1 MiB/s serpent-cbc 256b N/D N/D twofish-cbc 256b 61,3 MiB/s 61,6 MiB/s aes-xts 256b 85,1 MiB/s 90,0 MiB/s serpent-xts 256b N/D N/D twofish-xts 256b 60,7 MiB/s 62,9 MiB/s aes-xts 512b 68,6 MiB/s 69,6 MiB/s serpent-xts 512b N/D N/D twofish-xts 512b 62,6 MiB/s 62,6 MiB/s root@rpi4:~ (0) #
1365.0 Mo/s soit plus de 1,3650 Go/s pour la PI 5 contre 85,1 Mo/s pour la PI 4. Cela est du aux instructions AES présentes dans le CPU de la PI 5 et absente de la PI 4.
root@rpi5:~ (0) # grep -e ^Feature -e ^BogoMIPS -e ^Model /proc/cpuinfo | tail -3 BogoMIPS : 108.00 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp Model : Raspberry Pi 5 Model B Rev 1.0 root@rpi5:~ (0) #
root@rpi4:~ (0) # grep -e ^Feature -e ^BogoMIPS -e ^Model /proc/cpuinfo | tail -3 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid Model : Raspberry Pi 4 Model B Rev 1.1 root@rpi4:~ (0) #
Le chiffrement sous Ubuntu/GNU Linux se fait via Luks. Il n'existe pas de méthode pour “activer” le chiffrement sur un système existant, contrairement à ce qui se fait sous macos avec Filevault ou Windows avec bitlocker, La méthode est grossière et consiste à :
Avec un peu de détails, ça donne ceci :
NB
Si vous voulez faire ça sur un PI neuf, commencez par installer ubuntu 24.04 (ou ultérieur) sur la carte micro SD, avec le logiciel Raspberry PI Imager. bootez une fois ou deux sur ce système, histoire de terminer rapidement sa configuration. N'en faites pas trop et n'ajoutez pas de paquets, ça ne ferait que rallonger cette procédure inutilement.
Il va falloir disposer du matériel suivant :
Côté logiciel, il faut :
J'ai réalisé ces opérations sur une carte Raspberry PI 5 avec
Dans toute la suite de cet article, /dev/mmcblk0
désigne la carte micro SD avec le système ubuntu GNU/Linux qu'on veut chiffrer ; et /dev/sda
désigne la clé USB avec le système temporaire. Adaptez les commandes à votre cas.
C'est parti !
Pour économiser mes petits doigts, et ne pas saisir sudo
toutes les deux lignes,
toutes les commandes shell sont passées sous le compte root.
donc, devenez root, immédiatement et complètement. par exemple avec
sudo -i
La commande id
doit vous répondre que vous êtes root
root@leia:~# id uid=0(root) gid=0(root) groups=0(root)
À l'aide du Raspberry PI Imager, j'installe le système officiel «Raspberry PI OS (64-bit)» sur une clé USB. Pourquoi un système différent ? Pour reconnaître facilement le système sur lequel je me trouve, et ne pas, par étourderie commettre de boulettes irréparables. Aussi, parce que c'est cool, qu'on est par défaut connecté avec une interface graphique légère et efficace, et que c'est le premier sur la liste.
Je retire la carte micro SD, je boote une ou deux fois sur la clé USB. Un coup de raspi-config
pour activer ssh, ça ne mange pas de pain et ça peut servir.
Comme je compte utiliser XFS et non pas ext4 sur le système chiffré, j'ajoute le paquet xfsprogs. Question de goûts personnels.
sudo apt-get install xfsprogs
-a
-H
-x
–numeric-ids
et des options de visualisation du progrès. Les options aHx
et numeric-ids
doivent être utilsées, pour le reste faites comme bon vous semble. Je copie tout dans /root/system.org
, car j'ai la place à cet endroit. Ça peut durer plus ou moins longtemps…install -d -m 0 /root/{system.org,initramfsunpacked.org} /mnt/{0..9} umount /dev/mmcblk0p1 2>/dev/null umount /dev/mmcblk0p2 2>/dev/null mount /dev/mmcblk0p2 /mnt/2 rsync -aHx --numeric-ids --info=progress2 /mnt/2/. /root/system.org/.
ummkinitramfs /mnt/1/initrd.img /root/initramfsunpacked.org
Pour l'instant, on va choisir une phrase de passe stupidement courte. Et également utiliser une lettre qui a le même emplacement quel que soit le clavier chargé (QWERTZ, QWERTY, AZERTY etc…). On pourra facilement changer la phrase de passe à la fin de cette procédure.
Je propose d'utiliser t
.
umount /dev/mmcblk0p2 cryptsetup luksFormat /dev/mmcblk0p2
Puis on ouvre et formate le volume chiffré. J'utilise le nom
crypted-root
, mais ce nom étant libre, utilisez ce que
bon vous semble.
cryptsetup luksOpen /dev/mmcblk0p2 crypted-root
Le volume chiffré est maintenant ouvert, et disponible pour la suite des opérations. Il est temps d'installer un système de fichier sur ce volume. Chacun fera comme il veut, j'aime bien XFS, mais utilisez ext4 si c'est votre système préféré.
mkfs.xfs -f /dev/mapper/crypted-root -L "racine pi 5"
On peut maintenant recopier le système d'origine sur la partition chiffrée
mount /dev/mapper/crypted-root /mnt/2
rsync -aHx --numeric-ids --info=progress2 /root/system.org/. /mnt/2/.
On ajuste alors sur la carte micro sd les fichiers de configuration suivants
/mnt/2/etc/crypttab
tries=0
offre un nombre infini d'essais d'ouverture du volume chiffré, ce qui nous rendra service quand on utilsera ssh pour ouvrir le volume. Pas question de se trouver bloqué au bout de trois tentatives infructueuses, avec un système distant qu'on ne peut même pas redémarrer.crypted-root /dev/mmcblk0p2 none luks,tries=0
crypted-root PARTUUID=0529037a-02 none luks,tries=0
NB
On détermine facilement l'uuid de partition correspondant à /dev/mmcblk0p2
, par exemple avec cette commande
ls -l /dev/disk/by-partuuid/ | awk '/mmcblk0p2/ { print $ (NF - 2) }'
/mnt/2/etc/fstab
/dev/mapper/crypted-root / xfs defaults 0 1
/mnt/1/cmdline.txt
root=…
et éventuellement, le système de fichiers rootfstype=…
console=serial0,115200 multipath=off dwc_otg.lpm_enable=0 console=tty1 root=/dev/mapper/crypted-root rootfstype=xfs rootwait fixrtc cfg80211.ieee80211_regdom=FR
/cryptroot/crypttab
dans l'arborescenceinstall -d -m 0 /tmp/remkinitrd rsync -aHx /root/initramfsunpacked.org/early/. /tmp/remkinitrd/. rsync -aHx /root/initramfsunpacked.org/main/. /tmp/remkinitrd/. cp /mnt/2/etc/crypttab /tmp/remkinitrd/cryptroot/crypttab
initrd.img
et le mettre en placecd /tmp/remkinitrd && find .r* * | cpio -o -H newc | gzip -9 >/tmp/new-initrd.img test -r /mnt/1/initrd.img.org || mv /mnt/1/initrd.img /mnt/1/initrd.img.org mv /tmp/new-initrd.img /mnt/1/initrd.img
On peut maintenant redémarrer. Le système va demander la phrase de passe
et on va répondre t
.
reboot
apt-get install dropbear-initramfs
rm /etc/dropbear/initramfs/dropbear_ecdsa_host_key
/etc/initramfs-tools/conf.d
indiquant l'IP, la passerelle, le masque de sous réseau et le nom d'hôte. Comme cette configuration réseau va persister, il faut également ajouter les serveurs DNS. Tout cela comme une déclaration de variable. Utilisez les valeurs qui conviennent à votre cas. On pourrait créer un fichier static-wired-ip.conf
contenant ceci :# Voir https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt IP=172.131.1.57::172.131.1.1:255.255.255.0:leia:::172.131.1.4:1.1.1.1:
authorized_keys
. Le format est le même que celui d'openssh, une clé par ligne. Voilà un exemple réel avec l'une de mes clésssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH7tTbt9XLZ0bOi4+dNFIFUv8cuM7/TphfnLfjuR58/q ma clé
Si vous n'y connaissez rien en clé ssh, je vous conseille d'utiliser des clés ed25519 et d'utiliser un agent. Deux liens sont dans les références de ce billet.
update-initramfs -c k $(uname -r) reboot
Tout doit toujours fonctionner.
Lorsque dropbear a terminé sa config, par défaut, il déconfigure l'interface réseau. Le module networking du boot va le réactiver de toute façons. C'est donc une bonne chose.
Mais, l'un des composants d'initramfs se dit « Tiens ! j'ai une configuration réseau, je vais donc générer un fichier /run/netplan/xxxx.yaml
pour que cette configuration soit reprise dans les phases suivantes. » FBI. Fausse Bonne Idée. Pour plusieurs raisons,
/etc/netplan
sera appliquée dans les étapes suivantes de boot. Et cette première configuration générée vient se mélanger et finalement prends le pas sur la configuration habituelle./etc/netplan
/etc/netplan
, et bien, on ne pourrait pas.
Pour ces raisons, je propose qu'on se débarrasse de la configuration générée. Il faut, à la fin de l'exécution des scripts d'initramfs, supprimer les fichiers de /run/netplan
.
La solution consiste à créer un fichier /etc/initramfs-tools/scripts/init-bottom/deconfnet
avec ce contenu :
#!/bin/sh PREREQ="dropbear" prereqs() { echo "$PREREQ" } case "$1" in (prereqs) prereqs exit 0 ;; esac rm -f /run/netplan/* >/dev/null || :
On se retrouve maintenant avec des clés ssh pour la phase de boot qui seront différentes des clés ssh d'openssh une fois la machine bootée. Pour éviter les problèmes de «Offending key…», on a deux solutions.
~/.ssh/config
sur son pc perso de connexion à la carte raspberry pi et on y ajoute une section concernant la carte raspberry pi en cours de boot. Mon pi s'appelle leia
, j'utilise le nom leiaboot
pour cette phase de boot.Host leiaboot user root Hostname 172.131.1.57
rm /etc/dropbear/initramfs/dropbear_*key dropbearconvert openssh dropbear \ /etc/ssh/ssh_host_ed25519_key \ /etc/dropbear/initramfs/dropbear_ed25519_host_key dropbearconvert openssh dropbear \ /etc/ssh/ssh_host_rsa_key \ /etc/dropbear/initramfs/dropbear_rsa_host_key
La deuxième chose à réaliser est que l'utilisation de ssh n'est pas la panacée. Si un ou une attaquante dispose d'un accès physique à la carte raspberry, elle peut tout à fait vous berner très facilement. Il suffit d'éteindre le pi et de déballer l'initrd. Ce dernier se trouve en effet sur une partition FAT non chiffrée. L'attaquante ou l'attaquant n'a plus qu'à placer ces clés sur une carte micro SD préparée à l'avance. Lorsque vous vous connecterez en ssh pour déverrouiller le disque, vous serez en fait connecté sur le système piégé. Il sera simplement impossible de s'en rendre compte, car ce système disposant alors de vos clés ssh répondra comme vous vous y attendez. Sauf qu'au lieu de déverrouiller votre disque chiffré, vous donnerez la clé de déchiffrement à l'attaquante, qui pourra alors inspecter votre disque sans problème.
On a mis t
comme phrase de passe, c'est pas terrible. Il est temps de
la changer. En manque d'inspiration ? Allez donc voir xkcd 936.
il faut utiliser
printf %s
, non pas echo, sinon la phrase de passe
contiendra un retour chariot qu'on ne peut pas saisir au clavier, puisqu'il valide la
saisie.
Changement de la phrase de passe. Dans l'expemple, la nouvelle phrase de passe
sera exact cheval pile agrafe
:
printf %s "exact cheval pile agrafe" >fichier-de-passe cryptsetup luksChangeKey /dev/mmcblk0p2 fichier-de-passe
Et encore un reboot. Ça passe ou ça casse. Si ça casse, tout est perdu, et il faut recommencer.
S'il advient malheur aux secteurs de l'en-tête luks de la partition chiffrée, alors cette partition est verrouillée à tout jamais, et devient aussi utile qu'une brique (ou un timbre poste, attendu qu'on parle ici d'une carte µSD).
On peut sauvegarder ces en-têtes. Il suffit d'en faire un vidage et de les mettre en sécurité qq part. Le fichier à une taille d'exactement 16 MiB.
Si un attaquant trouve le fichier contant le vidage d'en-tête, il va pouvoir commencer une attaque par force brute, comme s'il avait volé le disque. Comme le chiffrement est censé résister au moins plusieurs années à ce genre d'attaque, c'est pas si grave, mais pas super non plus. Ici s'arrêtent mes compétences concernant la résistance du chiffrement. Si ma copie de sauvegarde était divulguée, je rechiffrerais immédiatement le disque.
cryptsetup luksHeaderBackup /dev/mmcblk0p2 --header-backup-file luks-root-header
Et voilà, le fichier luks-root-header
contient une copie des entêtes. Ne reste
plus qu'à le mettre en sécurité.