This document describes how nbc handles Secure Boot for both GRUB2 and systemd-boot bootloaders.
Secure Boot is a UEFI feature that ensures only signed bootloaders can execute. The trust chain works as follows:
- UEFI Firmware trusts Microsoft's UEFI CA
- Shim is signed by Microsoft, so firmware trusts it
- Shim contains the distro's key (e.g., Debian, Fedora) and trusts binaries signed by that key
- Bootloader (GRUB or systemd-boot) is signed by the distro, so shim trusts it
- Kernel is either signed or loaded via MOK (Machine Owner Key)
Shim is the critical component for Secure Boot. Key facts:
- Signed by Microsoft: UEFI firmware trusts it
- Contains distro key: Can verify distro-signed binaries
- Hardcoded to load
grubx64.efi: Looks for this file in the same directory - Only verifies signature: Doesn't care what grubx64.efi actually is
This last point is crucial: shim will happily load a signed systemd-boot binary as long as it's named grubx64.efi and signed by the distro key.
/boot/EFI/
├── BOOT/
│ ├── BOOTX64.EFI ← shimx64.efi.signed (957KB)
│ ├── grubx64.efi ← systemd-bootx64.efi.signed (125KB) - NOT GRUB!
│ └── mmx64.efi ← mmx64.efi.signed (850KB, optional)
└── systemd/
└── systemd-bootx64.efi ← copy for bootctl discoverability
/boot/EFI/
├── BOOT/
│ ├── BOOTX64.EFI ← shimx64.efi
│ ├── grubx64.efi ← signed grubx64.efi from container
│ └── mmx64.efi ← MOK manager (optional)
└── fedora/ ← or centos, redhat
└── grub.cfg ← GRUB configuration
| Binary | Location in Container |
|---|---|
| Shim | /usr/lib/shim/shimx64.efi.signed |
| MOK Manager | /usr/lib/shim/mmx64.efi.signed |
| systemd-boot | /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed |
| Fallback | /usr/lib/shim/fbx64.efi.signed (DO NOT USE) |
| Binary | Location in Container |
|---|---|
| Shim | /boot/efi/EFI/{distro}/shimx64.efi |
| GRUB | /boot/efi/EFI/{distro}/grubx64.efi |
| MOK Manager | /boot/efi/EFI/{distro}/mmx64.efi |
The fallback bootloader (fbx64.efi) causes a "Restore Boot Option" blue screen because:
- fbx64.efi looks for
EFI/<distro>/BOOTX64.CSV - Our setup uses
EFI/BOOT/(removable media path) - When CSV is not found, fbx64.efi shows the blue screen
We use efibootmgr to register boot entries instead.
grub-installproduces unsigned GRUB EFI binaries- These will be rejected by Secure Boot
- Always use the signed binaries from the container image
- Distro signing keys are not in UEFI firmware's trust store
- Only Microsoft-signed binaries (like shim) are trusted directly
- Must go through shim chain
- Container extraction may create lowercase
efi - FAT32 is case-insensitive but case-preserving
- Use two-step rename:
efi→efi_tmp→EFI
Cause: fbx64.efi is being executed
Solution: Remove fbx64.efi from EFI/BOOT/
# From rescue environment
mount /dev/sda1 /mnt
rm /mnt/EFI/BOOT/fbx64.efi
umount /mnt
rebootCause: Secure Boot rejected an unsigned or incorrectly-signed binary
Solutions:
- Ensure shim is used as BOOTX64.EFI (not systemd-boot directly)
- Verify grubx64.efi is the signed binary from the container
- Check that shim and bootloader are from the same distro
Cause: Boot order not set correctly
Solution:
# Check current order
efibootmgr -v
# Set your OS first (replace 0008 with your boot entry)
efibootmgr -o 0008,0002,0003Possible causes:
- Secure Boot not enabled in firmware
- Booted directly, not through shim
Verification:
mokutil --sb-state # Should say "SecureBoot enabled"This section documents the debugging process that led to the current implementation.
After installing a Debian system with systemd-boot using nbc, Secure Boot failed with various symptoms including "Restore Boot Option" blue screen.
- Tried using
grub-installoutput directly - Result: Secure Boot rejected the unsigned binary
- Assumption: Distro-signed binaries are in Microsoft's trust chain
- Reality: They're not - only shim is Microsoft-signed
- Result: "Access Denied"
- Included fbx64.efi thinking it was needed for boot recovery
- Result: "Restore Boot Option" blue screen
- Root cause: fbx64.efi couldn't find BOOTX64.CSV
- Assumed systemd-boot couldn't work as grubx64.efi because it "needs to know its path"
- This was wrong - systemd-boot finds loader.conf relative to ESP root
- Wasted time trying alternative approaches
- Shim as BOOTX64.EFI - Microsoft-signed, trusted by firmware
- Signed systemd-boot as grubx64.efi - Distro-signed, trusted by shim
- MOK manager - For key enrollment if needed
- NO fbx64.efi - Causes blue screen
Shim doesn't care what grubx64.efi actually is. It only:
- Looks for a file named
grubx64.efiin the same directory - Verifies the signature against the embedded distro key
- Loads and executes it if signature is valid
This means systemd-boot works perfectly as grubx64.efi because:
- It's signed by Debian's key
- Shim trusts Debian's key
- systemd-boot doesn't care what filename it's loaded as
# Create VM with Secure Boot enabled
incus launch images:debian/trixie myvm --vm \
-c security.secureboot=true
# Attach install ISO
incus config device add myvm iso disk \
source=/path/to/installer.iso boot.priority=10
# Start and connect
incus start myvm
incus console myvm# Inside the running system
mokutil --sb-state
# Should output: SecureBoot enabled
bootctl status
# Should show: Secure Boot: enabled (user)# Check file sizes to identify binaries
ls -la /boot/EFI/BOOT/
# Expected:
# BOOTX64.EFI ~957KB (shim)
# grubx64.efi ~125KB (systemd-boot) or ~2MB (GRUB)
# mmx64.efi ~850KB (MOK manager)pkg/bootloader.go- Main bootloader installation codesetupSystemdBootSecureBootChain()- systemd-boot Secure Boot setupsetupSecureBootChain()- GRUB2 Secure Boot setupfindShimEFI(),findSignedSystemdBootEFI(), etc. - Binary locators