Ubuntu with Grub2 + LUKS encrypted LVM root + hidden USB keyfile

Posted: January 2nd, 2012 | Author: | Filed under: computing | Tags: , , , , , | 2 Comments »

STANDARD DISCLAIMER APPLIES. USE AT YOUR OWN RISK. This is what worked for me. Your system may be different. IF THINGS GO WRONG YOU’LL BE STUCK DOING MANUAL SYSTEM RECOVERY. This is a high-level guide, not an exact step-by-step and assumes you are familiar with linux administration and command line.

Started with a fresh install of Ubuntu Server (Ubuntu Lucid 10.04.3 LTS) and wanted the same USB keyfile setup as used previously in the links below, but needed to adapt for Grub2.
Debian Lenny + LUKS encrypted root + hidden USB keyfile
Debian Lenny + LUKS encrypted root + hidden USB keyfile (part 2)

I’m too embarrassed to publish how long it took me to figure this out. Let’s just say it’s working now:

1) System setup using the manual partitioner to create crypt container partition and LVM partitions. Use the same process as described here to create and test the usb key and the udev rule file.

2) The keyscript has changed (including modifying the keyscript filename to remove the hyphens, update-initramfs would not copy in the script with hyphens in the filename). Create the following keyscript as “/usr/local/sbin/unlockusbkey.sh”


# flag tracking key-file availability

# check and modprobe the USB driver if not already loaded
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
if [ $USBLOAD -gt 0 ]; then
modprobe usb_storage >/dev/null 2>&1

# give the system time to settle and open the USB device
sleep 10

# check for the specifc /dev/usbkey device created by udev using /etc/udev/rules.d/99-unlock-luks.rules
if [ -b /dev/usbkey ]; then
# if device exists then output the keyfile from the usb key (hidden key is 4096 bytes long starting at 2048 bytes)
dd if=/dev/usbkey bs=512 skip=4 count=8 | cat

if [ $OPENED -ne $TRUE ]; then
echo "FAILED to get USB key file ..." >&2
if [ -x /bin/plymouth ] && plymouth --ping; then
plymouth ask-for-password --prompt "Enter passphrase"
/lib/cryptsetup/askpass "Enter passphrase"
echo "Success loading key file. Moving on." >&2

sleep 1
exit 0

Make the script executable:

# chmod a+x /usr/local/sbin/unlockusbkey.sh

3) Create/edit the following files (edit sda2_crypt and the UUID for your system):


sda2_crypt /dev/disk/by-uuid/uuid-goes-here none luks,keyscript=/usr/local/sbin/unlockusbkey.sh





4) Create this file (and make executable) to ensure your custom udev rule gets copied into the initrd image when running update-initramfs.


# udev-usbkey script

echo "$PREREQ"

case $1 in
exit 0

. /usr/share/initramfs-tools/hook-functions

# Copy across relevant rules

cp /etc/udev/rules.d/99-unlock-luks.rules ${DESTDIR}/lib/udev/rules.d/

exit 0

5) Edit your Grub2 config. The key line is “GRUB_CMDLINE_LINUX_DEFAULT”. Notice the initrd keyscript location is different than the previous setups (using cryptsetup 2:1.1.0~rc2-1ubuntu13 and initramfs-tools 0.92bubuntu78).


# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.

GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`

# Uncomment to disable graphical terminal (grub-pc only)

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'

# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux

# Uncomment to disable generation of recovery mode menu entries

# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"

6) Run “update-grub” and check the generated /boot/grub/grub.cfg file to verify the cryptopts kernel options were added.

7) Update the initrd image for your current kernel (or just run “update-initramfs -u” to update all kernels):

# update-initramfs -u -k 2.6.XX-XX-server

8) If you want to verify that everything has copied correctly, you can unpack your current initrd.img to the tmp directory and look through the extracted files. The keyscript should have been copied into the “lib/cryptsetup/scripts” directory and and udev rule into “lib/udev/rules.d/”. The grub keyscript line above should match the location of the keyscript in the initrd image.

# cd /tmp
# zcat /boot/initrd.img-2.6.XX-X-amd64 | cpio -iv

9) If all looks in order then reboot. With the USB stick inserted the system should boot all the way to the login prompt. Without the USB stick it should prompt you for your crypt password to mount the root filesystem.

If something goes wrong you’ll likely get dropped to the “(initramfs)” prompt. From here you can manually unlock the crypt partition using “cryptsetup luksOpen /dev/sda2 sda2_crypt” and entering your crypt password. If this unlocks successfully then typing “exit” should drop you back into the automated boot sequence.


Steps for creating & adding additional crypt disks:

1) Use fdisk to create the new partition (using /dev/sdx1 for example) with Type 83, Linux

2) Optional -- good idea to check for badblocks and fill partition with pseudo-random data:
badblocks -c 10240 -s -w -t random -v /dev/sdx1

Or, for truly paranoid types (verrry slow):
dd if=/dev/urandom of=/dev/sdx1

3) Create new luks partition
# cryptsetup --verify-passphrase --verbose --hash=sha256 --cipher=aes-cbc-essiv:sha256 --key-size=256 luksFormat /dev/sdx1
# cryptsetup luksOpen /dev/sdx1 sdx1_crypt

4) create LVM
# pvcreate /dev/mapper/sdx1_crypt
# vgcreate vgname /dev/mapper/sdx1_crypt
# lvcreate -LXXG -n lvname vgname

5) format new LVM partition (example uses ext4 fs)
# mkfs.ext4 /dev/vgname/lvname

6) mount new LV (add to /etc/fstab to make persistent)
# mount /dev/mapper/vgX-nameX /mnt/nameX

7) find the uuid of the encrypted physical partition
# ls -al /dev/disk/by-uuid
uuid-goes-here -> ../../sdx1


cryptsetup luksDump /dev/sdx1

8) add new line to /etc/crypttab
sdx1_crypt /dev/disk/by-uuid/uuid-goes-here none luks,keyscript=/usr/local/sbin/unlockusbkey.sh

9) Add the USB key to the new crypt partition:
cryptsetup luksAddKey /dev/sdx1 /root/luks-secret.key --key-slot 1

10) Update the initrd for good measure:
update-initramfs -u

11) profit.