Securing My Arch System
Foreword
When I was trying to recover the root password of a virtual machine, I
was surprised by how easy it could be. All I needed was a single kernel
parameter, systemd.debug_shell. For non-systemd distros,
init=/bin/bash would also do. Or I could just boot from a live USB and
chroot into the system. Why did I not think of this before? As a result,
I decided to switch to systemd-boot + LUKS + UKI + Secure Boot.
Full disk encryption
The first thing to do was encrypt the disk. LUKS is the obvious choice for Linux. I just followed the Arch Wiki page. There is even a dedicated section on how to encrypt an existing partition.
After that, I added the sd-encrypt hook to the initramfs. Then, when I
was figuring out how I should update my /etc/fstab and
/etc/crypttab, I learned that systemd can automatically mount the
partitions for me if they have the right partition types.
UKI
Full disk encryption protects against someone with physical access to my laptop. But what if someone tampers with my bootloader? That is where Secure Boot comes in. A UKI (Unified Kernel Image) bundles the kernel, initramfs, and other bits into a single image, which makes it easier to sign for Secure Boot.
I chose mkinitcpio for this, since it is the first option listed.
First, I moved my kernel command-line parameters from the systemd-boot
configuration to /etc/kernel/cmdline. Then I modified the preset
/etc/mkinitcpio.d/linux.preset to generate UKIs. It is fortunate that
systemd-boot can pick up UKIs from /boot/EFI/Linux automatically, so I
removed the configured systemd-boot entries. So clean!
Secure Boot
Secure Boot is a UEFI feature that helps prevent loading unauthorized binaries. By signing the bootloader and the UKIs, I can ensure that only files signed by me can be loaded. This way, no one can tamper with my bootloader or kernel.
Setting up Secure Boot was a bit trickier. I first tried to follow the "Assisted process with systemd" section of the Arch Wiki page. It seemed to work, but I could not boot into the system and was greeted by an invalid signature error.
After that, I found that more people use sbctl to manage the keys. So
I undid the changes I had made and followed the instructions in the
sbctl section. I needed to sign more files manually, but it worked on
the first try. This part is a little tricky and I am afraid I will
forget it, so I will quote it here:
If you use Systemd-boot and
systemd-boot-update.service, the boot loader is only updated after a reboot, and the sbctl pacman hook will therefore not sign the new file. As a workaround, it can be useful to sign the boot loader directly in/usr/lib/, asbootctl installandupdatewill automatically recognize and copy .efi.signed files to the ESP if present, instead of the normal .efi file. See bootctl(1).
# sbctl sign -s -o /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed /usr/lib/systemd/boot/efi/systemd-bootx64.efi
Conclusion
I then completed the setup. It was actually much easier than I had
thought (and heard). Some people say that Secure Boot is a Microsoft
conspiracy and not worth setting up for a normal user, but with sbctl
and other tools, setting up Secure Boot is not that hard. I think it is
worth the effort.
References
- https://wiki.archlinux.org/title/Reset_lost_root_password
- https://wiki.archlinux.org/title/Dm-crypt/Device_encryption
- https://wiki.archlinux.org/title/Systemd#GPT_partition_automounting
- https://wiki.archlinux.org/title/Unified_kernel_image
- https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot