Mise en place du noyau
La dernière (mais pas la moindre) chose qu'il manque à notre système, c'est un noyau.
Notre noyau sera installé depuis le paquet debian ordinaire, mais celà ne suffit pas : le noyau est
installé directement dans /boot, qui dans notre installation se trouve dans le volume chiffré. Il
ne sera donc pas accessible lors du démarrage et ne pourra donc pas être chargé. Nous allons donc
mettre en place un système permettant, à partir du noyau packagé par Debian, d'avoir un fichier
amorçable par l'UEFI.
Création d'une image de noyau unifiée (UKI) amorçable
Pour permettre le démarrage du système, nous allons regrouper tout ce qui est nécessaire, c'est à dire principalement le noyau Linux et son système de fichier initial (initrd), en un seul fichier directement amorçable par l'UEFI, qui sera installé sur la partition EFI. Ce type de fichier est connu sous le nom d'UKI, pour Unified Kernel Image ou, en français, image de noyau unifiée. Pour plus de détails sur ce format, on pourra consulté, par exemple, le wiki Arch. Ce fichier sera signé avec notre clé SecureBoot mise en place à l'étape précédente, ce qui lui permettra d'être chargée directement, sans passer par un chargeur d'amorçage.
On commence par installer les paquets dont nous aurons besoin pour cette étape :
apt-get install systemd-ukify sbsigntool efibootmgr systemd-boot-efi cryptsetup-initramfs
Pour que cette génération se fasse automatiquement à chaque mise à jour du noyau, nous allons la
mettre en place dans un script placé dans le répertoire /etc/kernel/postinst.d/ qui sera donc
exécuté après chaque installation d'un noyau. Nous allons donc créer un fichier
/etc/kernel/postinst.d/zz-1-update-uki (le préfixe permet de contrôler l'ordre d'exécution, dans
le cas où d'autres scripts seraient présents) avec le contenu suivant :
#!/bin/sh -e
version="$1"
/usr/lib/systemd/ukify build \
--linux /boot/vmlinuz-${version} \
--initrd /boot/initrd.img-${version} \
--os-release @/usr/lib/os-release \
--uname ${version} \
--cmdline @/etc/cmdline \
--output /boot/efi/EFI/debian/Linux-${version}.efi
/usr/bin/sbsign \
--key /root/Rocannon-SecureBoot.key \
--cert /root/Rocannon-SecureBoot.crt \
--output /boot/efi/EFI/debian/Linux-${version}.efi \
/boot/efi/EFI/debian/Linux-${version}.efi
Ce script fait référence à plusieurs fichiers externes qui doivent donc être présents et dont les chemins sont potentiellement à adapter :
/usr/lib/os-releaseest installé par le paquetbase-files, qui fait partie de l'installation de base,/etc/cmdlineest un fichier que nous allons créer et qui nous permet de configurer la ligne de commande de démarrage du noyau. Il se compose de la ligne suivante (à adapter, en particulier selon le nom du volume group choisi lors du partitionnement) :root=/dev/mapper/vg_rocannon-lv_racine ro rootflags=subvol=racine quiet loglevel=3 panic=0/root/Rocannon-SecureBoot.keyet/root/Rocannon-SecureBoot.crtcorrespondent respectivement à notre clé privée de type db, générée à l'étape précédente, et à son certificat de clé publique.
Notre UKI ne contient pas seulement le noyau, mais également l'initrd associé. Elle doit donc
également être régénérée en cas de mise à jour de l'initrd. Pour cela, il nous suffit de créer un
lien symbolique vers notre script dans /etc/initramfs/post-update.d/ :
mkdir -p /etc/initramfs/post-update.d
ln -s /etc/kernel/postinst.d/zz-1-update-uki /etc/initramfs/post-update.d/
Installation de l'UKI dans l'UEFI
Une fois notre image créée et signée dans la partition EFI, il faut encore créer une entrée
correspondante dans la séquence de démarrage de l'UEFI. Cela se fait avec un second script,
également dans /etc/kernel/postinst.d/, que nous allons nommer zz-2-install-uki, pour garantir
qu'il s'exécute bien après le précédent :
#!/bin/sh -e
version="$1"
/usr/bin/efibootmgr \
--disk /dev/nvme0n1 \
--create \
--label "Debian-Linux-${version}" \
--loader "\EFI\debian\Linux-${version}.efi"
Contrairement au précédent, ce script n'a besoin d'être exécuté que lors de la première installation
de chaque version du noyau, il ne faut donc pas créer de lien dans /etc/initramfs/post-update.d/.
Gestion de la désinstallation
Pour éviter de saturer notre partition EFI, il faut également supprimer les fichiers que nous y
avons créés lors de la désinstallation du noyau correspondant, et mettre à jour la configuration
UEFI en conséquence. De façon similaire à l'installation, nous allons mettre en place un script dans
le répertoire /etc/kernel/postrm.d/, nommé zz-remove-uki :
#!/bin/sh -e
version="$1"
# recherche du numéro de l'entrée concernée dans l'ordre de démarrage UEFI
num=$(efibootmgr --disk /dev/nvme0n1 \
| grep "Debian-Linux-${version}" \
| cut -c 5-8)
if [ -n "$num" ]
then
efibootmgr \
--disk /dev/nvme0n1 \
--delete-bootnum \
--bootnum $num
fi
# l'option -f évite une erreur si le fichier n'existe pas
rm -f /boot/efi/EFI/debian/Linux-${version}.efi
Installation du noyau
Maintenant que nos scripts sont bien en place, nous pouvons installer le meta-paquet correspondent à l'architecture utilisée :
apt-get install linux-image-amd64
La sortie de la commande d'installation, et l'examen du contenu de la partition EFI, permettent de vérifier que tout s'est bien passé.