Unified Kernel Images and Secure Boot using Arch Linux
enI recently got a new laptop computer and decided to give Unified Kernel Images and Secure Boot with my own keys another try. When I last looked into these topics almost a decade ago, they were extremely cumbersome to set up and maintain, and required lots of manual steps. A lot has changed since, and most of the steps have been automated, so that only little configuration and manual steps are required.
Please note that none of this is original work by me; it's mainly taken from the Arch Linux wiki articles linked above. However, since there are multiple, partially conflicting ways for setting up either, I wanted to document here which methods I used. As far as I'm aware, this is also the method that requires the least amount of custom configuration.
EFI Partition Layout
I'm mounting my EFI system partition (ESP) under /efi
, as this is one of the supported default locations in this setup; other locations may require additional configuration.
Inside the ESP, I'm placing all images in /EFI/arch
, so e.g. the primary UKI would be placed at /efi/EFI/arch/arch.efi
.
Unified Kernel Image
When directly booting UKI's, there is no boot loader such as GRUB2 involved. Therefore, the kernel command line needs to be baked into the UKI.
You can place your cmdline in /etc/cmdline.d/*.conf
; I placed the command line for unlocking and mounting the root volume in /etc/cmdline.d/root.conf
:
cryptdevice=UUID=6b50e908-8270-49d9-8b31-12444502670d:crypt root=UUID=8808fd0b-16d3-4531-af25-510b1d9c399f
To actually build the UKI, you also need to modify the mkinitcpio preset /etc/mkinitcpio.d/linux.preset
by commenting out the *_image
lines, and instead uncommenting the *_uki
lines:
# ...
#default_image="/boot/initramfs-linux.img"
default_uki="/efi/EFI/arch/arch.efi"
# ...
# ...
#fallback_image="/boot/initramfs-linux-fallback.img"
fallback_uki="/efi/EFI/arch/arch-fallback.efi"
# ...
If you're using another preset file, e.g. for linux-lts
, you need to apply the same config change to this file as well.
Now you can build your UKI's with mkinitcpio -p linux
. Among the output you should see the following lines:
# mkinitcpio -p linux
...
==> Initcpio image generation successful
==> Creating unified kernel image: '/efi/EFI/arch/arch.efi'
-> Using ukify to build UKI
-> Using cmdline file: '/etc/cmdline.d/root.conf'
Using config file: /usr/lib/kernel/uki.conf
Wrote unsigned /efi/EFI/arch/arch.efi
==> Unified kernel image generation successful
...
You should now be able to boot using this UKI. To set this up in your firmware, complete the following steps:
- Reboot into firmware setup. If your system supports it, you can use
systemctl reboot --firmware-setup
. - Once in the firmware setup, add an UEFI boot entry for
/EFI/arch/arch.efi
. You may also want to add one forarch-fallback.efi
. - Since the UKI is not signed yet, make sure that Secure Boot is disabled. At this point you can also delete the Secure Boot keys to put Secure Boot into Setup Mode.
- Save your firmware settings and reboot. If everything went right, the UKI should be booted.
Secure Boot
Setting up Secure Boot has become almost trivial in the last few years through the help of tools such as sbctl
.
For this, sbctl needs to be installed via pacman -S sbctl
.
To verify that the system is ready for Secure Boot enrollment, run sbctl status
:
# sbctl status
Installed: ✘ Sbctl is not installed
Setup Mode: ✘ Enabled
Secure Boot ✘ Disabled
Vendor Keys: microsoft
The important info is that Secure Boot is disabled and in Setup Mode.
NOTE: Removing the Microsoft vendor keys may render some devices unusable. Before you proceed, read the sbctl notes on Option ROMs to learn how to verify whether they can be safely removed.
If you have verified that you can indeed remove the Microsoft keys, generate your Secure Boot keys using sbctl create-keys
and enroll them with sbctl enroll-keys
.
If you want to keep the Microsoft vendor keys around, enroll them as well with sbctl enroll-keys -m
.
Another run of sbctl status
should now read:
# sbctl status
Installed: ✓ Sbctl is installed
Owner GUID: 46af18e7-46b9-48bb-8b3c-a85249a72cbd
Setup Mode: ✓ Disabled
Secure Boot ✘ Disabled
Vendor Keys:
To actually sign the UKI's, run mkinitcpio -p linux
again. This time you should see the following new lines in the output:
# mkinitcpio -p linux
...
==> Running post hooks
-> Running post hook: [sbctl]
Signing /efi/EFI/arch/arch.efi
✓ Signed /efi/EFI/arch/arch.efi
==> Post processing done
...
You can also verify whether the files in the ESP are signed using sbctl verify
:
# sbctl verify
Verifying file database and EFI images in /efi...
✓ /efi/EFI/arch/arch.efi is signed
✓ /efi/EFI/arch/arch-fallback.efi is signed
Now, reboot into firmware setup again and enable Secure Boot. Again, you can verify the Secure Boot status with sbctl status
:
# sbctl status
Installed: ✓ Sbctl is installed
Owner GUID: 46af18e7-46b9-48bb-8b3c-a85249a72cbd
Setup Mode: ✓ Disabled
Secure Boot ✓ Enabled
From now on, only images signed by your key should be bootable unless you disable Secure Boot again.
Firmware Updates
If you're using fwupd
to update your firmware, you should also sign the fwupdx64.efi
image. You only need to do this once, afterwards this is taken care of by a pacman hook of sbctl:
# sbctl sign -s -o /usr/lib/fwupd/efi/fwupdx64.efi.signed /usr/lib/fwupd/efi/fwupdx64.efi
You also need to tell fwupd to not use the Secure Boot Shim signed by Microsoft. For this, you need to place the following lines in /etc/fwupd/fwupd.conf
:
[uefi_capsule]
DisableShimForSecureBoot=true
EFI Shell
In order to be able to troubleshoot boot issues without e.g. a GRUB2 shell available and without resorting to a live system, I also placed an EFI shell in the ESP:
# pacman -S edk2-shell
# cp /usr/share/edk2-shell/x64/Shell_Full.efi /efi/EFI/arch/shell.efi
I did however NOT sign the EFI shell binary, so that it can't simply be started by anyone, compromising Secure Boot - instead I need to temporarily disable Secure Boot if I ever need to use it.