237 lines
7.4 KiB
Markdown
237 lines
7.4 KiB
Markdown
# Quick Start: NixOS Secure Boot
|
|
|
|
This document attempts to guide users into setting up UEFI Secure Boot
|
|
for their NixOS system using a custom key chain. The audience are
|
|
experienced NixOS users.
|
|
|
|
This guide has been tested on a Lenovo Thinkpad and is expected to
|
|
work on other Thinkpads without change. On other systems, certain
|
|
steps may be different.
|
|
|
|
## ⚠ Disclaimers ⚠
|
|
|
|
Secure Boot for NixOS is still in development and has some sharp
|
|
edges. There may be cases where you end up with a system that does not
|
|
boot.
|
|
|
|
**We only recommend this to NixOS users that are comfortable using
|
|
recovery tools to restore their system or have a backup ready.**
|
|
|
|
## Requirements
|
|
|
|
To be able to setup Secure Boot on your device, NixOS needs to be
|
|
installed in UEFI mode and
|
|
[`systemd-boot`](https://www.freedesktop.org/wiki/Software/systemd/systemd-boot/)
|
|
must be used as a boot loader.
|
|
|
|
These prerequisites can be checked via `bootctl status`:
|
|
|
|
```console
|
|
$ bootctl status
|
|
System:
|
|
Firmware: UEFI 2.70 (Lenovo 0.4720)
|
|
Secure Boot: disabled (disabled)
|
|
TPM2 Support: yes
|
|
Boot into FW: supported
|
|
|
|
Current Boot Loader:
|
|
Product: systemd-boot 251.7
|
|
...
|
|
```
|
|
|
|
In the `bootctl` output, the firmware needs to be `UEFI` and the
|
|
current boot loader needs to be `systemd-boot`. If this is the case,
|
|
you are all set to continue.
|
|
|
|
## Part 1: Preparing Your System
|
|
|
|
In the first part, we will prepare everything on the software side of
|
|
things. At the end of this part, you will have your own Secure Boot
|
|
keys and a NixOS that has signed boot binaries.
|
|
|
|
### Finding the UEFI System Partition (ESP)
|
|
|
|
The UEFI boot process revolves around a special partition on the
|
|
disk. This partition is called _ESP_, the (U)EFI System
|
|
Partition. This partition is by convention mounted at `/boot` on NixOS
|
|
and the rest of this document assumes this.
|
|
|
|
You can verify that `/boot` is the ESP by looking for `ESP:` in
|
|
`bootctl status` output.
|
|
|
|
### Creating Your Keys
|
|
|
|
To create Secure Boot keys, we use `sbctl`, a popular Secure Boot Key
|
|
Manager. `sbctl` is available in
|
|
[Nixpkgs](https://github.com/NixOS/nixpkgs) as `pkgs.sbctl`.
|
|
|
|
Once you have installed sbctl (or entered a Nix shell), creating your
|
|
Secure Boot keys requires this command:
|
|
|
|
```console
|
|
$ sudo sbctl create-keys
|
|
[sudo] password for julian:
|
|
Created Owner UUID 8ec4b2c3-dc7f-4362-b9a3-0cc17e5a34cd
|
|
Creating secure boot keys...✓
|
|
Secure boot keys created!
|
|
```
|
|
|
|
This takes a couple of seconds. When it is done, your Secure Boot keys
|
|
are located in `/etc/secureboot`. `sbctl` sets the permissions of the
|
|
secret key so that only root can read it.
|
|
|
|
### Switching to bootspec
|
|
|
|
`lzbt` currently doesn't handle
|
|
non-[bootspec](https://github.com/grahamc/rfcs/blob/bootspec/rfcs/0125-bootspec.md)
|
|
generations well
|
|
([#55](https://github.com/nix-community/lanzaboote/issues/55)). As
|
|
such, we need to switch to bootspec and get rid of all previous
|
|
generations before we can continue.
|
|
|
|
Bootspec is currently available as preview in nixpkgs unstable. To
|
|
enable bootspec, set `boot.bootspec.enable = true;` in your system
|
|
configuration, rebuild and reboot.
|
|
|
|
When everything is working, you can garbage collect your old
|
|
non-bootspec generations: `nix-collect-garbage -d`.
|
|
|
|
🔪 **Sharp edge:** 🔪 This will leave old boot entries lying around in
|
|
the ESP. `systemd-boot` will display these during boot. This can be
|
|
confusing during boot. **After you made a backup of your ESP**, you
|
|
may delete these entries in `/boot/loader/entries`.
|
|
|
|
### Configuring NixOS (with Flakes)
|
|
|
|
Below is a fragment of a NixOS configuration that enables the Secure
|
|
Boot stack.
|
|
|
|
```nix
|
|
nixosConfigurations = {
|
|
yourHost = nixpkgs.lib.nixosSystem {
|
|
system = "x86_64-linux";
|
|
|
|
modules = [
|
|
# ... other modules ...
|
|
|
|
lanzaboote.nixosModules.lanzaboote
|
|
|
|
({ config, pkgs, lib, ... }: {
|
|
# This should already be here from switching to bootspec earlier.
|
|
# It's not required anymore, but also doesn't do any harm.
|
|
boot.bootspec.enable = true;
|
|
|
|
environment.systemPackages = [
|
|
# For debugging and troubleshooting Secure Boot.
|
|
pkgs.sbctl
|
|
];
|
|
|
|
# Lanzaboote currently replaces the systemd-boot module.
|
|
# This setting is usually set to true in configuration.nix
|
|
# generated at installation time. So we force it to false
|
|
# for now.
|
|
boot.loader.systemd-boot.enable = lib.mkForce false;
|
|
|
|
boot.lanzaboote = {
|
|
enable = true;
|
|
pkiBundle = "/etc/secureboot";
|
|
};
|
|
})
|
|
];
|
|
};
|
|
```
|
|
|
|
After you rebuild your system, check `sbctl verify` output:
|
|
|
|
```console
|
|
$ sudo sbctl verify
|
|
Verifying file database and EFI images in /boot...
|
|
✓ /boot/EFI/BOOT/BOOTX64.EFI is signed
|
|
✓ /boot/EFI/Linux/nixos-generation-355.efi is signed
|
|
✓ /boot/EFI/Linux/nixos-generation-356.efi is signed
|
|
✓ /boot/EFI/nixos/0n01vj3mq06pc31i2yhxndvhv4kwl2vp-linux-6.1.3-bzImage.efi is signed
|
|
✓ /boot/EFI/systemd/systemd-bootx64.efi is signed
|
|
```
|
|
|
|
🔪 **Sharp edge:** 🔪 In case something is **not** signed in the
|
|
`sbctl verify` output, you have hit a bug
|
|
([#39](https://github.com/nix-community/lanzaboote/issues/39)). You
|
|
**have to fix this** to avoid ending up with an unbootable system
|
|
([#58](https://github.com/nix-community/lanzaboote/issues/58)). The
|
|
way to solve this is **deleting** the unsigned files indicated by
|
|
`sbctl` and switching to the configuration again. This will copy and
|
|
sign the missing files.
|
|
|
|
## Part 2: Enabling Secure Boot
|
|
|
|
Now that NixOS is ready for Secure Boot, we will setup the
|
|
firmware. At the end of this section, Secure Boot will be enabled on
|
|
your system and your firmware will only boot binaries that are signed
|
|
with your keys.
|
|
|
|
These instructions are specific to Thinkpads and may need to be
|
|
adapted on other systems.
|
|
|
|
### Entering Secure Boot Setup Mode
|
|
|
|
The UEFI firmware allows enrolling Secure Boot keys when it is in
|
|
_Setup Mode_.
|
|
|
|
On a Thinkpad enter the BIOS menu using the "Reboot into Firmware"
|
|
entry in the systemd-boot boot menu. Once you are in the BIOS menu:
|
|
|
|
1. Select the "Security" tab.
|
|
2. Select the "Secure Boot" entry.
|
|
3. Set "Secure Boot" to enabled.
|
|
4. Select "Reset to Setup Mode".
|
|
5. Select "Clear All Secure Boot Keys".
|
|
|
|
When you are done, press F10 to save and exit.
|
|
|
|
You can see these steps as a video [here](https://www.youtube.com/watch?v=aLuCAh7UzzQ).
|
|
|
|
### Enrolling Keys
|
|
|
|
Once you've booted your system into NixOS again, you have to enroll
|
|
your keys to activate Secure Boot. We include Microsoft keys here to
|
|
avoid boot issues.
|
|
|
|
```console
|
|
$ sudo sbctl enroll-keys --microsoft
|
|
Enrolling keys to EFI variables...
|
|
With vendor keys from microsoft...✓
|
|
Enrolled keys to the EFI variables!
|
|
```
|
|
|
|
You can now reboot your system. After you've booted, Secure Boot is
|
|
activated:
|
|
|
|
```console
|
|
$ bootctl status
|
|
System:
|
|
Firmware: UEFI 2.70 (Lenovo 0.4720)
|
|
Firmware Arch: x64
|
|
Secure Boot: enabled (user)
|
|
TPM2 Support: yes
|
|
Boot into FW: supported
|
|
```
|
|
|
|
That's all! 🥳
|
|
|
|
## Disabling Secure Boot and Lanzaboote
|
|
|
|
When you want to get back to a system without the Secure Boot stack,
|
|
**first** disable Secure Boot in your firmware settings. Then you can
|
|
disable the Lanzaboote related settings in the NixOS configuration and
|
|
rebuild.
|
|
|
|
You may need to clean up the `EFI/Linux` directory in the ESP manually
|
|
to get rid of stale boot entries. **Please backup your ESP, before you
|
|
delete any files** in case something goes wrong.
|
|
|
|
## Alternatives
|
|
|
|
The [ArchLinux wiki](https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot)
|
|
contains alternatives to handling your keys, in case `sbctl` is not
|
|
flexible enough.
|