Secure Boot
Keystone integrates UEFI Secure Boot through Lanzaboote, a tool that signs NixOS boot components with custom keys. Secure Boot ensures that only trusted code executes during the boot process, forming the foundation of the trust chain that TPM-based disk encryption relies on. This page covers how Secure Boot works in Keystone, the key enrollment process, verification procedures, and key management.
How Secure Boot works
UEFI Secure Boot is a firmware feature that verifies the digital signature of every executable loaded during boot. If a binary is not signed by a trusted key, the firmware refuses to execute it. This prevents bootkits, rootkits, and unauthorized operating systems from running.
Keystone uses custom Secure Boot keys rather than relying on the pre-installed Microsoft keys found on most consumer hardware. This means the system trusts only binaries signed by the owner's keys, providing full control over the boot chain.
Lanzaboote
Lanzaboote replaces systemd-boot as the bootloader when Secure Boot is enabled. It performs the same function (loading the Linux kernel and initrd) but additionally signs all boot components with the machine's custom Secure Boot keys.
When keystone.os.secureBoot.enable is true, the module:
- Enables Lanzaboote with the PKI bundle stored at
/var/lib/sbctl. - Disables systemd-boot (Lanzaboote provides its own bootloader).
- Installs
sbctlfor key management. - Registers an activation script that provisions keys on first boot.
keystone.os.secureBoot = {
enable = true; # default: true
};The Secure Boot module requires an x86_64-linux system and EFI variables access (boot.loader.efi.canTouchEfiVariables = true, which the storage module enables automatically).
UEFI Setup Mode and User Mode
UEFI firmware operates in one of two modes with respect to Secure Boot:
Setup Mode exists when no Platform Key (PK) is enrolled. In this mode:
- Secure Boot firmware is present but not enforcing signature checks.
- Unsigned code is allowed to execute, including the Keystone installer.
- All key variables (PK, KEK, db, dbx) can be modified freely.
- The system transitions to User Mode once a Platform Key is enrolled.
User Mode is active after the Platform Key has been enrolled. In this mode:
- Secure Boot signature verification is enforced.
- Only binaries signed by keys in the
db(signature database) are allowed to execute. - Key variables can only be modified by entities holding the appropriate keys.
New hardware typically ships in Setup Mode or with Microsoft keys pre-enrolled. The Keystone installer expects Setup Mode so that it can enroll custom keys during the first boot.
Verifying the current mode
bootctl statusSetup Mode output:
System:
Firmware: UEFI 2.70 (EDK II 1.00)
Secure Boot: disabled (setup)
Setup Mode: setupUser Mode output (after key enrollment):
System:
Firmware: UEFI 2.70 (EDK II 1.00)
Secure Boot: enabled (user)
Setup Mode: userKey enrollment
Automatic enrollment during first boot
Keystone provisions Secure Boot keys automatically during the first NixOS activation after deployment. The provisioning script (modules/os/scripts/provision.sh) performs the following steps:
- Detect Setup Mode. The script reads the
SetupModeEFI variable. If the system is already in User Mode with valid keys, provisioning is skipped. - Generate keys. If no keys exist at
/var/lib/sbctl/keys,sbctl create-keysgenerates a complete set:- PK (Platform Key): The root of trust. Enrolling the PK transitions the firmware from Setup Mode to User Mode.
- KEK (Key Exchange Key): Authorizes updates to the signature database.
- db (Signature Database): Contains the keys used to verify boot binaries.
- Enroll keys. The script runs
sbctl enroll-keys --yes-this-might-brick-my-machineto write the keys into the UEFI firmware. Microsoft certificates are not included by default, meaning only Keystone-signed binaries are trusted. - Transition to User Mode. After enrollment, the firmware transitions to User Mode and Secure Boot enforcement begins on the next reboot.
Key storage
Secure Boot keys are stored at /var/lib/sbctl/keys with the following structure:
/var/lib/sbctl/keys/
├── PK/
│ ├── PK.key # Platform Key private key
│ └── PK.pem # Platform Key certificate
├── KEK/
│ ├── KEK.key # Key Exchange Key private key
│ └── KEK.pem # Key Exchange Key certificate
└── db/
├── db.key # Signature Database private key
└── db.pem # Signature Database certificateThese keys are generated on the target machine and never leave it. They are stored on the encrypted root filesystem, so they are protected by the disk encryption layer.
Manual key management with sbctl
The sbctl tool is installed automatically when Secure Boot is enabled. Common operations include:
# Check Secure Boot status and signed files
sudo sbctl status
# List signed EFI binaries
sudo sbctl list-files
# Verify all signed files are correctly signed
sudo sbctl verify
# Sign a new EFI binary
sudo sbctl sign /path/to/binary.efi
# Re-sign all enrolled binaries (after key rotation)
sudo sbctl sign-allVerification
Verifying Secure Boot status
After enrollment and reboot, confirm that Secure Boot is active:
bootctl status | grep "Secure Boot"
# Expected: Secure Boot: enabled (user)Verifying signed binaries
Confirm that all boot components are properly signed:
sudo sbctl verifyThis command checks every enrolled binary against the current Secure Boot keys. All entries should show as properly signed. If any binary is unsigned or signed with a different key, Lanzaboote will fail to boot it.
Inspecting EFI variables directly
For lower-level verification, the EFI variables can be read from sysfs:
# Check SetupMode (0 = User Mode, 1 = Setup Mode)
od --address-radix=n --format=u1 \
/sys/firmware/efi/efivars/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c
# Check SecureBoot (0 = not enforcing, 1 = enforcing)
od --address-radix=n --format=u1 \
/sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c
# List all Secure Boot related variables
ls /sys/firmware/efi/efivars/ | grep -i secureResetting to Setup Mode
In some situations, it may be necessary to return the firmware to Setup Mode. This is required when:
- Re-testing the key enrollment process.
- Recovering from a bricked Secure Boot configuration.
- Rotating Secure Boot keys.
On physical hardware
Most UEFI firmware provides an option in the BIOS settings to clear Secure Boot keys or reset to Setup Mode. The exact location varies by manufacturer but is typically found under "Security" or "Boot" settings.
On virtual machines
The bin/virtual-machine script provides a dedicated command:
# Shut down the VM
virsh shutdown keystone-test-vm
# Reset NVRAM to Setup Mode
./bin/virtual-machine --reset-setup-mode keystone-test-vm
# Start the VM
virsh start keystone-test-vmAlternatively, delete and recreate the VM to start with a fresh NVRAM:
./bin/virtual-machine --reset keystone-test-vm
./bin/virtual-machine --name keystone-test-vm --startRelationship to TPM enrollment
Secure Boot and TPM enrollment are tightly coupled in Keystone. The TPM module requires Secure Boot to be enabled (keystone.os.tpm.enable asserts keystone.os.secureBoot.enable).
The connection works through PCR 7 (Secure Boot certificates). When TPM enrollment binds the disk encryption key to PCR 7, it creates a dependency: the disk will only unlock automatically when the same Secure Boot keys are active. If Secure Boot is disabled or the keys change, the PCR 7 value changes, and the TPM refuses to unseal the disk encryption key.
This means:
- Secure Boot protects the boot chain. Only signed code executes.
- TPM protects the disk encryption key. The key is only released when the boot chain is verified.
- Together they ensure that an attacker cannot boot an unauthorized OS to extract data from the encrypted disk.
After re-enrolling Secure Boot keys (which changes PCR 7), TPM enrollment must be redone. See Disk encryption for the re-enrollment procedure.
Troubleshooting
"Access Denied" on boot
This error occurs when Secure Boot is in User Mode but the boot binary is not signed by a trusted key. Common causes:
- NixOS was rebuilt but Lanzaboote did not sign the new kernel. Run
sudo sbctl sign-alland reboot. - The PKI bundle at
/var/lib/sbctlis corrupted or missing. Regenerate keys in Setup Mode.
Firmware does not transition to User Mode
If bootctl status still shows Setup Mode after enrollment:
- Verify that the enrollment command completed without errors.
- Some firmware requires a reboot before the mode change takes effect.
- Check that the firmware supports custom key enrollment (some locked-down firmware only accepts Microsoft keys).
Keys exist but Secure Boot shows "disabled"
This can occur if:
- Secure Boot was disabled in the BIOS settings. Re-enable it.
- The firmware was reset or updated, clearing the enrolled keys. Re-enter Setup Mode and re-run the provisioning by removing
/var/lib/sbctl/keysand rebuilding.
VM testing
Keystone provides tooling for testing Secure Boot in virtual machines with full UEFI firmware emulation. The bin/virtual-machine script creates libvirt VMs with OVMF firmware in Setup Mode, including TPM 2.0 emulation. This allows testing the complete enrollment flow without physical hardware. See Testing for detailed VM testing procedures.
See also
- Disk encryption for how TPM enrollment depends on the Secure Boot state
- Testing for Secure Boot VM testing workflows
- Getting started for Secure Boot key enrollment during initial installation