This article will guide you through a basic installation of Arch Linux using UKI, root partition encryption with LUKS while allowing drive decryption either via passphrase of a FIDO2 hardware key.

Verify following before starting!

  • Your computer supports SecureBoot/UEFI
  • Your computer allows for enrollment of your own secureboot keys

Preparation

  1. create a bootable USB
  2. Reboot to UEFI/BIOS and enable Secure Boot setup mode.
  3. Boot into Arch Linux USB

Network configuration

Wired connections should work out of the box. You can verify connection by running:

ping archlinux.org

To connect to WiFi run:

iwctl station wlan0 connect <SSID>

Disk partitioning

Using your favourite tool, create two partitions:

  • 512MB size -> EFI, in my case /dev/nvme0n1p1
  • Remaining space -> LUKS encrypted root partition, /dev/nvme0n1p2

Format EFI:

mkfs.fat -F32 /dev/nvme0n1p1

LUKS setup

Create encrypted volume:

cryptsetup luksFormat --type luks2 /dev/nvme0n1p2

Decrypt created volume:

cryptsetup open --perf-no_read_workqueue --perf-no_write_workqueue --persistent /dev/nvme0n1p2 cryptlvm

--perf options are optional and recommended for SSDs

Configuring LVM

If you want a more advanced setup follow instructions on the wiki, for simplicity’s sake I’ll go with a single root volume:

pvcreate /dev/mapper/cryptlvm
vgcreate vg /dev/mapper/cryptlvm
lvcreate -l 100%FREE vg -n root

Format created volume(s):

mkfs.ext4 /dev/vg/root

Mounting drives

Nothing crazy here, just mount created partitions:

mount /dev/vg/root /mnt
mkdir -p /mnt/boot/efi
mount /dev/nvme0n1p1 /mnt/boot/efi

remember to mount all other partitions when using a different partition scheme!

System bootstrapping

Install core packages:

pacstrap /mnt \
    base base-devel \
    linux-zen linux-firmware \
    man neovim git networkmanager \
    lvm2 dracut efibootmgr binutils libfido2 \
    sbctl sbsigntools \
    intel-ucode # use amd-ucode for AMD CPUs

base-devel is technically not required for this setup but it’s required to install AUR packages

Generate fstab:

genfstab -U /mnt > /mnt/etc/fstab

Chroot

Chroot into your new system:

arch-chroot /mnt

Configure timezone

ln -sf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime
hwclock --systohc

Replace Europe/Warsaw with your timezone

Generate locale

sed -i -e 's/#pl/pl/' -e 's/#en_US/en_US/' /etc/locale.gen
locale-gen
echo 'LANG=en_US.UTF-8' > /etc/locale.conf

Set hostname

echo 'archlinux' > /etc/hostname

Create non-root user

To create user run:

useradd -m <user>
passwd <user>

And to grant sudo privileges:

echo '<user> ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/<user>

omit NOPASSWD: if you prefer using a password with sudo

Start NetworkManager

systemctl enable NetworkManager

Pacman hooks

For Unified Kernel Images to work properly we’ll need to create few scripts that will hook into pacman:

For image creation:

/usr/local/bin/dracut-install.sh

#!/usr/bin/env bash

mkdir -p /boot/efi/EFI/Linux

while read -r line; do
    if [[ "$line" == 'usr/lib/modules/'+([^/])'/pkgbase' ]]; then
        kver="${line#'usr/lib/modules/'}"
        kver="${kver%'/pkgbase'}"

        dracut --force --uefi --kver "$kver" /boot/efi/EFI/Linux/arch-linux.efi
    fi
done

And for image removal:

/usr/local/bin/dracut-remove.sh

#!/usr/bin/env bash
rm -f /boot/efi/EFI/Linux/arch-linux.efi

Remember to make scripts executable:

chmod +x /usr/local/bin/dracut-*

Now create pacman hooks:

mkdir /etc/pacman.d/hooks

Hook for install/upgrade:

/etc/pacman.d/hooks/90-dracut-install.hook

[Trigger]
Type = Path
Operation = Install
Operation = Upgrade
Target = usr/lib/modules/*/pkgbase

[Action]
Description = Updating linux EFI image
When = PostTransaction
Exec = /usr/local/bin/dracut-install.sh
Depends = dracut
NeedsTargets

And for removal:

/etc/pacman.d/hooks/60-dracut-remove.hook

[Trigger]
Type = Path
Operation = Remove
Target = usr/lib/modules/*/pkgbase

[Action]
Description = Removing linux EFI image
When = PreTransaction
Exec = /usr/local/bin/dracut-remove.sh
NeedsTargets

Dracut configuration

Configure kernel parameters:

cat << EOF > /etc/dracut.conf.d/cmdline.conf
kernel_cmdline="rd.luks.uuid=luks-$(blkid -s UUID -o value /dev/nvme0n1p2) rd.luks.options=fido2-device=auto rd.lvm.lv=vg/root root=/dev/mapper/vg-root rootfstype=ext4 rootflags=rw,relatime"
EOF

Set dracut flags:

cat << EOF > /etc/dracut.conf.d/flags.conf
compress="zstd"
hostonly="no"
EOF

Enable FIDO2 support:

echo 'add_dracutmodules+=" fido2 "' > /etc/dracut.conf.d/fido2-module.conf

Build the image

Now reinstalling the kernel (or installing any other kernel) should generate a proper image:

pacman -S linux-zen

Add image to UEFI

First, check existing entries:

efibootmgr

Any not needed entries can be removed with:

efibootmgr -b <index> -B

To create boot entry for your image run:

efibootmgr --create --disk /dev/nvme0n1 --part 1 --label "Arch Linux" --loader 'EFI\Linux\arch-linux.efi' --unicode

Now, check which index is assigned to created boot entry and set it as default:

efibootmgr -o <index>

Now, reboot and log back in.

Secure Boot

First, verify that Secure Boot is in setup mode:

# sbctl status
Installed:      ✘ Sbctl is not installed
Setup Mode:     ✘ Enabled
Secure Boot:    ✘ Disabled

If not, reboot to UEFI:

systemctl reboot --firmware-setup

And enable setup mode for Secure Boot

Each BIOS is different, check manual for your device for additional info

Create keys and sign binaries

sbctl create-keys
sbctl sign -s /boot/efi/EFI/Linux/arch-linux.efi

Configure dracut to use created keys:

cat << EOF > /etc/dracut.conf.d/secureboot.conf
uefi_secureboot_cert="/usr/share/secureboot/keys/db/db.pem"
uefi_secureboot_key="/usr/share/secureboot/keys/db/db.key"
EOF

Replace sbctl’s pacman hook:

/etc/pacman.d/hooks/zz-sbctl.hook

[Trigger]
Type = Path
Operation = Install
Operation = Upgrade
Operation = Remove
Target = boot/*
Target = efi/*
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/**/efi/*.efi*

[Action]
Description = Signing EFI binaries...
When = PostTransaction
Exec = /usr/bin/sbctl sign /boot/efi/EFI/Linux/arch-linux.efi

Enroll generated keys:

sbctl enroll-keys

If you want to dual-boot with Windows add --microsoft flag

Reboot and verify Secure Boot with sbctl:

# sbctl status
Installed:	✓ sbctl is installed
Owner GUID:	<your guid>
Setup Mode:	✓ Disabled
Secure Boot:	✓ Enabled

Adding FIDO2 key to LUKS

Nothing complicated here, simply run:

systemd-cryptenroll /dev/nvme0n1p2 --fido2-device=auto

For additional settings consult the manpage

Reboot and verify that your FIDO2 key is detected.

Post-installation

Congratulations, now configure your system as you see fit.

Sources

This guide was heavily based on Ataraxxia’s secure-arch guide, 459below’s Debian fido2 with dracut boot and a few hours of digging through Arch Wiki.