Eine Tutorialreihe zur Einrichtung einer Rollbackfunktion in Arch Linux unter Nutzung von Unified Kernel Images und systemd-boot.
Inhaltsverzeichnis
- Einleitung
- Teil 1: Unified Kernel Image & systemd-boot einrichten in Arch Linux (das ist dieser Artikel)
- Teil 2: Automatische Btrfs Snapshots mit `snapper` und Co.
- Teil 3: Arch Linux Bootbare Btrfs Snapshots mit UKIs
Teil 1
Ein Unified Kernel Image (UKI) ist eine ausführbare Datei, die den Kernel, das initramfs, einen EFI Boot Stub, und die Kernel Kommandozeile (cmdline) in einer von der UEFI Firmware bootbaren .efi Datei kombiniert.
Es gibt verschiedene Tools, die UKIs erstellen. Ich nutze mkinitcpio da es sowohl den Bau der UKIs als auch die Generierung des initramfs übernimmt (Standardtool in Arch). Sofern systemd-ukify installiert ist, übergibt mkinitcpio in Arch Linux den Bau der UKI an systemd-ukify (ist relevant, wenn z. B. der TPM genutzt wird in Kombination mit signierten Systemzuständen).
Falls du noch auf die "alte" Art bootest, wird deine EFI Systempartition (ESP) höchstwahrscheinlich auf das /boot Verzeichnis gemountet sein. Das bedeutet, alle für den Boot notwendigen Dateien befinden sich auf der ESP unter /boot und sind somit direkt zugänglich bzw. nach aussen exponiert. Im Kontext von Secure Boot etwas problematisch, da die UEFI Firmware ausschliesslich signierte EFI Dateien verifiziert. Kernel und initramfs werden in klassischen Setups in der Regel vom Bootloader nachgeladen und sind nicht automatisch Teil dieser Vertrauenskette. Ob und wie sie verifiziert werden, hängt von der jeweiligen Bootloader-Konfiguration ab.
Diese neue Variante ist vor allem interessant, wenn eine verschlüsselte Root Partition verwendet wird. Das Setup mountet die ESP auf /efi, /boot wird Teil der verschlüsselten Root Partition. So sind die einzigen unverschlüsselten Dateien auf der Festplatte die UKIs auf der ESP, die sich als signierbare, in sich geschlossene Dateien in Secure Boot integrieren lassen. Allerdings sind Kernel Parameter nun fest in die UKI eingebettet und können nicht mehr bequem zur Bootzeit editiert werden.
Wer wissen will, wie Arch Linux manuell mit einer verschlüsselten Root Partition installiert wird, kann gerne mein altes Tutorial aufsuchen. Alternativ funktioniert das archinstall Script heutzutage auch gut. Zu beachten, falls meinem Tutorial gefolgt wird: Arch hat alle offiziellen NVIDIA-Pakete auf „open“ umgestellt (gilt nur für Turing und neuer), bitte mit dem Wiki abgleichen. Allgemein sollte das Arch Wiki meinem Tutorial bevorzugt werden, da gewisse Informationen veraltet sein können.
Vorbereitung
Wir erstellen das /efi Verzeichnis, ändern in der /etc/fstab Datei den Mountpoint der ESP auf /efi, mounten die ESP neu unter /efi und verschieben die Kernel Images sowie ggf. den Microcode nach /boot.
# /efi Verzeichnis erstellen und Mountpoint der ESP ändern
# nutze den texteditor, der dir am geläufigsten ist
sudo mkdir /efi
sudo vim /etc/fstab
Beispielinhalt einer fstab Datei. Mountpoint der ESP wird in der ursprünglichen Zeile von /boot auf /efi geändert.
# alt
# /dev/sda1 LABEL=ESP
UUID=F685-B50B /boot vfat rw,relatime,fmask=0137,dmask=0027,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro 0 2
# neu
# /dev/sda1 LABEL=ESP
UUID=F685-B50B /efi vfat rw,relatime,fmask=0137,dmask=0027,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro 0 2
Wir re-mounten alle in fstab definierten Dateisysteme.
sudo mount -a
Jetzt befinden sich das initramfs, Kernel Image und ggf. Microcode noch auf der ESP in /efi, wir möchten sie allerdings auf der Root Partition unter /boot haben. Das initramfs wird nicht mehr benötigt, da es später direkt in die UKI gepackt wird – es kann gelöscht werden. Kernel Image und Microcode (hier Intel) verschieben wir nach /boot. Grund: pacman speichert in der Standardkonfiguration Kernel Image und Microcode in /boot, mkinitcpio erwartet sie dort. Dieses Verhalten behalte ich bei, da es der Standardkonfiguration entspricht und keine zusätzliche Anpassung der Paket-Hooks erfordert.
Achtung: Mit dem nächsten Schritt befindet sich dein System in einem unbootbaren Zustand (Bootloader, z.B. GRUB, erwartet initramfs und Kernel aber sie fehlen an der erwarteten Stelle). Wird erst mit Bau der UKIs im Schritt 2 und der Installation von systemd-boot im Schritt 3 "repariert".
cd /efi
# je nach Konfiguration können mehr oder wengier initramfs images existieren
sudo rm initramfs-linux.img initramfs-linux-fallback.img initramfs-linux-lts.img initramfs-linux-lts-fallback.img
# je nach Konfiguration können mehr oder wenger Kernel Images existieren (hier aktueller Kernel und LTS)
sudo mv vmlinuz-linux vmlinuz-linux-lts /boot
# microcode verschieben (hier intel, für amd: amd-ucode.img)
sudo mv intel-ucode.img /boot
1. Kernel Parameter definieren
Kernel Parameter in einer oder mehr Dateien in /etc/cmdline.d/root.conf definieren (Name der Datei spielt keine Rolle). Dateien in diesem Verzeichnis werden verkettet. Eine simple Installation benötigt im Grunde nur den root= Parameter für die Root-Disk (wird in den nächsten Teilen der Tutorialreihe relevant). Falls du GRUB nutzt, sind deine aktuellen Kernel Parameter in /etc/default/grub definiert.
Beispielinhalt einer simplen root.conf Datei:
root=UUID=b18fb5be-fff4-4ee3-99e1-efb175e6c630
2. Presets für UKIs definieren
Wir nutzen mkinitcpio um das initramfs zu generieren und die UKIs zu bauen. Die Presets werden im /etc/mkinitcpio.d/ Verzeichnis definiert. Es existieren die Dateien linux.preset für den aktuellen Kernel und linux-lts.preset für LTS. Auf Wunsch kann auch eine UKI mit Fallback initramfs erzeugt werden, ich nutze allerdings keine. Stellt sicher, dass das Verzeichnis /efi/EFI/Linux/ auch existiert.
sudo mkdir -p /efi/EFI/Linux/
Inhalt meiner linux.preset unten. ALL_kver definiert den Pfad des zu nutzenden Kernel Images. In PRESETS kann angegeben werden, ob eine zusätzliche UKI mit Fallback initramfs gewünscht wird. default_image generiert ein separates initramfs image, welches wir allerdings nicht brauchen, da es direkt in die UKI geschrieben wird. default_uki definiert den Pfad und Dateinamen der UKI. Die auskommentierten Zeilen sind enthalten, damit alle Optionen ersichtlich sind.
#ALL_config="/etc/mkinitcpio.conf"
ALL_kver="/boot/vmlinuz-linux"
#ALL_kerneldest="/boot/vmlinuz-linux"
PRESETS=('default')
#PRESETS=('default' 'fallback')
# default
#default_config="/etc/mkinitcpio.conf"
#default_image="/boot/initramfs-linux.img"
default_uki="/efi/EFI/Linux/arch-linux.efi"
#default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"
# fallback
#fallback_config="/etc/mkinitcpio.conf"
#fallback_image="/boot/initramfs-linux-fallback.img"
#fallback_uki="/efi/EFI/Linux/arch-linux-fallback.efi"
#fallback_options="-S autodetect"
Der Vollständigkeit halber hier meine linux-lts.preset Datei:
ALL_kver="/boot/vmlinuz-linux-lts"
PRESETS=('default')
default_uki="/efi/EFI/Linux/arch-linux-lts.efi"
Im Anschluss bauen wir die UKIs beider Presets mit mkinitcpio. Sie sollten sich nun in /efi/EFI/Linux/ befinden.
sudo mkinitcpio -P
3. Installation von systemd-boot
Vorteil von systemd-boot: Teil von systemd (keine zusätzlichen Pakete notwendig), ist sehr einfach zu installieren und listet automatisch alle .efi Dateien im /efi/EFI/Linux Verzeichnis als Einträge im Bootmenü auf. systemd-boot speichert den Bootloader in zwei Verzeichnissen: /efi/EFI/systemd/systemd-bootx64.efi sowie/efi/EFI/BOOT/BOOTX64.efi. Letzterer ist ein generischer Standardpfad in den meisten UEFI Firmwares der als Fallback Option dient.
sudo bootctl install
Wir bearbeiten /efi/loader/loader.conf und setzen folgende Einstellungen.
# 0 = Bootmenü ausgeblendet, durch halten der Space Taste sichtbar
timeout 0
# Standard efi Datei definieren
default arch-linux.efi
Dein alter Bootloader und sein Eintrag im NVRAM der Firmware sollten noch entfernt werden. Hier erkläre ich, wie GRUB deinstalliert wird.
# GRUB deinstallieren, efibootmgr installieren
sudo pacman -R grub
sudo pacman -S efibootmgr
# GRUB Eintrag im NVRAM der UEFI Firmware löschen
# Einträge auflisten
sudo efibootmgr
# GRUB ausfindig machen, das erste Wort des Eintrags ist relevant, z.B. Boot0000
# Eintrag löschen, XXXX mit der vierstelligen Zahl ersetzen
sudo efibootmgr -b XXXX -B
# alte GRUB Dateien löschen (sie befinden sich auf der ESP, neu unter /efi statt /boot)
sudo rm -rf /efi/EFI/grub
sudo rm -rf /efi/grub
Es existiert die Möglichkeit, das System ohne Bootloader zu nutzen. Dann müssen die Booteinträge im NVRAM der Firmware allerdings manuell verwaltet werden mit efibootmgr. Ein Eintrag kann wie folgt aussehen (UEFI Firmware nutzt Backslashes statt Forwardslashes):
sudo efibootmgr --create --disk /dev/sda --part 1 --label "Arch" --loader '\EFI\Linux\arch-linux.efi' --unicode
Damit wär's auch schon erledigt. Beim Upgrade der Kernel Version werden automatisch neue UKIs generiert. Falls gewünscht wird, Secure Boot einzurichten, empfehle ich das sbctl Tool. Nach einmaliger Einrichtung ist die Signierung der notwendigen Dateien völlig automatisiert. Bitte lest den Warnhinweis bezüglich OpROMs am Anfang des Dokuments sorgfältig durch, wenn ihr die Secure Boot Schlüssel von Microsoft und des Herstellers eurer Hardware von der Firmware löschen möchtet.
Im nächsten Teil (2) wird das Setup für snapper, snap-pac sowie snapper-rollback erklärt.
Quellen:
https://wiki.archlinux.org/title/Main_page