codeblog code is freedom — patching my itch

August 30, 2017

GRUB and LUKS

Filed under: Blogging,Debian,Security,Ubuntu,Ubuntu-Server — kees @ 10:27 am

I got myself stuck yesterday with GRUB running from an ext4 /boot/grub, but with /boot inside my LUKS LVM root partition, which meant GRUB couldn’t load the initramfs and kernel.

Luckily, it turns out that GRUB does know how to mount LUKS volumes (and LVM volumes), but all the instructions I could find talk about setting this up ahead of time (“Add GRUB_ENABLE_CRYPTODISK=y to /etc/default/grub“), rather than what the correct manual GRUB commands are to get things running on a failed boot.

These are my notes on that, in case I ever need to do this again, since there was one specific gotcha with using GRUB’s cryptomount command (noted below).

Available devices were the raw disk (hd0), the /boot/grub partition (hd0,msdos1), and the LUKS volume (hd0,msdos5):

grub> ls
(hd0) (hd0,msdos1) (hd0,msdos5)

Used cryptomount to open the LUKS volume (but without ()s! It says it works if you use parens, but then you can’t use the resulting (crypto0)):

grub> insmod luks
grub> cryptomount hd0,msdos5
Enter password...
Slot 0 opened.

Then you can load LVM and it’ll see inside the LUKS volume:

grub> insmod lvm
grub> ls
(crypto0) (hd0) (hd0,msdos1) (hd0,msdos5) (lvm/rootvg-rootlv)

And then I could boot normally:

grub> configfile $prefix/grub.cfg

After booting, I added GRUB_ENABLE_CRYPTODISK=y to /etc/default/grub and ran update-grub. I could boot normally after that, though I’d be prompted twice for the LUKS passphrase (once by GRUB, then again by the initramfs).

To avoid this, it’s possible to add a second LUKS passphrase, contained in a file in the initramfs, as described here and works for Ubuntu and Debian too. The quick summary is:

Create the keyfile and add it to LUKS:

# dd bs=512 count=4 if=/dev/urandom of=/crypto_keyfile.bin
# chmod 0400 /crypto_keyfile.bin
# cryptsetup luksAddKey /dev/sda5 /crypto_keyfile.bin
*enter original password*

Adjust the /etc/crypttab to include passing the file via /bin/cat:

sda5_crypt UUID=4aa5da72-8da6-11e7-8ac9-001cc008534d /crypto_keyfile.bin luks,keyscript=/bin/cat

Add an initramfs hook to copy the key file into the initramfs, keep non-root users from being able to read your initramfs, and trigger a rebuild:

# cat > /etc/initramfs-tools/hooks/crypto_keyfile <<EOF
#!/bin/bash
if [ "$1" = "prereqs" ] ; then
    cp /crypto_keyfile.bin "${DESTDIR}"
fi
EOF
# chmod a+x /etc/initramfs-tools/hooks/crypto_keyfile
# chmod 0700 /boot
# update-initramfs -u

This has the downside of leaving a LUKS passphrase “in the clear” while you’re booted, but if someone has root, they can just get your dm-crypt encryption key directly anyway:

# dmsetup table --showkeys sda5_crypt
0 155797496 crypt aes-cbc-essiv:sha256 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 8:5 2056

And of course if you’re worried about Evil Maid attacks, you’ll need a real static root of trust instead of doing full disk encryption passphrase prompting from an unverified /boot partition. :)

© 2017, Kees Cook. This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 License.
CC BY-SA 4.0

6 Comments

  1. The initramfs hook script is incorrect; it needs to check for the special case of $1 = prereqs.

    Comment by Ben Hutchings — August 30, 2017 @ 2:30 pm

  2. Ah, good point. I think it’s correct now, thanks!

    Comment by kees — August 30, 2017 @ 2:42 pm

  3. Thanks a lot. I was never stuck needing this information but it could have save me some time.

    Comment by claudex — August 30, 2017 @ 11:24 pm

  4. Great, finally someone had everything needed to make it work!

    Comment by Tr4sK — November 12, 2017 @ 9:42 pm

  5. initramfs’s can be inspected sometimes by simply gzip -d | cpio -idvm the /boot/initrd*
    grub has access to these files. so would any usb boot.

    So your key is in the clear and available to anyone. Unless you lock your initramfs down somehow. do you?

    Comment by patrick — February 20, 2018 @ 7:57 am

  6. A bit more complicated way to protect protect the keyfile would be:

    – Separate /boot from the big LVM partition, in a separate LUKS partition.
    – Put the crypto_keyfile.bin in /boot/crypto_keyfile.bin and update the hook script accordingly.
    – Have the /boot partition as “noauto” in the running system and only mount /boot when updating the kernel, ramdisk, etc

    The advantages is that (as long as /boot is not mounted) you never expose the boot kernel or keyfile, etc in the running system. If someone get root access they have to know the “GRUB password” to get the keyfile or mess with your boot environment.

    DISCLAIMER: I not tested this yet, but that’s my plan for the next box I install.

    Comment by Mem — March 6, 2018 @ 5:26 am

Powered by WordPress