Add secure-boot

This commit is contained in:
ItsDrike 2024-04-12 18:25:26 +02:00
parent fa6f2b49db
commit cb968bdc07
Signed by: ItsDrike
GPG key ID: FA2745890B7048C0
12 changed files with 459 additions and 1 deletions

View file

@ -225,7 +225,7 @@ reboot
You should now be back in your system, with the root subvolume wiped and auto-reconstructed by NixOS.
You can now move on to the next file: [MY_FLAKE](./99_MY_FLAKE.md).
You can now move on to the next file: [SECURE_BOOT](./03_SECURE_BOOT.md).
## Why?

169
docs/03_SECURE_BOOT.md Normal file
View file

@ -0,0 +1,169 @@
# Secure Boot
This guide will show you how to set up UEFI Secure Boot with NixOS. Once finished, you will be left with a system that
doesn't allow booting any untrusted EFI images (other operating systems, fraudulently modified kernels) on your machine.
This guide assumes you're following from the [INSTALLATION](./01_INSTALLATION.md) guide, and that
you have converted your config to a flake.
## Make sure you're using UEFI
As a first step, you will want to confirm that you really are on a UEFI system. If you're using any recent hardware,
this is very likely the case. Nevertheless, let's check and make sure:
```shell
bootctl info
```
Make sure the `Firmware` is reported as `UEFI`.
## Security requirements
The requirements are optional, as it is possible to set up secure boot without them. That said, they are heavily
encouraged, as without these, setting up secure boot will not be a very effective security measure.
First requirement is to set up a **BIOS Password**. This is a password that you will be asked for every time you wish to
enter the BIOS (UEFI). This is necessary, as without it, an attacker could very easily just go to the BIOS and disable
Secure Boot.
The second requirement is having **disk encryption**, at least for the root (or persist, if using impermanence)
partition. This is important, because the UEFI signing keys will be stored here, and you don't want someone to
potentially be able to get access to them, as it would allow them to sign any malicious images, making them pass secure
boot.
> [!NOTE]
> Even after following all of these, you should be aware that Secure Boot isn't an unbreakable solution. In
> fact, if someone is able to get a hold of your machine, they can simply pull out the CMOS battery, which usually
> resets the UEFI. That means turning off Secure Boot, and getting rid of the BIOS password.
>
> While UEFI is generally a good extra measure to have, it is by no means a reliable way to really prevent others from
> ever being able to boot untrusted systems, unless you use a specialized motherboard, which persists the UEFI state.
## Create your keys
To create secure boot keys, you can use `sbctl`, which is a very popular Secure Boot Key Manager. It is available in
nixpkgs as `pkgs.sbctl`. Make sure to add it to your configuration.
> [!IMPORTANT]
> If you have set up impermanence, you will first need to declare `/etc/secureboot` as a persistent directory. This
> directory will contain the secure boot keys necessary to sign the bootloader and your kernel/initrd images. If you
> lose this key, you will need to go through this process again.
Once you have sbctl installed, run the following command to create your new keys:
```shell
sudo sbctl create-keys
```
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.
## lanzaboote
`lanzaboote` is a tool to help you set up secure boot in NixOS. To install it, you can add
it as an input for your flake:
```nix
lanzaboote = {
url = "github:nix-community/lanzaboote/v0.3.0";
# Optional but recommended to limit the size of your system closure.
inputs.nixpkgs.follows = "nixpkgs";
};
```
And include the `lanzaboote.nixosModules.lanzaboote` module.
Now, you will want to add the following to your configuration:
```nix
# Lanzaboote replaces systemd-boot
boot.loader.systemd-boot.enable = lib.mkForce false;
boot.lanzaboote = {
enable = true;
pkiBundle = "/etc/secureboot";
};
```
You can now rebuild your system: `sudo nixos-rebuild switch --flake .`.
## Check that your machine is ready for secure-boot environment
After you rebuild your system, check `sudo sbctl verify` output. You should see it report all of your boot entries as
signed.
Note that files ending with `bzImage.efi` do not need to be signed.
### Manually sign an image
In case you'd ever need to do so, it is possible to sign an image manually with `sbctl`. To do so, you can run:
```shell
sbctl sign -s /boot/my_image.efi
```
The `-s` flag means save. This makes sure the files will be automatically re-signed when we update. (List of files to
re-sign will be stored in the secure boot database, in `/etc/secureboot`)
Note that you shouldn't really need to use this.
## Enabling secure boot
Now that NixOS is ready for secure-boot, we will set up 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.
### Enter Setup mode
To allow us to upload new signing keys into the UEFI firmware, we will need to enter "setup mode". This should be
possible by going to the Secure Boot category in your UEFI settings, and clicking on Delete/Clear certificates, or
there could even be a "Setup Mode" option directly.
This option may not be available without also enabling secure boot. This is fine, while in setup mode, the secure
boot checks will not be performed.
You can now save the settings and reboot.
Once booted, to check that you really are in Setup Mode, run:
```shell
sudo sbctl status
```
### Enroll the new keys
You will now have to enroll your new keys to activate Secure Boot.
```shell
sudo sbctl enroll-keys -m
```
> [!NOTE]
> The `-m` option (also known as `--microsoft`) will make sure to also include the Microsoft
> signing keys. This is required by most motherboards, not using it could brick your device.
This should automatically enable secure boot in user mode for you. You can now reboot the system.
### Make sure it worked
To check that you really are using secure-boot, you can run
```shell
bootctl status
```
It should report `Secure Boot: enabled (user)`.
## Why bother?
As I mentioned, secure boot can be bypassed if someone tries hard enough (pulling the CMOS battery). That then
brings to question whether it's even worth it to set it up, when it doesn't really give you that much. On its own,
I probably wouldn't bother with setting up secure-boot, however secure boot allows me to set up TPM (Trusted Platform
Module) to automatically release the decryption keys for my LUKS encrypted root partition, in a secure way. This means I
won't have to type my disk password every time I boot.
For more information on this, check out the follow-up guide: [TPM_UNLOCKING](./04_TPM_UNLOCKING.md).
## Sources / Attribution
- <https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md>

3
docs/04_TPM_UNLOCKING.md Normal file
View file

@ -0,0 +1,3 @@
# TPM Unlocking
WIP

View file

@ -133,6 +133,10 @@ The resulting file should then look something like this:
# devices."/dev/disk/by-label/NIXROOT".subvolumes = [ "root" ];
# };
#};
# Enable secure boot (requires running some commands afterwards, see the
# option's docs)
#secure-boot.enabled = true;
};
device = {
virtual-machine = false;

View file

@ -1,5 +1,115 @@
{
"nodes": {
"crane": {
"inputs": {
"flake-compat": [
"lanzaboote",
"flake-compat"
],
"flake-utils": [
"lanzaboote",
"flake-utils"
],
"nixpkgs": [
"lanzaboote",
"nixpkgs"
],
"rust-overlay": [
"lanzaboote",
"rust-overlay"
]
},
"locked": {
"lastModified": 1681177078,
"narHash": "sha256-ZNIjBDou2GOabcpctiQykEQVkI8BDwk7TyvlWlI4myE=",
"owner": "ipetkov",
"repo": "crane",
"rev": "0c9f468ff00576577d83f5019a66c557ede5acf6",
"type": "github"
},
"original": {
"owner": "ipetkov",
"repo": "crane",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"lanzaboote",
"nixpkgs"
]
},
"locked": {
"lastModified": 1680392223,
"narHash": "sha256-n3g7QFr85lDODKt250rkZj2IFS3i4/8HBU2yKHO3tqw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "dcc36e45d054d7bb554c9cdab69093debd91a0b5",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"lanzaboote",
"pre-commit-hooks-nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1660459072,
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
@ -35,6 +145,33 @@
"type": "github"
}
},
"lanzaboote": {
"inputs": {
"crane": "crane",
"flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
],
"pre-commit-hooks-nix": "pre-commit-hooks-nix",
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1682802423,
"narHash": "sha256-Fb5TeRTdvUlo/5Yi2d+FC8a6KoRLk2h1VE0/peMhWPs=",
"owner": "nix-community",
"repo": "lanzaboote",
"rev": "64b903ca87d18cef2752c19c098af275c6e51d63",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "v0.3.0",
"repo": "lanzaboote",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1712439257,
@ -51,12 +188,100 @@
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1678872516,
"narHash": "sha256-/E1YwtMtFAu2KUQKV/1+KFuReYPANM2Rzehk84VxVoc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9b8e5abb18324c7fe9f07cb100c3cd4a29cda8b8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-22.11",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks-nix": {
"inputs": {
"flake-compat": [
"lanzaboote",
"flake-compat"
],
"flake-utils": [
"lanzaboote",
"flake-utils"
],
"gitignore": "gitignore",
"nixpkgs": [
"lanzaboote",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1681413034,
"narHash": "sha256-/t7OjNQcNkeWeSq/CFLYVBfm+IEnkjoSm9iKvArnUUI=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "d3de8f69ca88fb6f8b09e5b598be5ac98d28ede5",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"home-manager": "home-manager",
"impermanence": "impermanence",
"lanzaboote": "lanzaboote",
"nixpkgs": "nixpkgs"
}
},
"rust-overlay": {
"inputs": {
"flake-utils": [
"lanzaboote",
"flake-utils"
],
"nixpkgs": [
"lanzaboote",
"nixpkgs"
]
},
"locked": {
"lastModified": 1682129965,
"narHash": "sha256-1KRPIorEL6pLpJR04FwAqqnt4Tzcm4MqD84yhlD+XSk=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "2c417c0460b788328220120c698630947547ee83",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View file

@ -11,6 +11,12 @@
# doesn't offer much above properly used symlinks but it is convenient
impermanence.url = "github:nix-community/impermanence";
# secure-boot support
lanzaboote = {
url = "github:nix-community/lanzaboote/v0.3.0";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {self, nixpkgs, ...} @ inputs: let

View file

@ -25,6 +25,7 @@ in
./herugrim
inputs.home-manager.nixosModules.home-manager
inputs.impermanence.nixosModules.impermanence
inputs.lanzaboote.nixosModules.lanzaboote
] ++ shared;
};
}

View file

@ -37,6 +37,8 @@
devices."/dev/disk/by-label/NIXROOT".subvolumes = [ "root" ];
};
};
secure-boot.enabled = true;
};
device = {

View file

@ -4,6 +4,7 @@ in
{
imports = [
./impermanence.nix
./secure-boot.nix
];
options.myOptions.system = {

View file

@ -0,0 +1,23 @@
{ lib, ... }: with lib; let
inherit (lib) mkEnableOption;
in
{
options.myOptions.system.secure-boot = {
enabled = mkEnableOption ''
secure-boot using lanzaboote.
Note that you will need to have UEFI firmware, and the rebuild
will report errors until you generate the secure boot keys with:
```shell
sudo sbctl create-keys
````
Optionally (though enabling this is pointless otherwise), you should
now enter secure-boot setup mode and enroll the keys:
```shell
sudo sbctl enroll-keys -m
```
Then reboot, and secure-boot should be enabled.
'';
};
}

View file

@ -1,5 +1,6 @@
_: {
imports = [
./systemd-boot.nix
./secure-boot.nix
];
}

View file

@ -0,0 +1,23 @@
{ config, pkgs, lib, ... }: let
inherit (lib) mkIf;
cfg = config.myOptions.system.secure-boot;
in {
config = mkIf cfg.enabled {
# Secure Boot Key Manager
environment.systemPackages = [ pkgs.sbctl ];
# Persist the secure boot keys (for impermanence)
myOptions.system.impermanence.root.extraDirectories = [
"/etc/secureboot"
];
# Lanzaboote replaces systemd-boot
boot.loader.systemd-boot.enable = lib.mkForce false;
boot.lanzaboote = {
enable = true;
pkiBundle = "/etc/secureboot";
};
};
}