Debian bookworm entièrement chiffrée avec LUKS2

De La Mouche VII
Révision datée du 21 septembre 2022 à 23:18 par Xiloynaha (discussion | contributions) (astuces)
Aller à la navigationAller à la recherche


Le but ici est d’installer une Debian "bookworm/sid" (été 2022) sur un disque entièrement chiffré, y compris /boot. Cela était possible depuis quelques années, mais la partition contenant le noyau devait obligatoirement être chiffrée avec LUKS1 (voir [1]). GRUB 2.06 a introduit le support initial de LUKS2, nous pouvons donc à présent profiter des améliorations de LUKS2 y compris pour /boot.

Je suppose ici un démarrage EFI, tout en essayant de documenter les paramètres nécessaires à un démarrage traditionnel (BIOS) — sans les avoir testés.

Les étapes en bref

  1. Installation (non décrite ici) de Debian “bookworm” (“testing”) avec partitionnement assisté chiffré.
  2. Chiffrement de la partition /boot selon le même principe que dans [1], mais en LUKS2 avec PBKDF2 (puisque GRUB 2.06 ne supporte pas Argon).
  3. Création d’une image personnalisée de GRUB comme décrit dans [2], car GRUB 2.06 sait déchiffrer un volume LUKS2, mais n’embarque pas ce code dans le binaire EFI généré par grub-install. On va en profiter pour embarquer une carte de clavier personnalisée (bépo dans mon cas), comme décrit dans [1].

N.B. : toutes les commandes décrites ci-dessous sont à exécuter en root.

Chiffrement de /boot

Sauvegarde du contenu de /boot :

mount -oremount,ro /boot
install -m0600 /dev/null /boot.tar
tar -C /boot --acls --xattrs --one-file-system -cf /boot.tar .

Démontage de la partition :

umount /boot/efi
umount /boot

Chiffrement de la partition (N.B. : dans mon cas, /boot est sur /dev/nvme0n1p2, remplacez par le bon périphérique chez vous) :

cryptsetup luksFormat --type luks2 --pbkdf pbkdf2 /dev/nvme0n1p2
uuid="$(blkid -o value -s UUID /dev/nvme0n1p2)"
echo boot_crypt UUID=$uuid none luks,discard >>/etc/crypttab
# Ici j'en profite pour renommer le volume principal en "root_crypt" dans
# /etc/crypttab, mais ce n'est pas nécessaire.
cryptdisks_start boot_crypt

Création d’un système de fichiers sur le volume chiffré (en réutilisant l’UUID du volume initial pour éviter d’avoir à modifier /etc/fstab) :

eval $(grep 'UUID=.*/boot ' /etc/fstab | cut -d' ' -f1)
mkfs.ext2 -m0 -U $UUID /dev/mapper/boot_crypt
mount -v /boot
tar -C /boot --acls --xattrs -xf boot.tar

N.B. : contrairement à ce qui est décrit dans [1], il est inutile dans notre cas d’activer GRUB_ENABLE_CRYPTODISK dans /etc/defaults/grub car nous allons créer notre propre image de GRUB.

Création de l’image GRUB

Créer le fichier de pré-configuration de GRUB (voir ci-dessous pour les explications et les éventuelles modifications à apporter dans votre environnement) :

uuid="$(blkid -o value -s UUID /dev/nvme0n1p2 | tr -d -)" # remplacez nvme0n1p2

cat >/boot/grub/grub-pre.cfg <<EOF
terminal_input at_keyboard
keymap (memdisk)/keymap.gkb
set uuid=$uuid
cryptomount -u \$uuid
set root=crypto0
set prefix=(\$root)/grub
insmod normal
normal
EOF

Script de génération de l’image GRUB, à enregistrer par exemple dans /boot/grub/grub-install.sh :

#!/bin/sh

# Carte de clavier à utiliser (mettre par exemple "fr oss" pour le français
# AZERTY) :
KEYMAP="fr bepo"

# Paramètres pour démarrage EFI :
IMAGE_FORMAT=x86_64-efi
OUTFILE=/boot/efi/EFI/debian/grubx64.efi

# Paramètres pour démarrage BIOS traditionnel :
#IMAGE_FORMAT="i386-pc"
#OUTFILE=/boot/grub/i386-pc/core.img

GRUB_PATH=/boot/grub
GRUB_PRECONF="$GRUB_PATH"/grub-pre.cfg
MEMDISK="$GRUB_PATH"/memdisk.tar 

MODULES="part_gpt cryptodisk luks2 pbkdf2 gcry_rijndael gcry_sha256 ext2 memdisk tar terminal keylayouts at_keyboard usb_keyboard"
# Notes :
# - Ajouter (ou remplacer "part_gpt" par) part_msdos pour gérer les tables de
#   partitions DOS.
# - Remplacer ext2 par le module correspondant au système de fichiers de /boot.
# - Ajouter "lvm" si /boot est sur un volume LVM. Ajuster également le chemin
#   de grub dans grub-pre.cfg (`($root)/boot/grub` au lieu de `($root)/grub`).
# - Il est possible que "uhci" et "ehci" soient nécessaires pour un clavier
#   USB, mais quand ils sont présents le disque n'est plus détecté (même avec
#   le module ahci), donc à tester.

set -x

# Création du memdisk contenant la carte de clavier personnalisée :
memdisk_tmp="$(mktemp --tmpdir --directory)"
grub-kbdcomp -o "$memdisk_tmp"/keymap.gkb $KEYMAP
tar -C "$memdisk_tmp" -cf "$MEMDISK" .
rm -fr "$memdisk_tmp"

# Génération de l'image GRUB :
grub-mkimage -p "$GRUB_PATH" -O "$IMAGE_FORMAT" -c "$GRUB_PRECONF" -m "$MEMDISK" -o "$OUTFILE" $MODULES

Donner les droits d’exécution au script, l’exécuter, redémarrer et croiser les doigts :

chmod +x /boot/grub/grub-install.sh
/boot/grub/grub-install.sh
shutdown -r now

Explications sur grub-pre.cfg

Définition du type de clavier (at_keyboard fonctionne pour le clavier de mon ordinateur portable ; mettre usb_keyboard pour un clavier USB) :

terminal_input at_keyboard

Chargement de la carte clavier personnalisée à partir du “memdisk” créé par le script ci-dessus :

keymap (memdisk)/keymap.gkb

N.B. : les deux lignes précédentes peuvent être supprimées si l’on ne souhaite pas utiliser de carte de clavier personnalisée.

L’UUID utilisé ici est l’UUID, sans tirets, du volume chiffré contenant /boot (donc de /dev/nvme0n1p2 chez moi, pas du système de fichiers boot_crypt lui-même).

set uuid=XXXXXXXXXXXXXXXXX

Déchiffrement du volume :

cryptomount -u $uuid

Définition du volume de démarrage (celui qui contient /boot) :

set root=crypto0

Sur du LVM, on pointerait plutôt sur le LV contenant /boot :

set root=lvm/monvg-bootlv

Définition du chemin vers les fichiers de GRUB :

set prefix=($root)/grub

Penser à ajuster le chemin, par exemple si /boot est sur / :

set prefix=($root)/boot/grub

Les instructions suivantes appellent le mode “normal” (par opposition au mode “rescue”) et chargent grub.cfg :

insmod normal
normal

Trucs et astuces

Éviter de taper deux fois le mot de passe

[1] propose une méthode pour éviter de taper deux fois le mot de passe au démarrage de la machine (chapitre 4, Avoiding the extra password prompt). Il s'agit d'inclure un fichier de clef (keyfile) dans l'image initrd. J'utilisais cette méthode lorsque mon /boot était chiffré avec LUKS1, car comme expliqué dans l'article, LUKS1 ne protège pas la clef d'un volume déverrouillé (elle est accessible en espace utilisateur via la table du device mapper).

En revanche, comme LUKS2 n'a pas ce problème, avoir un fichier contenant la clef de déchiffrement, lisible depuis l'espace utilisateur une fois la machine démarrée (soit depuis /etc/keys/, soit dans l'image initrd) devient un compromis inacceptable. Je me contente donc de taper deux fois le mot de passe (et deux fois seulement, car la phrase de passe est mise en cache et est automatiquement utilisée pour déchiffrer tous les volumes ayant une phrase de passe identique).

Erreur de mot de passe GRUB

Si l'on se trompe de mot de passe à l'invite de commande de GRUB, plutôt que de redémarrer la machine, on peut simplement taper :

cryptomount $uuid
insmod normal
normal

À noter qu'il faut retenir ces commandes par cœur car grub-rescue ne propose pas de complétion.

Réinstallation inopinée de GRUB

Il arrivera fatalement à un moment où un autre que les paquets de GRUB soient mis à jour et que GRUB soit automatiquement réinstallé. Si vous ne le remarquez pas, vous aurez une petite surprise au prochain redémarrage de votre machine. Comme expliqué en introduction, l'image par défaut de GRUB n'embarque pas le module luks2, il est donc impossible de se dépanner en tapant des commandes à l'invite de GRUB.

Vous devrez démarrer la machine sur un système de secours (par exemple SystemRescue, anciennement System Rescue CD), déchiffrer vos volumes et les monter, puis exécuter notre script d'installation de GRUB depuis un chroot. Quelque chose comme ceci :

cryptsetup open /dev/nvme0n1p2 boot_crypt
cryptsetup open /dev/nvme0n1p3 root_crypt
mount /dev/mapper/rootvg-rootlv /mnt
for i in dev proc sys ; do mount -o bind /$i /mnt/$i ; done
chroot /mnt
mount -a
/boot/grub/grub-install.sh
umount -a
exit
umount /mnt/*
umount /mnt
shutdown -r now

Références