Secure your boot process: UEFI + Secureboot + EFISTUB + Luks2 + lvm + ArchLinux
This tutorial isn’t a basic setup how-to in a way you will learn how to install Arch Linux, neither is intended to replace the Installation Guide, This is a guide for those who want a laptop with data-at-rest encryption and a verified boot process using SecureBoot.
I’ll not be arrogant saying that this setup is “tampering-proof” since this also depends on your firmware manufacturer, but I believe that this is a notebook setup with good enough security.
What is this blogpost about
- Arch Linux setup overview.
- Basic secureboot explanation.
- Luks2+lvm setup for encrypted partitions at boot time.
/homedisk setup with crypttab.
- EFISTUB to make Linux “it’s own bootloader” avoiding the entire
/bootto be mounted on your ESP.
UEFI is the new standard for boot and firmware management and it isn’t perfect, but is a natural answer to the old BIOS standard that has it’s limitations and is not aging well considering those limits and all workarounds involved to break them. You can find more information here. BIOS standard first appeared in IBM computers in 1976 and should (hopefully) die soon.
To keep words/concepts best alligned with what is correct, i’ll not call your basic computer program BIOS but firmware from now on during this reading.
I bought a laptop and wanted to encrypt all my data and thought: “Hey, i can do a full disk encryption but what if someone tamper my MBR/Boot Sector? So, using secureboot whas the best alternative (even with efi having a plain
FAT32 partition on it’s standard).
There’s a lot of drama around secureboot, most of it related to Microsoft and the way they demand deploying their keys on OEM vendor equipments. That doesn’t mean that secureboot is bad.
Pretty simple “explain like i’m five” secureboot concept: A Root of Trust combination with keys and certificates. Using SecureBoot your firmware will check if the operating system you are trying to boot and your bootloader are trusted by you. On each boot-up UEFI firmware will inspect what you are trying to boot and if it’s not trusted a security violation will be triggered.
There are four main EFI “variables” used to create a basic secureboot Root of Trust environment:
- PK: The Platform Key, the master one, the ring to rule them all. The holder of a PK can install a new PK and update the KEK.
- KEK: Key Exchange Key is a secondary key used to sign EFI executables directly or a key used to signd the db and dbx databases.
- db: The signature databse is a list with all allowed signing certificates or criptografy hashes to allowed binaries. We will use THIS db key to sign our Linux Kernel.
- dbx: The dark side of the db. Inverse db. “not-good-db”. You name it. It’s the list containing all keys that are not allowed.
I would like to highlight the following points of this setup:
- Your signing keys are stored inside an encrypted disk.
- Kernel signing will only happend after you have booted and running an already signed kernel.
- Most notebooks today don’t have an exposed CMOS to keep configurations but instead they have nvram modules that will store firmware and configurations.
- So, put a passord on your firmware to avoid secureboot being disabled.
- Putting a password on your firmware will almost invalidate any chance of boot option change or secureboot disable.
- In my case there is no “reset bios password” option and losing it will require contacting Lenovo to replace the main board.
- Even with secureboot disabled, and attacker will not be able to decrypt your root partition without knowing your password
- If you are worried about keys being accessed after booting, you have other issues to solve and disk encryption + secureboot will not be the answer.
- Modern processors have
aes-niinstuction that will help on disk decryption avoiding high cpu usage for this task.
- Using a key to unlock luks
/homepartition is a way to increase convenience without sacrificing security. That key is stored inside another encrypted partition so, there is no much to worry about.
- lvm inside a luks container gives you a lot of flexibility. This will also remove any visibility if someone steal you equipment since lvs will be inside one container.
- Less error prone setup while manipulating
UUIDs is also an implicit feature.
- Less error prone setup while manipulating
With that in mind, lets install ArchLinux, first boot it and create the Root of Trust of your notebook.
Installing Arch Linux
There’s a plenty of “efi how-tos” for Arch Linux on the internet, and some of the instructions here will be just an overview of what you dear reader will have to execute
Step 01: Download Arch Linux here and write it to a pendrive using
dd bs=4M if=path/to/archlinux.iso of=/dev/sdx status=progress oflag=sync where
sdx is your pendrive. If you are using Windows to create your bootable pendrive Win32 Disk Imager will help you.
Step 02: Configure your firmware to boot using UEFI, but keep secure boot disabled. Allow boot from usb and change it to be your first boot device. These instructions are pretty much vendor dependent and can change depending on your equipment.
Step 03: Boot Arch Linux live usb, and after getting a shell change your keybord layout with the following command:
After that, connect to your wifi using
wifi-menu -o your_device. There is an issue with the latest Arch Linux iso(06/2020) and
wifi-menu is not working as expected. If you are using ethernet just ignore this step. Enable ntp sync with
timedatectl set-ntp true.
Step 04: Create
luks2 containers and
lvm2 volumes on the first disk. On my laptop i have 2 drives:
sda is a ssd while
sdb is a spinning disk. Use
cgdisk /dev/sda and create a 256MB(i’m using 512MB but noticed that is way too much) partition for EFI (ESP) code
ef00 and the rest of your disk space create a partition with code
Create your luks container and open it. Default block cipher and block encyption mode should be good enough so there is no need of changing it with
cryptsetup -y -v --use-random luksFormat /dev/sda2 cryptsetup luksOpen /dev/sda2 crypt
Create your lvm infraesturucture on top of it. I’ll create swap and root logical volumes
pvcreate /dev/mapper/crypt vgcreate vg0 /dev/mapper/crypt lvcreate --size 4G vg0 --name swap lvcreate --size 30G vg0 --name root
Format your ESP, root and swap partitions/volumes
mkfs.vfat -F32 /dev/sda1 mkfs.ext4 /dev/mapper/vg0-root mkswap /dev/mapper/vg0-swap
Step 05: Now create a
luks2 container without lvm on it cause we will use the full disk just for
/home and automatically map/mount it using
crypttab+fstab here. Instead of typing a password 2 times during boot(one for root, another for home), we will just type the password for the root partition and host a key inside this encrypted partition to open the home luks container. Using a key to open a luks device has the same risks as typing a password and storing it into your ram.
cgdisk /dev/sdb and create an all-disk partition using
8309 partition code.
cryptsetup -y -v --use-random luksFormat /dev/sdb1 cryptsetup luksOpen /dev/sdb1 crypthome mkfs.ext4 /dev/mapper/crypthome
Step 06: Mount all and start to install:
mount /dev/mapper/vg0-root /mnt mkdir /mnt/efi mkdir /mnt/home mount /dev/sda1 /mnt/efi mount /dev/mapper/crypthome /mnt/home pacstrap /mnt base base-devel vim efibootmgr linux linux-firmware lvm2 mkinitcpio networkmanager intel-ucode git efitools wget python
Do not install
intel-ucode if you are using an AMD processor.
Step 07: Create your
fstab and change root to your new system
genfstab -U /mnt >> /mnt/etc/fstab arch-chroot /mnt
Step 08: Change your fstab
/home mount point to use the device mapper name. If you try to mount it using
UUID it will fail cause it needs to be decrypted first.
# /home /dev/mapper/crypthome /home ext4 rw,relatime 0 2
Create a key to automatically open the home luks container. Change the “secretfolder” path example as you please.
mkdir /root/secretfolder chmod 700 /root/secretfolder dd bs=512 count=4 if=/dev/urandom of=/root/secretfolder/crypto_keyfile.bin
Find the UUID of your home luks container(
crypthome) and add it to your
/etc/crypttab. Crypttab columns are: mapping name(crypthome), luks partition UUID, key path and luks. You can check disks UUID by issuing
blkid /dev/yyy where
yyy could be a partition or a disk. In this case, use
crypthome UUID=29d3555d-cccc-yyyy-xxxx-xxxxxxxxxxxx /root/secretfolder/crypto_keyfile.bin luks
Step 09: Configure the rest of the system. Remember, this is just an overview of the Arch Linux installation and the focus here is on the secureboot aspect of this setup. In this step we will configure locale, localtime, keymap, hostname and user. I’m configuring a setup for a Brazilian Portuguese user so, change this info to reflect your language.
ln -s /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime hwclock --systohc echo LANG=pt_BR.UTF-8 > /etc/locale.conf echo KEYMAP=br-abnt2 > /etc/vconsole.conf echo hostname_i_want > /etc/hostname
pt_BR.UTF-8 UTF-8 line inside
/etc/locale.gen and generate this localization with:
Create a password for root, and the basic info for your user(change
myuser to your login):
passwd useradd -m -G wheel,users myuser passwd myuser
Step 10: Edit your
mkinitcpio.conf and include the
MODULES and change
cat. You can check my config file here. Recreate your initd:
mkinitcpio -p linux
You may have noticed the
i915 module on my
mkinitcpio.conf. That’s how you avoid video flickering during the boot process if you are a user of an Intel Integrated graphics card.
Step 11: Lets check if your motherboard is able to handle EFI entries using the following command:
bootctl status| grep -i "sets" ✓ Boot loader sets ESP partition information
If this option is marked with
✓ or a green square you will be able to set boot information on your motherboard directly. Otherwise, you’ll have to rely on a bootloader like
systemd-boot. You could obviously use the default EFI fallback option (
EFI/BOOT/BOOTX64.EFI) but the sofware we will use to automatically create the EFISTUB and sign it will not put your STUB on that location.
You can’t use grub here cause it does not support luks2 volumes yet (maybe 2.06 will do).
Step 12(optional): Install
systemd-boot as a first boot measurement for efi boot:
bootctl --esp-path=/efi install
We will use this bootloader for the very first time to keep things simpler and to have the flexibility to boot
KeyFile when we were ready to deploy our efi Root of Trust.
After signing our first kernel and after we are sure that we will not be locked outside we can get rid of
systemd-boot just by removing the
/efi/EFI/BOOT/BOOX64.EFI and changing the boot order with
default signed.conf editor no
title Arch efi /BOOT/Arch/linux-signed.efi
title KeyTool efi /BOOT/KeyTool.efi
cp /usr/share/efitools/efi/KeyTool.efi /efi/BOOT/KeyTool.efi
Step 13: Manually create your EFISTUB containing OS release data, command line options, kernel and initrd:
cryptdevice=UUID=08be6138-ffff-vvvv-dddd-tttttttttttt:lvm:allow-discards resume=/dev/mapper/vg0-swap root=/dev/mapper/vg0-root rw quiet i915.fastboot=1
cryptdevice is your luks2 partition. I’m using UUID here but you could use
=/dev/sda2 device path if you like but remember, UUIDs are better to make your system less error prone to disk changes.
resume parameter is not needed if you will not use hibernation.
root device needs to point to your
lvm2 mapping name,
quiet are pretty much standard boot options and
i915.fastboot=1 is used for that flickering behavior I’ve mentioned above.
Cd to your /boot dir and create the efi:
cd /boot objcopy \ --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000 \ --add-section .cmdline="cmdline.txt" --change-section-vma .cmdline=0x30000 \ --add-section .linux="vmlinuz-linux" --change-section-vma .linux=0x40000 \ --add-section .initrd="initramfs-linux.img" --change-section-vma .initrd=0x3000000 \ /usr/lib/systemd/boot/efi/linuxx64.efi.stub /efi/BOOT/Arch/linux-signed.efi
Step 13.1(optional): If you didn’t ran into step 12, you could just copy
/efi/BOOT/Arch/linux-signed.efi to the default EFI boot path
/efi/EFI/BOOT/BOOX64.EFI to have a first boot, and you could create manually a boot entry to your KeyTool efi.
systemd-boot is just a little helper during your setup.
If something goes wrong here, you can boot your Live usb Arch Linux and open your luks2 partitions with
cryptSetup luksOpen and remap all your volumegroups with
lvscan -a. Nothing to worry. You should be prompted luks root device password after your system start.
Creating your Root of Trust
There is no need to reinvent the wheel so, we will use a pretty good script from mr. Roderick W. Smith aka rodsbooks.com. Check out his page for tons of informations related to EFI and other Linux related stuff. Access http://www.rodsbooks.com/efi-bootloaders/controlling-sb.html#creatingkeys download the script directly:
su - root cd /root mkdir keys cd keys wget https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh
Let’s explain the contents on this script:
opensslcommands will basically create key and certificate pairs for PK, KEK and DB on X509 format
pythonline will randomly create a
GUIDfor our secureboot assets (think it like a name to our keys)
cert-to-efi-sig-listis the software that will convert X509 certificates(openssl ones) to a format that EFI can understand
touchwill crate an empty noPK file since we do not have a list of revoked keys
sign-efi-sig-listcommands will sign PK with itself, sign noPK using PK, sign KEK using PK and finally sign DB using KEK creating all your root trust.
After taking a look at the script, just run it :)
chmod +x mkkeys.sh ./mkkeys.sh
sbupdate software from AUR. Use an AUR helper (best choice is
yay from Blackarch repository) or build it by manually.
/etc/sbupdate.conf to change your signed EFISTUB output location and to also sign your
systemd-boot efi for now. Add your boot parameters on the
#KEY_DIR="/etc/efi-keys" ESP_DIR="/efi" OUT_DIR="BOOT/Arch" #SPLASH="/usr/share/systemd/bootctl/splash-arch.bmp" #BACKUP=1 EXTRA_SIGN=('/efi/EFI/BOOT/BOOTX64.EFI' '/efi/EFI/systemd/systemd-bootx64.efi') CMDLINE_DEFAULT="cryptdevice=UUID=08be6138-f43a-4270-b5a3-f93562e7ab19:lvm:allow-discards resume=/dev/mapper/vg0-swap root=/dev/mapper/vg0-root rw quiet i915.fastboot=1"
Copy all keys and certs to
cp /root/keys/*.key /etc/efi-keys cp /root/keys/*.crt /etc/efi-keys
sbupdate package will create some hooks to trigger EFISTUB generation and signing after each Linux package variant (
linux-zen…) update. The efi file output will always be named
<linuxpackagename>-signed.efi. You can test this behavior by updating/reinstalling your linux package with
pacman -S linux. There is no problem if you sign an efi file with secureboot disabled.
Or, you could manually sign your kernel with the following command:
sbsign --key /etc/efi-keys/DB.key --cert /etc/efi-keys/DB.crt --output /efi/BOOT/Arch/linux-signed.efi /efi/BOOT/Arch/linux-signed.efi
This will sign
/efi/BOOT/Arch/linux-signed.efi and output to
/efi/BOOT/Arch/linux-signed.efi. Remember to sign your
systemd-boot files too.
Deploying your Root of Trust
This step will be higly dependent on what hardware you are using. Some notebooks allow you to import your keys into firmware just by entering firmware setup, accessing the “Security” tab and pointing the files hosted on a
FAT32 usb drive. If your firmware does not have that option, you will have to copy your keys into a USB drive(or into your
ESP since its
FAT32) and deploy them. To copy to your ESP partition:
copy /root/keys/*.esl /efi/BOOT copy /root/keys/*.auth /efi/BOOT
You will need to be sure that Secure boot is in “setup mode” not “user mode”. Some notebooks also have this option explicitly described, but others like mine will trigger setup mode as soon as you hit “remove oem keys”. After enabling setup mode, boot into
KeyTool.efi entry. Backup the existing keys if you like, but I see no need to do it.
Now, add your keys following this order:
- Select the db entry, hit “Add new key”, and point to
- Select the kek entry, hit “Add new key” and point to
- Finally, add the Platform Key(PK), select “Replace Keys” and point to
- Exit KeyTool and reboot
- Enable Secure Boot
- Obviously remove all keys that are hosted on your ESP partition and KeyTool.efi(from now on, KeyTool will not work since is not signed and Secure Boot should be in user mode). Use a removal tool like
blackarch/secure-deleteto reduce the chances of recovery, or even
ddto create a big file with the size of the available space of your ESP partition.
Making Linux it’s own bootloader
If your motherboard lets you create boot entries(Step 11), create an Arch Linux entry:
efibootmgr --create --disk /dev/sda --part 1 --label "ArchLinux" --loader "BOOT\Arch\linux-signed.efi" --verbose
Update: ran into some issues with this word parameter syntax while trying to reproduce this environment on kvm. Solved with:
efibootmgr -c -d /dev/sda -p 1 --label "ArchLinux" -l "BOOT\Arch\linux-signed.efi" --verbose
This command is pretty self-explained: ESP disk, ESP partition, label and efi location.
Now, lets check the boot order
[root@walhala ~]# efibootmgr BootCurrent: 0000 Timeout: 0 seconds BootOrder: 0000,0002,2001,2002,2003 Boot0000* Linux Boot Manager Boot0002* ArchLinux Boot2001* EFI USB Device Boot2002* EFI DVD/CDROM Boot2003* EFI Network
Numbers could change in your setup but on my laptop
Boot0000. If you delete this entry, next in order will be
0002 so, there is no need to manually order your boot entries:
[root@walhala ~]# efibootmgr -b 0000 -B BootCurrent: 0002 Timeout: 0 seconds BootOrder: 0002,2001,2002,2003 Boot0002* ArchLinux Boot2001* EFI USB Device Boot2002* EFI DVD/CDROM Boot2003* EFI Network
ArchLinux isn’t your first boot option, reorder it by issuing
efibootmgr -o 0002,2001,2020 with the corresponding boot numbers of your list.
Reboot and test. Now, you should have a fully functional secureboot+efistub+luks setup :). Double-check secure boot:
[root@walhala ~]# dmesg | grep -i secure [ 0.015260] Secure boot enabled
After that, you are free to remove any
systemd-boot related files(line below) from your system and comment the following line on your
sbupdate.conf configuration file
Security isn’t a “one pill” medicine. There’s plenty of room for other tools to create a more secure environment:
tpm2boot policies to create a Security Violation if boot options are changed
usbguardto avoid tricky devices like those usb drivers that are actually HIDs under-the-hood
- Setup a vpn client to use on public wifi hostpots you don’t trust much
- Create a fake windows installation partition before your root luks partition
Those are subjects to other blogposts :)