If you run Arch Linux on a mirrored ZFS root pool, you likely have redundant EFI System Partitions (ESPs) mapped to multiple NVMe drives for resilience.

However, protecting this boot path with Secure Boot can be a challenge. With the use of Secure Boot key manager you can take ownership of your motherboard’s platform security, automat syncing across multiple drives, and verify the integrity of your native ZFS boot environment.

The Tools

  • ZFSBootMenu: ZFSBootMenu is a Linux bootloader that attempts to provide an experience similar to FreeBSD’s bootloader. It is built on an initramfs that can natively discover, import, and boot from ZFS pools. It has plenty of other nifty tricks too.
  • sbctl: This tool intends to be a user-friendly secure boot key manager capable of setting up secure boot, offer key management capabilities, and keep track of files that needs to be signed in the boot chain.

Aligning the ZFSBootMenu Configuration

ZFSBootMenu includes a tool, generate-zbm, that can be used to build and bundle all necessary components for a initramfs into a single Unified Kernel Image (UKI). It uses a special file, /etc/zfsbootmenu/config.yaml, to manage this process. The docs for the config.yaml can be found here

The key things to set in config.yaml:

  1. ManageImages: true - without this generate-zbm will do nothing.
  2. Enabled: false inside Components - make sure it makes a single UKI.
  3. Versions: false inside EFI - make sure it doesn’t version control the file name.
  4. Prefix: VMLINUZ inside Kernel - make sure the final filenames match the exact capitalization expected (e.g., VMLINUZ.EFI and VMLINUZ-BACKUP.EFI)

An example of my config.yaml file.

Global:
  ManageImages: true
  BootMountPoint: /boot/efi
  DracutConfDir: /etc/zfsbootmenu/dracut.conf.d
  PreHooksDir: /etc/zfsbootmenu/generate-zbm.pre.d
  PostHooksDir: /etc/zfsbootmenu/generate-zbm.post.d
  InitCPIOConfig: /etc/zfsbootmenu/mkinitcpio.conf
Components:
  Enabled: false
EFI:
  ImageDir: /boot/efi/EFI/ZBM
  Versions: false
  Enabled: true
  SplashImage: /etc/zfsbootmenu/splash.bmp
Kernel:
  CommandLine: ro quiet loglevel=0
  Prefix: VMLINUZ

Synchronizing Redundant ESPs via Post-Hooks

By default, generate-zbm only knows how to write to its primary mount point (/boot/efi). If you maintain a secondary mirror drive mounted at /boot/efi1, you can utilize ZFSBootMenu’s native hook framework to clone your boot loader automatically upon creation.

Here is the post-generate script I am using to keep the directories synced.

sudo tee "/etc/zfsbootmenu/generate-zbm.post.d/sync-backup-esp" > /dev/null <<'EOF'
#!/bin/bash
SOURCE_DIR="/boot/efi/EFI/ZBM"
TARGET_DIR="/boot/efi1/EFI/ZBM"

if [ -d "$SOURCE_DIR" ] && [ -d "/boot/efi1/EFI" ]; then
    echo "--- Syncing ZFSBootMenu to secondary ESP (/boot/efi1) ---"
    mkdir -p "$TARGET_DIR"
    rsync -av --delete "$SOURCE_DIR/" "$TARGET_DIR/"
else
    echo "WARNING: Secondary ESP missing. Sync skipped."
fi
EOF

sudo chmod +x /etc/zfsbootmenu/generate-zbm.post.d/sync-backup-esp

NOTE: the post-generation script directory processing framework ignores files with shell extensions, so drop the .sh suffix. Also, the echo never print. Or at least, I’ve never seen them print. I didn’t get that to work so I gave up.

Fixing the Hostid Mismatch

Before cooking the new images, verify that your active system hostid matches what your ZFS module expects. A mismatch will cause ZFSBootMenu to drop to a recovery shell because it assumes the pool belongs to another physical computer.

If your generator throws a hostid warning, force-sync it:

sudo rm -f /etc/hostid
sudo zgenhostid 00bab10c

(Replace 00bab10c with the specific hostid requested by your pool).

Regenerate your images to bake the correct hostid into the initramfs:

sudo generate-zbm

Enrolling Keys and Securing the Boot Chain

With your firmware in Setup Mode, install sbctl and initialize your platform keys.

sudo pacman -S sbctl
sudo sbctl create-keys

Next, enroll your keys into the motherboard’s NVRAM. Use the -m flag to include Microsoft’s standard OEM keys alongside yours. This ensures option ROMs on internal components (like graphics cards) and dual-boot continue to work.

sudo sbctl enroll-keys -m

Verify the status:

sudo sbctl status

Signing Binaries Across Both Drives

The motherboard will now instantly reject any untrusted binary. Instruct sbctl to sign and track (-s) all four ZFSBootMenu images distributed across your primary and secondary NVMe drives:

# Primary ESP files
sudo sbctl sign -s /boot/efi/EFI/ZBM/VMLINUZ.EFI
sudo sbctl sign -s /boot/efi/EFI/ZBM/VMLINUZ-BACKUP.EFI

# Secondary ESP files
sudo sbctl sign -s /boot/efi1/EFI/ZBM/VMLINUZ.EFI
sudo sbctl sign -s /boot/efi1/EFI/ZBM/VMLINUZ-BACKUP.EFI

Finally, verify the state of your boot paths:

$ sudo sbctl verify
✓ /boot/efi/EFI/ZBM/VMLINUZ.EFI is signed
✓ /boot/efi/EFI/ZBM/VMLINUZ-BACKUP.EFI is signed
✓ /boot/efi1/EFI/ZBM/VMLINUZ.EFI is signed
✓ /boot/efi1/EFI/ZBM/VMLINUZ-BACKUP.EFI is signed

Because sbctl integrates directly with pacman hooks, any future upstream upgrades to your kernel or ZFSBootMenu system will automatically re-build, mirror across your hardware array, and sign the resulting binaries out of the box.

Backup