Recently, I configured secure boot for my Arch Linux, and I would like to document the process and any issues I encountered.
Implementing Secure Boot#
For a complete description of implementing secure boot, refer to the Arch Wiki. However, the wiki format can make the process description complex. This section aims to provide a simplified method for implementing secure boot, skipping detailed conceptual content.
Note: This article only describes setting up secure boot for Arch Linux. For further implementation and coexistence with Windows secure boot, please refer to the corresponding entry in the Arch Wiki here.
Generating Keys#
Implementing secure boot involves four types of keys:
- Platform Key (PK)
- Key Exchange Key (KEK)
- Signature Database (db)
- Forbidden Signatures Database (dbx)
To use secure boot properly, we need at least the first three keys. To simplify the process, we can use a script to generate them:
# The sbupdate tool, which automatically handles kernel updates, defaults to using keys located in /etc/efi-keys.
# To make it easier, we'll create this directory and generate the keys in it
mkdir /etc/efi-keys
cd !$
curl -L -O https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh
chmod +x mkkeys.sh
./mkkeys.sh
<Enter any name to embed in the key, for example "Secure Boot">
Automatic Signing#
To automatically sign during kernel and bootloader updates, we can use the sbupdate tool.
Installation#
Install it with the following command:
yay -S sbupdate-git
Configuration#
After installation, we need to configure sbupdate to specify what needs to be automatically signed.
Open /etc/sbupdate.conf and modify the configuration file. Here is an example of my settings and their options:
# Directory where the keys are located
KEY_DIR="/etc/efi-keys"
# Location of the EFI boot partition
ESP_DIR="/boot"
# Location of the generated separate EFI boot files
OUT_DIR="EFI/Linux"
# Default kernel parameters carried by the generated separate EFI boot files
CMDLINE_DEFAULT="loglevel=3 quiet nomce rw"
# Additional files that need to be signed, usually including your own bootloader files
# The kernel is automatically signed in theory, but for some reason my vmlinuz-linux-zen doesn't work, so I also include the kernel file here
EXTRA_SIGN=('/boot/EFI/BOOT/BOOTX64.EFI' '/boot/EFI/systemd/systemd-bootx64.efi' '/boot/vmlinuz-linux-zen')
# Individual kernel configurations
INITRD["linux-zen"]="/boot/initramfs-linux-zen.img"
# If no kernel parameters are configured, use CMDLINE_DEFAULT above
CMDLINE["linux-zen"]="root=PARTUUID=db9157b1-bed4-fa44-a715-5c1bfc8bdfb4 quiet nomce loglevel=3 rw"
Here are some specific explanations for individual kernel configurations:
sbupdate generates a separate boot file for each kernel (located at ${ESP_DIR}/${OUT_DIR}, with the file name ${kernel_name}-signed.efi), which includes kernel parameters and temporary file system configurations (corresponding to CMDLINE[${kernel_name}] and INITRD[${kernel_name}] in the configuration file).
There are three ways to boot:
- Use the existing configuration of a boot loader (such as grub/systemd-boot, etc.)
- Directly use the generated boot file for booting
- Use a boot loader to indirectly boot by calling the boot file
Most users usually use the first method. If there are no issues with this method, there is no need to use the separate boot file. In other words:
You can ignore OUT_DIR, CMDLINE_DEFAULT, and individual kernel configurations above.
Signing#
After the initial configuration, you need to manually execute the signing command:
sudo sbupdate
In the future, this tool will automatically sign during kernel updates.
Special handling for automatic signing with systemd-boot#
For other boot methods, the above configuration methods may be sufficient. However, if you are using systemd-boot as the boot loader, further configuration may be required.
Handling of hook execution order#
Regarding this situation:
In general, we only need to use pacman hooks to update the signature when updating the kernel or systemd. However, when using systemd-boot, we also need to update the boot loader when updating systemd (i.e., sudo bootctl update
, which replaces /boot/EFI/BOOT/BOOTX64.EFI and /boot/EFI/systemd/systemd-bootx64.efi with the latest versions). Therefore, the execution order of hooks becomes a significant issue - we need to ensure that the boot loader update occurs before the signing process.
Users who use systemd-boot are probably familiar with the automatic update method using pacman hooks (see systemd boot - Automatic Updates). The document provides two methods:
- Install systemd-boot-pacman-hook (essentially downloading systemd-boot.hook)
- Manually write the given content to /etc/pacman.d/hooks/100-systemd-boot.hook.
As per the alpm-hooks documentation:
Hooks are run in alphabetical order of their file name, where the ordering ignores the suffix.
According to this rule, neither the system-boot.hook obtained from method 1 nor the 100-systemd-boot.hook written in method 2 can meet the requirement of executing before the signing hook. My solution is to use method 2 but rename the file to 90-systemd-boot.hook to satisfy the ordering requirement.
Handling of additional signing for the boot loader#
We have solved the first obstacle, but don't worry, there is another issue here.
We have listed the boot loader files that need to be additionally signed in sbupdate's EXTRA_SIGN. However, by examining the sbupdate source code lines 66-72 and lines 195-205, we can see that the -k parameter indicates that sbupdate is called by a hook. For security reasons, when sbupdate is called by a hook, it skips the content in EXTRA_SIGN, which is obviously not what we expect.
The solution is simple. Open /usr/share/libalpm/hooks/95-sbupdate.hook and remove the -k parameter.
Writing Keys to the BIOS#
After completing the above steps, we are almost ready. The last step is to write the keys to the BIOS.
Deleting Existing Keys#
By default, the BIOS comes with Microsoft keys. To write our own keys, we need to delete the existing keys.
In this step, you need to enter the BIOS, find the certificate management option for secure boot, and select delete.
Writing New Keys#
Use sbsigntools
to simplify the process of writing keys.
First, we need a directory like this:
/etc/secureboot/keys
├── db
├── dbx
├── KEK
└── PK
Create it with the following command:
mkdir -p /etc/secureboot/keys/{db,dbx,KEK,PK}
Then copy the *.auth
files from /etc/efi-keys to the corresponding directories (dbx is optional).
Finally, execute the following commands:
sbkeysync --verbose
sbkeysync --verbose --pk
If everything goes well without any errors, congratulations! You have completed the configuration of secure boot for Arch Linux. Now, go to the BIOS, enable the secure boot option, and start your system!
Conclusion#
In this article, I have listed all the steps I took to configure secure boot for my machine. However, I cannot guarantee that readers will be able to reproduce my success.
If you encounter any issues while following the steps in this article, I recommend referring to the original Arch Wiki. The original article includes multiple implementation methods for each step and provides detailed error handling, making it more representative than this article.