Installer UKI (Unified Kernel Image)

Tags: #<Tag:0x00007f336e47f1a0> #<Tag:0x00007f336e47f038>

Préambule
UKIs (Unified Kernel Images) sont des binaires UEFI PE qui intègrent tout ce qu’il faut pour démarrer un système. Ils peuvent être lancés à partir du firmware UEFI, ou d’un premier étage ou d’un second chargeur de démarrage.

Ils offrent plusieurs avantages par rapport à une approche traditionnelle basée sur les artefacts divisés :

  • Tout le contenu, y compris l’initrd, est couvert par la signature PE et vérifié pour la confiance.
  • Ils se décrivent eux-mêmes, donc le gestionnaire de démarrage n’a pas besoin de configuration auxiliaire et peut simplement générer des éléments de menu avec tous les détails requis à partir de leur contenu.
  • Ils fournissent un support pour la politique de descellement TPM2 PCR basée sur la signature.

À la base, un UKI est créé en combinant systemd-stub, kernel, cmdline et initrd en un seul binaire EFI, et en le signant pour SecureBoot.

Introduction
En premier lieu, pour mettre en place l’UKI, il faut avoir Secure Boot d’activé. Une installation avec Secure Boot activé dans le bios installera Debian avec Secure Boot Activé.
Si ce n’est pas le cas, c’est que la configuration du bios est mauvaise, ou que le média utilisé pour l’installation est mauvais.
Par contre, mettre en place Secure Boot sur une installation déjà réalisée sans n’est pas couverte ici. C’est une opération difficile qui nécessite de signer les modules, les noyaux et les stubs efi.

** Prérequis**
Les prérequis sont donc l’installation des paquets systemd-ukify et sbsigntool, de créer une paire clef/certificat, de créer les hooks pour le kernel et pour l’initramfs.

** Installation des paquets **
C’est simple:
apt -y install systemd-ukify sbsigntool
Il n’y a ici rien d’autre à faire.

** Création de la clef et du certificat **
NOTE: Actuellement il n’est pas possible d’utiliser autre chose qu’une clef RSA. Si l’enrollement du certificat créé à partir d’une clef ED25519 par exemple, la signature Secure Boot ne permet que l’utilisation d’une clef RSA. C’est bien dommage, il faut espérer que les développeurs vont rapidement intégrer cette possibilité un jour. Mais Microsoft étant un acteur majeur sur le sujet, j’ai comme un doute.

Pour stocker la clef et le certificat, nous utiliserons le répertoire /var/lib/shim-signed/mok :
mkdir -p /var/lib/shim-signed/mok

Création de la clef:
openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:4096 -out /var/lib/shim-signed/mok /MOK.priv

Ensuite, création du certificat:
Nous utiliserons la clef précédente pour le certificat, et nous mettrons les extension permettant de faire un CA avec une contrainte critique, un usage critique de Digital Signature, de Certificate Sign et de CRL Sign, l’usage etendu de Code Signing, ainsi que les information sur l’autorité.
Ces options sont optionnelles (hors basique) pour le fonctionnement de l’UKI, et ne sont mises ici qu’à titre indicatif.
La validité de la clef débutera à 00:00 du jour de création et pour 30 ans à minuit. Le certificat sera créé au format DER; c’est nécessaire pour l’enrollement dans la base Secure Boot.
Ce qui nous donne la commande openssl suivante:

openssl req \
                -x509 \
                -nodes \
                -not_before $(date -d "today" +"%Y%m%d000000Z") \
                -not_after $(date -d "$dt1 + 30 years" +"%Y%m%d000000Z") \
                -new \
                -key /var/lib/shim-signed/mok/MOK.priv \
                -outform DER \
                -out /var/lib/shim-signed/mok/MOK.der \
                -subj  "/C=mon pays code ISO/ST=ma region/L=ma ville/O=Mon Organisation/OU=Secure Boot Cert/CN=Le nom que je veux ou mon domaine/" \
                -addext "basicConstraints = critical, CA:TRUE" \
                -addext "keyUsage = critical, digitalSignature, keyCertSign, cRLSign" \
                -addext "extendedKeyUsage = critical, codeSigning" \
                -addext "authorityInfoAccess = OCSP;URI:http://mon.url.ocsp.org/,caIssuers;URI:https://url.du..ca.du.fournisseur.com"

Le -subj et l’extension basicConstraints sont nécessaires.

Il faut tout de même convertir le certificat au format PEM pour l’utilisation par ukify.

openssl x509 -inform DER -in /var/lib/shim-signed/mok/MOK.der -outform PEM -out //var/lib/shim-signed/mok/MOK.pem

Création des hooks et configurations
Si vous utilisez DKMS, ce que je ne saurais que vous conseiller, il faut penser à modifier le framework dkms dans le fichier /etc/dkms/framework.conf avec les clef/cert:

sed -Ei 's/^[#]*\s*(mok_signing_key=).*/\1\/var\/lib\/dkms\/MOK.priv/g' /etc/dkms/framework.conf
sed -Ei 's/^[#]*\s*(mok_certificate=).*/\1\/var\/lib\/dkms\/mok\/MOK.der/g' /etc/dkms/framework.conf

On importe le certificat au format DER dans la base Secure Boot:
mokutil -P -i /var/lib/shim-signed/mok/MOK.der

  • -P: utiliser le mot de passe root
  • -i: importer

Déterminer l’UUID de la partition de démarrage:
Exemple 1: si les partition ont un label:
root_uuid=$(lsblk -f | grep ROOT | awk '{print $5}')

Exemple 2: si les partitions n’ont pas de label:
root_uuid=$(lsblk -f | grep -E '\s\/$' | awk '{print $5}')

root_uuid va servir pour la création des hooks et du fichier de configuration ukify.

Créer le hook kernel:

cat << EOF > /etc/kernel/postinst.d/zz-ukify
#!/bin/bash
set -e

/usr/lib/systemd/ukify build --linux="\$2" --initrd="/boot/initrd.img-\$1" --cmdline="root=UUID=${root_uuid} video=1920x1080 splash quiet" --splash="/boot/grub/themes/enedwaith/background.png" --output="/boot/efi/EFI/Linux/debian.efi"

# Add this line if you want to sign the image for secure boot
sbsign --key /var/lib/shim-signed/mok/MOK.priv --cert /var/lib/shim-signed/mok/MOK.pem --output /boot/efi/EFI/Linux/debian.efi /boot/efi/EFI/Linux/debian.efi

EOF
chmod ug+x /etc/kernel/postinst.d/zz-ukify

Créer le hook initramfs:

cat << EOF > /etc/initramfs/post-update.d/zz-ukify
#!/bin/bash
set -e

/usr/lib/systemd/ukify build --linux="/boot/vmlinuz-\$1" --initrd="\$2" --cmdline="root=UUID=${root_uuid} video=1920x1080 splash quiet" --splash="/boot/grub/themes/enedwaith/background.png" --output="/boot/efi/EFI/Linux/debian.efi"

# Add this line if you want to sign the image for secure boot
sbsign --key /var/lib/shim-signed/mok/MOK.priv --cert /var/lib/shim-signed/mok/MOK.pem --output /boot/efi/EFI/Linux/debian.efi /boot/efi/EFI/Linux/debian.efi

EOF
chmod ug+x /etc/initramfs/post-update.d/zz-ukify

Créer le fichier de configuration par défaut de ukify:

cat <<EOF > /etc/kernel/ukify.conf
[UKI]
Cmdline="root=UUID=${root_uuid} video=1920x1080 splash quiet"
Linux="/boot/vmlinuz-$(uname -r)"
Initrd="/boot/initrd.img-$(uname -r)"
Splash="/boot/grub/themes/enedwaith/background.png"
SecureBootPrivateKey="/var/lib/shim-signed/mok/MOK.priv"
SecureBootCertificate="/var/lib/shim-signed/mok/MOK.pem"
SignKernel=true
EOF

La ligne de commande(cmdline) est déterminée avec les options suivantes:

  • root=UUID=uuid de la partition: la partition de démarrage
  • video=1920x1080: car je n’ai que des écran en 1920x1080 à minima.
  • splash: pour l’utilisation de plymouth
  • quiet: pour ne pas avoir d’affichage de logs de démarrage

Les hooks vont être utilisés par tout lancement de la commande de mise à jour de l’initramfs (update-initramfs) ou par l’installation d’un nouveau noyau.
Ce sera aussi utilisé si on reconfigure un noyau avec dpkg-reconfigure).

Activation
Enfin, pour installer l’UKI:
dpkg-reconfigure linux-image-$(uname -r)

Il suffit de redémarrer et de procéder à l’import MOK du certificat juste au lancement de la machine (attention en cas d’échec il faudra relancer la commande mokutil et redémarrer une nouvelle fois).

Conclusion
Et au démarrage désormais vous avez deux entrées:

  • Celle que vous aviez avec systemd-boot
  • Celle que vous venez de créer (qui se positionne en premier)
    Pour bien faire, il vous suffit de désactiver l’ancienne entrée de démarrage, car l’UKI est bien plus sécurisée et ne peut en aucun cas être réécrite.
    image

Pour les commentaires, correction, etc… Aller dans le fil dédié ici

1 J'aime