This article describes how to use YubiKeys for FIDO2-based Full Disk Encryption (FDE) on NixOS. The keys can be used as single-factor authentication devices or in combination with a pin.

Throughout this guide, names surrounded by < > characters are used as placeholders, replace them with the appropriate values.


Preparations

Installer

  1. Get a minimal ISO image and boot it.

  2. Switch to the root user.

    sudo -i
    
  3. Optionally, change the keyboard layout.

    loadkeys sv-latin1
    
  4. Connect to internet using, for example, nmtui.

YubiKey setup

Make sure that all YubiKeys that will be used are configured correctly with a FIDO2 pin set, refer to official documentation.

Partitioning

Create a GPT partition table and two partitions on the target disk.

  • Partition 1: The boot partition.

    If you want to dual-boot with an OS that is already installed, use the existing boot partition.

    • Size: 1GB recommended.
    • Type: EFI System.
  • Partition 2: The LUKS-encrypted partition.
    • Size: Remaining space or user preference, it will contain the root and swap volumes.
    • Type: Linux filesystem.
  1. List all disks and identify which disk to install on.

    lsblk
    
  2. Create the partitions.

    cfdisk /dev/<disk>
    
  3. Set the following variables to match you partitions, they will be used in future steps.

    EFI_PART=/dev/<efi_part>
    LUKS_PART=/dev/<luks_part>
    
  4. Format the boot partition, skip this if using an existing boot partition.

    mkfs.fat -F 32 -n boot "$EFI_PART"
    

Encrypted partition

LUKS device

  1. Create the LUKS device.

    cryptsetup luksFormat "$LUKS_PART"
    

    You will be asked to enter a passphrase, either choose something simple and remove it later or choose a strong passphrase and keep it as a backup option. If you only have a single physical key I would recommend keeping it to avoid getting locked out.

  2. Open the LUKS device using the selected passphrase. The last value in the command is the name the unlocked partition will be available under.

    cryptsetup luksOpen "$LUKS_PART" encrypted
    

LVM

LVM is used to create multiple “partitions” (volumes) inside the encrypted partition.

  1. Setup the LUKS device as a physical volume.

    pvcreate /dev/mapper/encrypted
    
  2. Create a volume group.

    vgcreate partitions /dev/mapper/encrypted
    
  3. Create two logical volumes.

    • Volume 1: This will be the swap partition, choose an appropriate size.
    • Volume 2: This will be the root partition, rest of the free space.
    lvcreate -L 16G -n swap partitions
    lvcreate -l 100%FREE -n root partitions
    
    vgchange -ay # Activate volumes
    
  4. Format the volumes with appropriate filesystems.

    mkswap -L swap /dev/partitions/swap
    mkfs.ext4 -L root /dev/partitions/root
    

NixOS installation

Install

  1. Mount partitions.

    mount /dev/partitions/root /mnt
    mkdir /mnt/boot
    mount -o umask=077 "$EFI_PART" /mnt/boot
    swapon /dev/partitions/swap
    
  2. Generate (hardware) config.

    nixos-generate-config --root /mnt
    
  3. Replace /mnt/etc/nixos/configuration.nix with this minimal config and replace all placeholders with appropriate values, there are 4.

    { pkgs, ... }:
    {
      imports = [ ./hardware-configuration.nix ];
    
      boot = {
        loader = {
          efi.canTouchEfiVariables = true;
          grub = {
            enable = true;
            efiSupport = true;
            device = "nodev";
          };
        };
        initrd = {
          systemd.enable = true;
          luks.devices.encrypted = {
            device = "<luks_part>";
            crypttabExtraOpts = [ "fido2-device=auto" ];
          };
        };
      };
    
      networking = {
        hostName = "<hostname>";
        networkmanager.enable = true;
      };
    
      users.users.<username> = {
        isNormalUser = true;
        extraGroups = [ "wheel" "networkmanager" ];
      };
    
      environment.systemPackages = with pkgs; [
        vim
        git
      ];
    
      console.keyMap = "<keymap>"; # E.g. "sv-latin1"
    
      system.stateVersion = "26.05";
    }
    
  4. Install NixOS.

    nixos-install
    

    Select a root password when prompted.

  5. Set the user password, replace <username> with the username set in configuration.nix.

    nixos-enter --root /mnt -c 'passwd <username>'
    

YubiKeys

Plug in one key at a time and run the command below.

  • --fido2-with-client-pin controls whether to require the user to enter the FIDO2 PIN when unlocking.
  • --fido2-with-user-presence controls whether to require the user to tap the key to confirm presence when unlocking.
systemd-cryptenroll "$LUKS_PART" --fido2-device=auto --fido2-with-client-pin=no --fido2-with-user-presence=yes

Once all keys have been added the passphrase can be removed, unless it should be kept as a backup.

systemd-cryptenroll "$LUKS_PART" --wipe-slot=0

Reboot

Reboot the computer and boot into the fresh install. When prompted plug in one of the YubiKeys to unlock the LUKS-device.

The installation is now finished. There are some maintenance sections below, such as adding more keys, removing lost keys, and recovering a broken system.

You could now move on to installing a larger NixOS configuration, see for example my config, or just using the system.


Maintenance

Add additional keys

TODO

Remove lost key

⚠️ Make sure at least one working key is available at all times during this process. Losing access to all valid keys will make the data permanently inaccessible.

TODO

Recovery

TODO


Further reading