Full Disk Encryption: Difference between revisions

From NixOS Wiki
imported>Thibaultmol
I think 'partition' was meant here instead of 'disk'
imported>Ulinja
correct misleading heading, remove unnecessary config options, improve clarity
Line 67: Line 67:
</syntaxhighlight>
</syntaxhighlight>


== Option 3: Full disk encryption (encrypted /boot) with password ==
== Option 3: Full disk encryption with password (LVM on LUKS) ==


Partition formatting will be : one partition with LVM on LUKS, and the other in FAT. (EFI partition)
In this example, everything except for the <code>/boot</code> partition is encrypted.
The LVM partition contains both the swap and the root filesystem.
The <code>sda</code> block device will have two partitions:
This only works with LUKS1 partition because Grub doesn't know LUKS2, so make sure to pass the argument --type luks1 to cryptsetup when creating the LUKS partition.
# Unencrypted <code>/boot</code> partition (EFI system partition) formatted as FAT.
# LUKS-encrypted logical volume group for everything else (swap and <code>/</code>).
 
When unlocked and mounted, it will look like this:


<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda            8:0    0 233.8G  0 disk
sda            8:0    0 233.8G  0 disk
├─sda1          8:1    0  500M  0 part  /boot/efi
├─sda1          8:1    0  500M  0 part  /boot
└─sda2          8:2    0 233.3G  0 part
└─sda2          8:2    0 233.3G  0 part
   └─root      254:0    0 233.3G  0 crypt
   └─root      254:0    0 233.3G  0 crypt
Line 83: Line 86:
</syntaxhighlight>
</syntaxhighlight>


- mount your EFI partition (here /dev/sda1) as /boot/efi.
The initrd needs to be configured to unlock the encrypted <code>/dev/sda2</code> partition during stage 1 of the boot process.
- generate your nixos config
To do this, add the following options (replacing <code>UUID-OF-SDA2</code> with the actual UUID of the encrypted partition <code>/dev/sda2</code>. -- You can find it using <code>lsblk -f</code> or <code>sudo blkid -s UUID /dev/sda2</code>.)
- add the following options : (replace TODO by the UUID in /dev/disk/by-uuid pointing to the partition containing the encrypted part. -- You can also do lsblk -f.)
 
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
     boot.loader.efi.canTouchEfiVariables = true;
     boot = {
    boot.loader.grub = {
      loader = {
      enable = true;
        canTouchEfiVariables = true;
      version = 2;
        grub = {
      device = "nodev";
          enable = true;
      efiSupport = true;
           device = "nodev";
      enableCryptodisk = true;
           efiSupport = true;
    };
    boot.loader.efi.efiSysMountPoint = "/boot/efi";
    boot.initrd.luks.devices = {
        root = {
           device = "/dev/disk/by-uuid/TODO";
           preLVM = true;
         };
         };
      };
      initrd.luks.devices.cryptroot.device = "/dev/disk/by-uuid/UUID-OF-SDA2";
     };
     };
</syntaxhighlight>
</syntaxhighlight>
During boot, the password used to unlock the encrypted device must be entered.
Once it is unlocked, the boot process continues.
= zimbatm's laptop recommendation =
= zimbatm's laptop recommendation =



Revision as of 11:51, 31 March 2024

There are a few options for full disk encryption.

Basic Installation

Unattended Boot via USB

Sometimes it is necessary to boot a system without needing an keyboard and monitor. You will create a secret key, add it to a key slot and put it onto an USB stick.

dd if=/dev/random of=hdd.key bs=4096 count=1
cryptsetup luksAddKey /dev/sda1 ./hdd.key

Option 1: Write key onto the start of the stick

This will make the usb-stick unusable for any other operations than being used for decryption. Write they key onto the stick:

dd if=hdd.key of=/dev/sdb

Then add the following configuration to your configuration.nix:

{
  "..."

  # Needed to find the USB device during initrd stage
  boot.initrd.kernelModules = [ "usb_storage" ]; 

  boot.initrd.luks.devices = {
      luksroot = {
         device = "/dev/disk/by-id/<disk-name>-part2";
         allowDiscards = true;
         keyFileSize = 4096;
         # pinning to /dev/disk/by-id/usbkey works
         keyFile = "/dev/sdb";
      };
  };
}

Option 2: Copy Key as file onto a vfat usb stick

If you want to use your stick for other stuff or it already has other keys on it you can use the following method by Tzanko Matev. Add this to your configuration.nix:

let
  PRIMARYUSBID = "b501f1b9-7714-472c-988f-3c997f146a17";
  BACKUPUSBID = "b501f1b9-7714-472c-988f-3c997f146a18";
in {

  "..."

  # Kernel modules needed for mounting USB VFAT devices in initrd stage
  boot.initrd.kernelModules = ["uas" "usbcore" "usb_storage" "vfat" "nls_cp437" "nls_iso8859_1"];

  # Mount USB key before trying to decrypt root filesystem
  boot.initrd.postDeviceCommands = pkgs.lib.mkBefore ''
    mkdir -m 0755 -p /key
    sleep 2 # To make sure the usb key has been loaded
    mount -n -t vfat -o ro `findfs UUID=${PRIMARYUSBID}` /key || mount -n -t vfat -o ro `findfs UUID=${BACKUPUSBID}` /key
  '';

  boot.initrd.luks.devices."crypted" = {
    keyFile = "/key/keyfile";
    preLVM = false; # If this is true the decryption is attempted before the postDeviceCommands can run
  };
}

Option 3: Full disk encryption with password (LVM on LUKS)

In this example, everything except for the /boot partition is encrypted. The sda block device will have two partitions:

  1. Unencrypted /boot partition (EFI system partition) formatted as FAT.
  2. LUKS-encrypted logical volume group for everything else (swap and /).

When unlocked and mounted, it will look like this:

NAME          MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
sda             8:0    0 233.8G  0 disk
├─sda1          8:1    0   500M  0 part  /boot
└─sda2          8:2    0 233.3G  0 part
  └─root      254:0    0 233.3G  0 crypt
    ├─vg-swap 254:1    0     8G  0 lvm   [SWAP]
    └─vg-root 254:2    0 225.3G  0 lvm   /

The initrd needs to be configured to unlock the encrypted /dev/sda2 partition during stage 1 of the boot process. To do this, add the following options (replacing UUID-OF-SDA2 with the actual UUID of the encrypted partition /dev/sda2. -- You can find it using lsblk -f or sudo blkid -s UUID /dev/sda2.)

    boot = {
      loader = {
        canTouchEfiVariables = true;
        grub = {
          enable = true;
          device = "nodev";
          efiSupport = true;
        };
      };
      initrd.luks.devices.cryptroot.device = "/dev/disk/by-uuid/UUID-OF-SDA2";
    };

During boot, the password used to unlock the encrypted device must be entered. Once it is unlocked, the boot process continues.

zimbatm's laptop recommendation

Let's say that you have a GPT partition with EFI enabled. You might be booting on other OSes with it. Let's say that your disk layout looks something like this:

   8        0  500107608 sda
   8        1     266240 sda1       - the EFI partition
   8        2      16384 sda2
   8        3  127388672 sda3
   8        4  371409920 sda4    - the NixOS root partition
   8        5    1024000 sda5

Boot the NixOS installer and partition things according to your taste. What we are then going to do is prepare sda4 with a luks encryption layer:

# format the partition with the luks structure
cryptsetup luksFormat /dev/sda4
# open the encrypted partition and map it to /dev/mapper/cryptroot
cryptsetup luksOpen /dev/sda4 cryptroot
# format as usual
mkfs.ext4 -L nixos /dev/mapper/cryptroot
# mount
mount /dev/disk/by-label/nixos /mnt
mkdir /mnt/boot
mount /dev/sda1 /mnt/boot

Now keep installing as usual, nixos-generate-config should detect the right partitioning. You should have something like this in your /etc/nixos/hardware-configuration.nix:

{ # cut
  fileSystems."/" =
    { device = "/dev/disk/by-uuid/5e7458b3-dcd2-49c6-a330-e2c779e99b66";
      fsType = "ext4";
    };

  boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-uuid/d2cb12f8-67e3-4725-86c3-0b5c7ebee3a6";

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/863B-7B32";
      fsType = "vfat";
    };

  swapDevices = [ ];
}

To create a swap add the following in your /etc/nixos/configuration.nix:

{
  swapDevices = [{device = "/swapfile"; size = 10000;}];
}

Perf test

# compare
nix-shell -p hdparm --run "hdparm -Tt /dev/mapper/cryptroot"
# with
nix-shell -p hdparm --run "hdparm -Tt /dev/sda1"

I had to add a few modules to initrd to make it fast. Since cryptroot is opened really early on, all the AES descryption modules should already be made available. This obviously depends on the platform that you are on.

{
   boot.initrd.availableKernelModules = [
    "aesni_intel"
    "cryptd"
  ];
}

Further reading