Files
clan-core/docs/site/getting-started/disk-encryption.md

7.4 KiB

Setting up Encryption with Remote Decryption in NixOS

This guide provides an example setup for a single-disk ZFS system with native encryption, accessible for decryption remotely. This configuration only applies to systemd-boot enabled systems and requires UEFI booting.

For a mirrored disk setup, add mode = "mirror"; to zroot. Under the disk option, provide the additional disk identifier, e.g., y = mirrorBoot /dev/disk/by-id/<second_disk_id>.

Replace the disk nvme-eui.002538b931b59865 with your own.

Below is the configuration for disko.nix

{ lib, ... }:
let
  mirrorBoot = idx: {
    type = "disk";
    device = "/dev/disk/by-id/${idx}";
    content = {
      type = "gpt";
      partitions = {
        boot = {
          size = "1M";
          type = "EF02"; # for grub MBR
          priority = 1;
        };
        ESP = lib.mkIf (idx == "nvme-eui.002538b931b59865") {
          size = "1G";
          type = "EF00";
          content = {
            type = "filesystem";
            format = "vfat";
            mountpoint = "/boot";
            mountOptions = [ "nofail" ];
          };
        };
        zfs = {
          size = "100%";
          content = {
            type = "zfs";
            pool = "zroot";
          };
        };
      };
    };
  };
in
{
  boot.loader.systemd-boot.enable = true;

  disko.devices = {
    disk = {
      x = mirrorBoot "nvme-eui.002538b931b59865";
    };
    zpool = {
      zroot = {
        type = "zpool";
        rootFsOptions = {
          compression = "lz4";
          acltype = "posixacl";
          xattr = "sa";
          "com.sun:auto-snapshot" = "true";
          mountpoint = "none";
        };
        datasets = {
          "root" = {
            type = "zfs_fs";
            options = {
              mountpoint = "none";
              encryption = "aes-256-gcm";
              keyformat = "passphrase";
              keylocation = "file:///tmp/secret.key";
            };
          };
          "root/nixos" = {
            type = "zfs_fs";
            options.mountpoint = "/";
            mountpoint = "/";
          };
          "root/home" = {
            type = "zfs_fs";
            options.mountpoint = "/home";
            mountpoint = "/home";
          };
          "root/tmp" = {
            type = "zfs_fs";
            mountpoint = "/tmp";
            options = {
              mountpoint = "/tmp";
              sync = "disabled";
            };
          };
        };
      };
    };
  };
}

Add this to networking.nix and replace the default values as well as the name gchq-local and networking.hostId with your own.

{ config, lib, ... }:
{
  options = {
    networking.gchq-local.ipv4.address = lib.mkOption {
      type = lib.types.str;
      default = "192.168.178.177";
    };
    networking.gchq-local.ipv4.cidr = lib.mkOption {
      type = lib.types.str;
      default = "24";
    };

    networking.gchq-local.ipv4.gateway = lib.mkOption {
      type = lib.types.str;
      default = "192.168.178.1";
    };

    networking.gchq-local.ipv6.address = lib.mkOption {
      type = lib.types.str;
      default = "2003:100:6701:d500:fbbc:40fb:cff3:3b87";
    };

    networking.gchq-local.ipv6.cidr = lib.mkOption {
      type = lib.types.str;
      default = "64";
    };
    networking.gchq-local.ipv6.gateway = lib.mkOption {
      type = lib.types.str;
      default = "fe80::3ea6:2fff:feef:3435";
    };
  };

  config = {
    networking.dhcpcd.enable = false;
    networking.nameservers = [ "127.0.0.1" ];
    networking.hostId = "a76ebcca"; # Needs to be unique for each host

    # The '10' in the network name is the priority, so this will be the first network to be configured
    systemd.network.networks."10-eth" = {
      matchConfig.Type = "ether";
      addresses = [
        {
          Address=config.networking.gchq-local.ipv4.address + "/" + config.networking.gchq-local.ipv4.cidr;
        }
        {
          Address=config.networking.gchq-local.ipv6.address + "/" + config.networking.gchq-local.ipv6.cidr;
        }
      ];
      DHCP = "yes";
    };
  };
}

Put this into initrd.nix and add your pubkey to authorizedKeys. Replace kernelModules with the ethernet module loaded one on your system.

{config, pkgs, ...}:

{

  boot.initrd.systemd = {
    enable = true;
    network.networks."10-eth" = config.systemd.network.networks."10-eth";
  };
  boot.initrd.network = {
    enable = true;

    ssh = {
      enable = true;
      port = 7172;
      authorizedKeys = [ "<yourkey>" ];
      hostKeys = [
        "/var/lib/initrd-ssh-key"
      ];
    };
  };
  boot.initrd.availableKernelModules = [
    "xhci_pci"
  ];

  # Check the network card by running `lspci -k` on the target machine
  boot.initrd.kernelModules = [ "r8169" ];
}

Step 1: Copying SSH Public Key

Before starting the installation process, ensure that the SSH public key is copied to the NixOS installer.

  1. Copy your public SSH key to the installer, if it has not been copied already:
ssh-copy-id -o PreferredAuthentications=password -o PubkeyAuthentication=no root@nixos-installer.local

Step 1.5: Prepare Secret Key and Clear Disk Data

  1. Access the installer using SSH:
ssh root@nixos-installer.local
  1. Create a secret.key file in /tmp using nano or another text editor:
nano /tmp/secret.key
  1. Discard the old disk partition data:
blkdiscard /dev/disk/by-id/nvme-eui.002538b931b59865
  1. Run the clan machine installation with the following command:
clan machines install gchq-local root@nixos-installer --yes --no-reboot

Step 2: ZFS Pool Import and System Installation

  1. SSH into the installer once again:
ssh root@nixos-installer.local
  1. Perform the following commands on the remote installation environment:
zpool import zroot
zfs set keystate=prompt zroot/root
zfs load-key zroot/root
zfs set mountpoint=/mnt zroot/root/nixos
mount /dev/nvme0n1p2 /mnt/boot
  1. Disconnect from the SSH session:
CTRL+D
  1. Securely copy your local initrd_rsa_key to the installer's /mnt directory:
scp ~/.ssh/initrd_rsa_key root@nixos-installer.local:/mnt/var/lib/initrd-ssh-key
  1. SSH back into the installer:
ssh root@nixos-installer.local
  1. Navigate to the /mnt directory, enter the nixos-enter environment, and then exit:
cd /mnt
nixos-enter
realpath /run/current-system
exit
  1. Run the nixos-install command with the appropriate system path <SYS_PATH>:
nixos-install --no-root-passwd --no-channel-copy --root /mnt --system <SYS_PATH>
  1. After the installation process, unmount /mnt/boot, change the ZFS mountpoint, and reboot the system:
umount /mnt/boot
cd /
zfs set mountpoint=/ zroot/root/nixos
reboot
  1. Perform a hard reboot of the machine and remove the USB stick.

Step 3: Accessing the Initial Ramdisk (initrd) Environment

  1. SSH into the initrd environment using the initrd_rsa_key and provided port:
ssh -p 7172 root@192.168.178.141
  1. Run the systemd-tty-ask-password-agent utility to query a password:
systemd-tty-ask-password-agent --query

After completing these steps, your NixOS should be successfully installed and ready for use.

Note: Replace root@nixos-installer.local and 192.168.178.141 with the appropriate user and IP addresses for your setup. Also, adjust <SYS_PATH> to reflect the correct system path for your environment.