It took me quite a while to get to this setup so I thought I would write a guide to help others and also to discuss feedback and other desktop setups.
I’m currently running NixOS on my Surface Pro 6 intel tablet/laptop and an 8-9 years old custom gaming tower PC with intel + nvidia. I did a fresh install with btrfs on the tablet and I had an ext4 LUKS1 setup running on the tower for a while.
For those who want to jump ahead and just look at the setup, here it is. Everything is open, except for one encrypted file which I’m testing for keeping secrets and sensitive info. The encryption is done via git-crypt and once it’s setup it’s transparent when using git. Feel welcome to fork it.
The setup is LUKS2 encrypted Btrfs root with a swapfile, auto unlock with TPM2, secureboot and a BIOS password.
During the first-time installation if you’re inexperienced with partitioning you will probably select the auto option. It is better to manually set it up for btrfs, because the automatic setup will use ext4. If you’re ok with using ext4, that’s also perfectly fine, but btrfs has some nice features to avoid data corruption or back up your data and roll back.
If you already have a system installed with ext4, here’s an easy to follow guide to convert to btrfs.
During the installation you should select disk encryption which will set it up for you, however it will use LUKS1, which doesn’t work with the TPM unlock. This simple guide shows you how to upgrade it to LUKS2 and switch to a more secure algorithm after the installation while you’re still on the live USB.
After rebooting into the installed system, I would start a nix-shell with git and git-crypt, clone my repo to my home directory, and unlock git-crypt with a key that I exported from another machine. The repo has a top level flake.nix which contains configurations for both of my computers based on the hostname, my home manager setup, and even the shell setup for the repo, note that using nix-shell to clone works just as well.
Assuming that this is the first time I’m bringing up a new device, I would just create a folder for it within “devices” and add a conf.nix and a hw.nix. I would copy the contents of the auto generated /etc/nixos/hardware-configuration.nix into the local hw.nix. For the conf.nix, something like this:
{ config, pkgs, pconf, nixos-hardware, ... }: {
imports = [
./hw.nix
nixos-hardware.nixosModules.my-device
../../common/configuration.nix
];
#
networking.hostName = "${pconf.user}-my-device";
# Swap
swapDevices = [ { device = "/var/swapfile"; size = 10*1024; } ]; # 10 = 8 GB RAM + 2 buffer
boot.resumeDevice = "/dev/dm-0"; # the unlocked drive mapping
boot.kernelParams = [
"resume_offset=#########" # for hibernate resume
];
#
system.stateVersion = "23.11"; # Do not change
}
The swapfile will be automatically created based on the config, the resume device can be found with ll /dev/mapper/luks*
and there is a command in my README in the linked repo for finding the resume offset.
Then add a new machine config in the flake which imports this conf.nix, like I did for the other 2 devices. If the device already had a working config and needs to be brought up after a fresh clean reinstall, then there is no need to recreate these 2 config files or to re-add it to the flake.
Then I would remove both files from /etc/nixos/ and create a symlink of my flake to /etc/nixos/flake.nix. There is also a symlink for my home manager configuration. The commands for both are in my README.
At this point we’re still missing the secure boot signing keys, so the setup won’t build. Here’s a short guide to set up secureboot. First I would open a nix shell with “sbctl” and run the key generation command, then the build should already work. If you set up the symlinks, using the standard sudo nixos-rebuild switch
works.
Enrolling the secureboot key was a different process for my two machines. On the surface I just ran the enroll command and it just worked after that. On the tower I had to turn ON the Windows 10 WHQL settings in BIOS, switch a newly appeared setting from CSM to UEFI and then put secureboot in a setup state, then reboot and run the enroll command. After enabling secureboot I put a BIOS password on both machines, but I’m not sure if that significantly improves security.
After enrolling the keys and enabling secureboot, make sure to reboot and verify that it works according to the guide.
Finally I enrolled the disk decryption key in the TPM chip using pins 0, 1, 2, 3, 7. The cryptenroll command and another command to find the name of your encrypted partition are both in my README.
At this point, you should be able to reboot with secureboot enabled and only have to enter your login password, not encryption password. Depending on your hardware, this setup is fairly secure. As long as your nix configuration doesn’t install malicious software of course. If an attacker tampers with your unencrypted boot, secureboot will fail, and if they disable secureboot or load a live USB the TPM won’t decrypt your root partition, so they won’t be able to access your data. If they steal your laptop, modify your boot partition, get past your BIOS password, disable secure boot, and return your laptop without you noticing, then you unknowingly turn it on, not notice that secure boot is off, then enter the encryption key to unlock your drive, then they could gain access to your data. Or using the cold boot attack…
After you confirmed that everything works, nix-collect-garbage -d
can free up some space and make your boot menu cleaner by erasing old boot generations and unused packages.
Note, the declarative email/calendar in the config doesn’t work, hopefully in the future it will. I would also like to add impermanence to this setup, but I’m not there yet.