There are many possible encrypted root setups. This guide is for setting up LVM over Luks, which is an easy and safe setup that will satisfy most users. Other setups should still be sufficiently similar.

Contents

edit Important

Here you will find *only* NixOS-specific bits. For general information regarding this setup, how to partition disks and such refer to [1] or other detailed guide.

edit Updating from how it was previously

Luks got changed lately (see mailinglist from 3.3.2012 titled "[Nix-dev] luks changes")

 If you had:
 boot.initrd.luksRoot = "/dev/sda2";
 
 Then now you have to write:
 boot.initrd.luks.enable = true;
 boot.initrd.luks.devices = [ { name = "luksroot"; device = "/dev/sda2"; } ];

edit the configuration of /etc/nixos/configuration.nix

In this example we assume that:

  • your boot partition is /dev/sda1 and
  • your luks-encrypted partition is /dev/sda2 that contains the LVM volume group "vg".

edit Make sure initrd finds and mounts the root partition

The current implementation always opens the luks devices in the stage1 (before mounting the rootfs).

This part of configuration.nix will make cryptsetup luksOpen to be called after the LVM initialisation for /dev/sda2 to the name 'luksroot':

  boot.initrd.luks.enable = true;
  boot.initrd.luks.devices = [ { name = "luksroot"; device = "/dev/sda2"; } ];

You can extend the list, if you have for example a ciphered swap partition too, or any else:

  boot.initrd.luks.devices = [
    { name = "luksroot"; device = "/dev/sda2"; }
    { name = "swap"; device = "/dev/sda3"; }
  ];

Notice that you will have to set the root filesystem to be mounted from the device /dev/mapper/luksroot, and the swap enabled for the device /dev/mapper/swap. Or, if you set labels, you can use the labels.

In case you had luks *over* LVM, you want to luksOpen the device *before* lvm vgscan gets called:

  boot.initrd.luks.devices = [
    { name = "luksroot"; device = "/dev/sda2"; preLVM = true; }
  ];

edit creating encrypted swap

If you don't use LVM then you have a problem with creating and using an encrypted swap. One approach would be to unlock the swap partition with a keyfile instead of a random key:

First create a normal encrpyted partition and after unlocking it, format it as swap space using mkswap.

  cryptsetup luksFormat /dev/sdXY
  cryptsetup luksOpen /dev/sdXY swap
  mkswap /dev/mapper/swap

Then create a keyfile for auto-unlocking swap and store it in the root folder (if this is your first installation store it in /mnt/root/) and add it to the swap partition

  dd if=/dev/urandom of=/root/keyfile bs=1024 count=1
  chmod 0400 /root/keyfile
  cryptsetup luksAddKey /dev/sdXY /root/keyfile

Then, in this case, you can't benefit from the current boot.initrd.luks, because it does not support keyfile. As in the stage1 the rootfs gets mounted to /mnt-root, you can use this postMountCommands to get the swap dmcrypt device opened.

  boot.initrd.postMountCommands = "cryptsetup luksOpen --key-file /mnt-root/root/keyfile /dev/sdaXY swap";
  swapDevices = [
    { device = "/dev/mapper/swap"; }
  ];

edit no encrypted root filesystem, no encrypted swap but only encrypted /home

If you only want to have an encrypted home directory, you need to set something like this, for example:

  boot.initrd.luks.enable = true;
  boot.initrd.device = [ { device = "/dev/sda3"; name = "lukshome"; };

edit Extra kernel modules you might need

Depending on the encryption algorithm you have chosen for your Luks volume, you will probably need to ensure kernel has the necessary crypto modules.

If you are unsure which ones, run

cryptsetup luksDump /dev/sda2

What you are looking for is this:

LUKS header information for /dev/sda2

Version:        1
Cipher name:    aes
Cipher mode:    cbc-essiv:sha256
Hash spec:      sha1

In this example you need SHA1, SHA256, AES, and CBC.

You can put the required crypto modules into initrd along with dm_crypt module needed by Luks like this:

boot.initrd.kernelModules = ["dm_crypt" "aes-i586" "sha256" "sha1" "cbc"];

On my 64bit system (2.6.32) I needed this modules instead the listed above:

boot.initrd.kernelModules = ["dm_crypt" "sha256_generic" "sha1_generic" "cbc" "aes_x86_64" "aes_generic" "xts" ];


Note that some USB keyboards also need special kernel support, which must be available in the init ramdisk to enter the pass phrase. Recent models of the Microsoft Internet keyboard, for example, need the module hid_microsoft in order to be recognized as an input device.

edit Root Filesystem

  fileSystems = [ {
    mountPoint = "/";
    device = "/dev/mapper/vg-root";
    #device = "/dev/mapper/luksroot"; # use this instead when NOT using LVM
  } {
    mountPoint = "/boot";
    device = "/dev/sda1";
  }
  #other filesystems go here 
  ]

edit Mounting from a rescue system

Within the rescue system:

  # cryptsetup luksOpen /dev/sda2 crypt
  # vgscan
  # vgchange -ay

Now your logical volumes should be available.