Skip to content

Instantly share code, notes, and snippets.

@candeira
Forked from ladinu/encryptedNixos.md
Created May 16, 2020 05:47
Show Gist options
  • Save candeira/83f0161287f1a130cce7e2f92de1b539 to your computer and use it in GitHub Desktop.
Save candeira/83f0161287f1a130cce7e2f92de1b539 to your computer and use it in GitHub Desktop.
NixOS install with encrypted /boot /root with single password unlock

Requirements

  1. Encrypt everthing including /boot and /root
  2. Enter password once
  3. Support UEFI

Installation media setup

Download NixOS minimal iso and copy to USB stick. For example on Mac OSX

$ diskutil list
$ diskutil unmountDisk /dev/disk1 # Make sure you got right device
$ dd if=nixos-minimal-17.09.2378.af7e47921c4-x86_64-linux.iso of=/dev/disk1

NixOS install

Boot from the USB stick and setup networking. (optionally setup SSH if you want to complete the install from another computer)

$ wpa_passhrase SSID PASSWORD > /etc/wpa_supplicant.conf
$ systemctl start wpa_supplicant
$ systemctl start sshd
$ passwd # So we can login via SSH

Partitioning

I have 2 drives on my system: NVME SSD and a regular SATA drive. This what the drives look after the install. I use NVME SSD for booting and SATA drive as a /data mount.

NAME             MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
sda                8:0    0 931.5G  0 disk
└─sda1             8:1    0 931.5G  0 part
  └─crypted-data 254:3    0 931.5G  0 crypt /data
nvme0n1          259:0    0 465.8G  0 disk
├─nvme0n1p1      259:1    0   549M  0 part  /boot/efi
└─nvme0n1p2      259:2    0 465.2G  0 part
  └─root         254:0    0 465.2G  0 crypt
    ├─vg-swap    254:1    0     4G  0 lvm   [SWAP]
    └─vg-root    254:2    0 461.2G  0 lvm   /

The only unecrypted partition is nvme0n1p1, which is mounted on /boot/efi. But rest of /boot is encrypted along with swap and root. /dev/sda1 is also encrypted and mounted as /data

Use Use gdisk to partition the drives

$ gdisk /dev/nvme0n1
  • o Create partition table
  • n Create new partition of size 550M and of type ef00
  • n Create another partition of type 8300 and use remainig space
  • p Show what gdisk will write
  • w Write to disk an exit
$ gdisk /dev/sda
  • o Create partition table
  • n Create another partition of type 8300 and use all space
  • p Show what gdisk will write
  • w Write to disk an exit

Generate keys for single password unlock

$ dd if=/dev/urandom of=./keyfile0.bin bs=1024 count=4
$ dd if=/dev/urandom of=./keyfile1.bin bs=1024 count=4

Setup LUKS and add the keys

$ cryptsetup luksFormat -c aes-xts-plain64 -s 256 -h sha512 /dev/nvme0n1p2
$ cryptsetup luksAddKey /dev/nvme0n1p2 keyfile0.bin
$ cryptsetup luksOpen /dev/nvme0n1p2 crypted-nixos

$ cryptsetup luksFormat -c aes-xts-plain64 -s 256 -h sha512 /dev/sda1
$ cryptsetup luksAddKey /dev/sda1 keyfile1.bin
$ cryptsetup luksOpen /dev/sda1 crypted-data

Setup LVM

$ pvcreate /dev/mapper/crypted-nixos
$ vgcreate vg /dev/mapper/crypted-nixos
$ lvcreate -L 4G -n swap vg
$ lvcreate -l '100%FREE' -n root vg

Format the partitions and mount

$ mkfs.fat -F 32 /dev/nvme0n1p1
$ mkswap -L swap /dev/vg/swap
$ mkfs.ext4 -L root /dev/vg/root
$ mkfs.ext4 -L data /dev/mapper/crypted-data
$ mount /dev/vg/root /mnt
$ mkdir -p /mnt/boot/efi
$ mount /dev/nvme0n1p1 /mnt/boot/efi
$ swapon /dev/vg/swap

Create an initrd which only contain the key files

$ find keyfile*.bin -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null | gzip -9 > /mnt/boot/initrd.keys.gz
$ chmod 000 /mnt/boot/initrd.keys.gz

Generate and edit configuration

$ nixos-generate-config --root /mnt

Add the following to /etc/nixos/configuration.nix

  boot.loader.efi.canTouchEfiVariables = true;
  boot.loader.efi.efiSysMountPoint = "/boot/efi";
  boot.loader.grub = {
    enable = true;
    device = "nodev";
    version = 2;
    efiSupport = true;
    enableCryptodisk = true;
    extraInitrd = /boot/initrd.keys.gz;
  };
  
  boot.initrd.luks.devices = [
      {
        name = "root";
        device = "/dev/disk/by-uuid/a8b302cf-5296-4a2e-a7ba-707e6fa75123"; # UUID for /dev/nvme01np2 
        preLVM = true;
        keyFile = "/keyfile0.bin";
        allowDiscards = true;
      }
  ];

  # Data mount
  fileSystems."/data" = {
    device = "/dev/disk/by-uuid/79630267-5766-4c7d-85a5-1d5f1dcd58ad"; # UUID for /dev/mapper/crypted-data
    encrypted = {
      enable = true;
      label = "crypted-data";
      blkDev = "/dev/disk/by-uuid/3476cb09-b3c4-4301-9ec9-84f60f32828a"; # UUID for /dev/sda1
      keyFile = "/keyfile1.bin";
    };
  };

You can get the UUIDs by running

$ blkid

Install NixOS and reboot

$ nixos-install
$ reboot

Thats it! Once you reboot, GRUB will ask for the password. If password is correct, GRUB will show you the NixOS system profiles menu. After that, your system will boot without asking for the disk password.

Future work

If I enter an incorrect disk password, GRUB does not handle it gracefully. It will drop me into a shell without re-prompting for a password. I usually end up rebooting to enter the password again. Need to figure out if GRUB has an option for it to re-prompt.

Credits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment