#!/coding/blatt
Sammelsurium mit Schwerpunkten Linux & IT-Sicherheit

Arch Linux & Secure Boot: Unified Kernel Image (UKI) mit systemd-ukify erstellen & signieren

Bis vor Kurzem hatte ich zum Generieren von Unified Kernel Images (UKIs) mein selbstentwickeltes Tool secbootctl verwendet. Da ich derzeit nicht die Muße habe, es weiterzuentwickeln und es durch eine der letzten systemd-Änderungen sowie nicht mehr korrekt funktioniert hat, habe ich mein System nun auf systemd-ukify umgestellt. Als Bestandteil von systemd ist somit sichergestellt, dass die generierten UKIs zukünftig immer der initial vom systemd-Projekt initierten UAPI: Bootloader Specification entsprechen (also hoffe ich zumindest :)).

In Verbindung mit pacman, dem Paketmanager von Arch Linux, wird bei jedem Kernel-, initramfs- und CPU-Microcode-Update ein UKI erstellt und mit meinem eigenen UEFI-Secure-Boot-Schlüssel signiert. Wie das genau funktioniert, erfahrt ihr in diesem Beitrag.

Folgende Geräte bzw. Software wurde verwendet:
  • Lenovo ThinkPad X1 Carbon Gen 9 mit Arch Linux
  • systemd v254.1-1-arch

systemd-ukify installieren

Standardmäßig wird unter Arch Linux systemd-ukify nicht mit dem Hauptpaket systemd mit ausgeliefert. Insofern ist das Paket explizit zu installieren:

sudo pacman -S systemd-ukify
Terminal / Konsole

UKI erstellen & signieren

Zum Erstellen und Signieren eines Unified Kernel Images reicht der folgende Befehl:

sudo /usr/lib/systemd/ukify build \
        --linux=/boot/vmlinuz-linux \
        --initrd=/boot/intel-ucode.img \
        --initrd=/boot/initramfs-linux.img \
        --cmdline=@/etc/kernel/cmdline \
        --splash=/usr/share/systemd/bootctl/splash-arch.bmp \
        --signtool=sbsign \
        --secureboot-private-key=/etc/secbootctl/keys/db.key \
        --secureboot-certificate=/etc/secbootctl/keys/db.crt \
        --output=/efi/EFI/Linux/arch-linux.efi

Host arch 'x86_64', EFI arch 'x64'
+ sbverify --list /boot/vmlinuz-linux
No signature table present
Kernel version not specified, starting autodetection 😖.
Found uname version: 6.4.11-arch1-1
+ sbsign --key /etc/secbootctl/keys/db.key --cert /etc/secbootctl/keys/db.crt /tmp/ukiebt6r79e --output /efi/EFI/Linux/arch-linux.efi
Signing Unsigned original image
Wrote signed /efi/EFI/Linux/arch-linux.efi
Terminal / Konsole

Dieser Befehl erstellt aus dem angegebenen Kernel, initramfs und Microcode ein UKI und signiert es mit dem angegebenen Secure-Boot-Key. Das erstellte signierte UKI wird dann direkt auf der EFI-Partition abgelegt. In Verbindung mit dem Bootloader systemd-boot werden UKIs unter /efi/EFI/Linux automatisch erkannt und bedürfen keiner extra Bootmenü-Konfiguration.

Hinweis ukify-Konfigurationsdatei verwenden

Anstatt alle Optionen beim Aufruf des Commands aufzurufen, kann bei Bedarf auch eine Konfigurationsdatei verwendet werden. Details siehe ukify-man

Hook für pacman

Damit ich nicht nach jedem System-Update manuell das entsprechende UKI erstellen muss, habe ich eine entsprechende Hook-Datei für pacman angelegt:

[Trigger]
Operation = Install
Operation = Upgrade
Type = Path
Target = usr/lib/modules/*/vmlinuz

[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Path
Target = usr/lib/initcpio/*

[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = intel-ucode
Target = amd-ucode

[Action]
Description = Create and sign unified kernel image with ukify.
When = PostTransaction
Exec = /usr/local/bin/secure-boot-update-uki
Depends = systemd-ukify
NeedsTargets
Datei: /etc/pacman.d/hooks/99-secure-boot-kernel.hook

Das Command /usr/local/bin/secure-boot-update-uki ruft dann systemd-ukify auf:

#!/bin/sh
/usr/lib/systemd/ukify build [...]
Datei: /usr/local/bin/secure-boot-update-uki

Bei Bedarf könnte man das Skript auch etwas universeller umsetzen, so dass es nicht nur für das Standard-Kernel-Paket unter Arch Linux funktioniert, sondern es dynamisch auflöst (analog wie ich das bei secbootctl hatte).

Wenn nun also ein System-Update via pacman ausgeführt wird und sich Kernel, initramfs und/oder Microcode ändern, wird automatisch durch pacman das Skript zum Erstellen des UKI aufgerufen.

sudo pacman -Syu
[...]
==> Generating module dependencies
==> Creating zstd-compressed initcpio image: '/boot/initramfs-linux-fallback.img'
==> Image generation successful
(4/4) Create and sign unified kernel image with ukify.
No signature table present
Signing Unsigned original image
Host arch 'x86_64', EFI arch 'x64'
+ sbverify --list /boot/vmlinuz-linux
Kernel version not specified, starting autodetection 😖.
Found uname version: 6.4.12-arch1-1
+ sbsign --key /etc/secbootctl/keys/db.key --cert /etc/secbootctl/keys/db.crt /tmp/uki3q_3jjoq --output /efi/EFI/Linux/arch-linux.efi
Wrote signed /efi/EFI/Linux/arch-linux.efi
[...]
Terminal / Konsole

Des Weiteren gibt es noch eine weitere Hook-Datei zum Aktualisieren und Signieren der system-boot-Bootloader-Dateien, aber das ist letztendlich unabhängig von der UKI-Erstellung mittels systemd-ukify.

Fazit

Mit systemd-ukify lassen sich leicht Unified Kernel Images (UKI) erstellen und mit dem eigenen Secure-Boot-Key signieren. Das ganze lässt sich prima mit pacman automatisieren, so dass man sich bei einem System-Update um nichts kümmern muss und auch nichts vergessen kann.