Full encrypted nixos system on legacy boot with secrets and remote unlock, for unstable 20.03

Hi,

My objective was to create, with unstable 20.03 channel :

  • a remote unlock (ssh / openssh)
  • LUKS1 (for grub, waiting this patch published) on LVM encrypted
  • /boot partition (partly) encrypted
  • legacy boot GRUB, not UEFI (i’m on hetzner vps)

Before asking this question :

Here the actual working result on public gist : https://gist.github.com/reyman/65ed5de52bef3f2230825f68b0b831c6

The LVM and LUKS part of script :

diskdev=/dev/sda
bootpart=/dev/sda2
rootpart=/dev/sda3

sgdisk -o -g -n 1::+5M -t 1:ef02 -n 2::+500M -t 2:8300 -n 3:: -t 3:8300 $diskdev

echo "$password" cryptsetup luksFormat --type luks1 -h sha512 $rootpart
echo "$password" cryptsetup luksOpen $rootpart enc-pv

pvcreate /dev/mapper/enc-pv
vgcreate vg0 /dev/mapper/enc-pv
lvcreate -L 8G -n swap vg0
lvcreate -L 40G -n nixos vg0
lvcreate -l '100%FREE' -n home vg0

# format disk
mkfs.ext2 -L boot $bootpart
mkfs.ext4 -L root /dev/vg0/nixos
mkfs.ext4 -L home /dev/vg0/home
mkswap -L swap /dev/vg0/swap

swapon /dev/vg0/swap
mount /dev/vg0/nixos /mnt
mkdir /mnt/boot
mount $bootpart /mnt/boot # boot is encrypted by the mounting ?

The configuration.nix part with grub / secrets / network

               boot.loader.grub.devices = [ "/dev/sda" ];
                boot.loader.grub.enable = true;
                boot.loader.grub.version = 2;
                boot.loader.grub.enableCryptodisk = true;
                boot.loader.supportsInitrdSecrets = true;
        
                boot.initrd.kernelModules = [ "dm-snapshot" ];
                boot.initrd.availableKernelModules = ["virtio-pci"];
                boot.initrd.network = {
                  enable = true;
                  ssh = {
                    enable = true;
                    port = 2222;
                    authorizedKeys = ["ssh-rsa  xxx"];
                    hostKeys = [ "/host_ecdsa_key" ];
                    };
                };
        
                boot.initrd.luks.devices = [
                  {
                    name = "enc-pv";
                    preLVM = true;
                    device = "$luksuuid";
                    allowDiscards = true;
                  }
                ];
        
                boot.initrd.secrets = {
                  "/host_ecdsa_key" = "/host_ecdsa_key";
                  };

But there are some points i don’t understand and someone could probably enlight me :

  • in many tutorial, with /boot encrypted, normaly we need to enter the passphrase twice, for Grub, then at stage 1, this is not the case with this config, password is only asked at stage 1. Why ??

  • in this step many tutorials mount /boot/efi and not /boot , but in legacy boot, we use directly /boot. Where is the magic ? Where did we say that /boot files are encrypted in this case ? We mount something unencrypted (/dev/sda2 as /mnt/boot) to something encrypted (/dev/sda3 as /mnt), but /dev/sda2 continue to be unencrypted.

  • So if it’s not the case, what’s the best way to encrypt /boot without or without creating a new encrypted partition ?

  • and a more general question, i see in many tutorials some peoples using “keyfile” to automaticaly unlock encrypted partitions ? This is counter productive in term of security, isn’it ? What’s the interest ?

Thanks for your help on that,

The answer to your first two questions seems to be that /boot is not encrypted, therefore does not require a password.

As for the key file, this can provide a layer of security when the keyfile is located on removable storage, as it requires that an attacker have access to both the computer and the removable storage at the same time to boot. Ideally, you would set it up to require 2 factors: something you know, a password; and something you have, a keyfile on removable storage.

1 Like

Thanks @theotherjimmy

So i add a question ahah, is there a way to encrypt /boot using legacy bios, or these tutorial listed on top of my post are only for uefi ?

Fundamentally, Full disk encryption needs to de decrypted by something prior to what that resides on the encrypted partition, and if you wish to encrypt the boot partition, your bootloader that resides there would also have to be decrypted by something. The legacy BIOS method of booting is to load the first block of an attached storage. I have yet to see an option to load and decrypt from any of these legacy BIOS implementations, or a boot stub that is able to do decryption (decryption in < 512 bytes of code would be quite the feat). Some help is needed from the firmware, and I have yet to see a firmware that implements decryption in the legacy BIOS boot path.

That’s a bit of a long winded way off saying “no, you have to use UEFI”.

1 Like

@theotherjimmy I understand, but i see that GRUB2 is capable to decrypt LUKS 1 partition. I’m my mind it was possible at least to :

  • mount /boot on /sda2
  • mount LVM luks on /sda3
  • Try to use Grub option to decrypt /sda2 at launch.

This is less elegant than encrypted /boot into /sda3 and /boot/efi on /sda2 but that’s work isn’t it ?

Any news on this ? I’m interested by a working solution, before cross posting on stack overflow.

Hey reyman, I missed your reply back in July. Some software has to decrypt Grub, no matter where it’s stored. That’s usually the BIOS. If your BIOS won’t decrypt, and you have no other options, I don’t think you can have full disk encryption, or full boot chain encryption. You can try to have Grub decrypt /boot, though I don’t know how well that will work. If I recall correctly, Grub uses a stub i the boot block to load the rest of Grub (sort o fa bootloder for your bootloader, fun). That stub can’t be encrypted without the help of the BIOS.

As an aside, you’re asking firmware and bootloader questions which you may get more help with elsewhere. Maybe a community dedicated to Grub could give you more help.

1 Like

Hi, no problem @theotherjimmy, i finally found my way, as Grub 2 is capable to find and decrypt /boot partition in LVM volume (GNU GRUB Manual 2.12 abd https://cryptsetup-team.pages.debian.net/cryptsetup/encrypted-boot.html ).

This config works with legacy BIOS: nixos-install.sh · GitHub

/boot is located and encrypted on LVM.

But, on a VPS, i lost the capacity to decrypt from SSH at GRUB stage 1. The only way to enter the passphrase at grub running was to use Hetzner VPS web console. I ask question about that to Hetzner but access to GRUB using Serial mode redirection on Lan (SOL) is actually not possible/available. After GRUB decrypt, passphrase is asked a second time, accessible on ssh this time.

So the only way to remote unlock using ssh on vps was to move /boot on unencrypted partition … I don’t found the option for that on legacy bios on Nixos.

1 Like