Categories
Tech

Ubuntu 14.04 LUKS Encrypted ZFS Root

Install the ZFS native repository for Ubuntu:

apt-add-repository --yes ppa:zfs-native/stable
apt-get update
apt-get install debootstrap ubuntu-zfs

We need a small partition for grub and a small RAID for the unencrypted /boot partition. I create an additional very small raid, with a LUKS container inside, so that all keys can be derived from that. The rest of the space is for the LUKS container with a ZFS pool and the root filesystem inside.

parted -s -a optimal /dev/sda mklabel gpt
parted -s -a minimal /dev/sda mkpart primary 1MiB 2MiB
parted -s -a optimal /dev/sda set 1 bios_grub on
parted -s -a optimal /dev/sda mkpart primary 2MiB 200MiB
parted -s -a optimal /dev/sda set 2 raid on
parted -s -a optimal /dev/sda mkpart primary 200MiB 220MiB
parted -s -a optimal /dev/sda set 3 raid on
parted -s -a optimal /dev/sda mkpart primary 220MiB 100%

parted -s -a optimal /dev/sdb mklabel gpt
parted -s -a minimal /dev/sdb mkpart primary 1MiB 2MiB
parted -s -a optimal /dev/sdb set 1 bios_grub on
parted -s -a optimal /dev/sdb mkpart primary 2MiB 200MiB
parted -s -a optimal /dev/sdb set 2 raid on
parted -s -a optimal /dev/sdb mkpart primary 200MiB 220MiB
parted -s -a optimal /dev/sdb set 3 raid on
parted -s -a optimal /dev/sdb mkpart primary 220MiB 100%

Next we create the raid

apt-get install mdadm --no-install-recommends
mdadm --create --verbose /dev/md/0 --level=1 --raid-devices=2 /dev/sda2 /dev/sdb2
#Answer Yes, if asked for 1.x metadata format
mdadm --create --verbose /dev/md/1 --level=1 --raid-devices=2 /dev/sda3 /dev/sdb3
#Answer Yes, if asked for 1.x metadata format

And then create the LUKS containers

cryptsetup luksFormat -l 512 -c aes-xts-plain64 -h sha512 /dev/md/1
cryptsetup luksOpen /dev/md/1 cryptroot
/lib/cryptsetup/scripts/decrypt_derived cryptroot | cryptsetup -s 512 -c aes-xts-plain64 -h sha512 luksFormat /dev/sda4
/lib/cryptsetup/scripts/decrypt_derived cryptroot | cryptsetup luksOpen /dev/sda4 crypt1
/lib/cryptsetup/scripts/decrypt_derived cryptroot | cryptsetup -s 512 -c aes-xts-plain64 -h sha512 luksFormat /dev/sdb4
/lib/cryptsetup/scripts/decrypt_derived cryptroot | cryptsetup luksOpen /dev/sdb4 crypt2

Create the zpool

zpool create -O mountpoint=none -o ashift=12 rpool mirror /dev/mapper/crypt1 /dev/mapper/crypt2
zfs create -o mountpoint=/ rpool/ROOT
zfs create -o mountpoint=none rpool/DATA
zpool set bootfs=rpool/ROOT rpool
zpool export rpool
zpool import -R /mnt rpool

install the base system

debootstrap saucy /mnt
mount --bind /dev/ /mnt/dev

Change into the new system

chroot /mnt /bin/bash --login

You are inside the new system now.

mkfs.ext4 /dev/mapper/cryptroot
mkfs.ext4 /dev/md0 
mount /dev/md0 /boot
mount -t proc proc /proc
mount -t sysfs sysfs /sys
ln -sf /dev/mapper/cryptroot /dev/cryptroot
ln -sf /dev/mapper/crypt1 /dev/crypt1
ln -sf /dev/mapper/crypt2 /dev/crypt2

locale-gen $LANG
locale-gen en_US.UTF-8

apt-get update
apt-get install software-properties-common

apt-add-repository --yes ppa:zfs-native/stable
apt-get update

apt-get install linux-image-server linux-headers-server ubuntu-minimal

apt-get install ubuntu-zfs cryptsetup

apt-get install mdadm --no-install-recommends
grub-install /dev/sda
grub-install /dev/sdb

apt-get install zfs-initramfs

echo "cryptroot UUID=$(blkid /dev/md/1 -s UUID -o value) none luks">> /etc/crypttab
echo "crypt1 UUID=$(blkid /dev/sda4 -s UUID -o value) cryptroot luks,keyscript=/lib/cryptsetup/scripts/decrypt_derived" >> /etc/crypttab 
echo "crypt2 UUID=$(blkid /dev/sdb4 -s UUID -o value) cryptroot luks,keyscript=/lib/cryptsetup/scripts/decrypt_derived" >> /etc/crypttab

echo "UUID=$(blkid /dev/md0 -s UUID -o value) /boot ext4 rw,relatime,stripe=4,data=ordered 0 0"> /etc/fstab
#we need a fake root system so that the crypt tools get added to the initramfs
#we cannot use /dev/mapper/cryptroot, since the initramfs is missing the derived script then...
echo "/dev/mapper/crypt1 / none none 0 0">> /etc/fstab

echo "target=cryptroot,source=UUID=$(blkid /dev/md/1 -s UUID -o value),key=none,rootdev"> /etc/initramfs-tools/conf.d/cryptroot
echo "target=crypt1,source=UUID=$(blkid /dev/sda4 -s UUID -o value),key=cryptroot,keyscript=/lib/cryptsetup/scripts/decrypt_derived,rootdev" >> /etc/initramfs-tools/conf.d/cryptroot
echo "target=crypt2,source=UUID=$(blkid /dev/sdb4 -s UUID -o value),key=cryptroot,keyscript=/lib/cryptsetup/scripts/decrypt_derived,rootdev" >> /etc/initramfs-tools/conf.d/cryptroot

update-initramfs -u -k all

sed -i 's|GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"|GRUB_CMDLINE_LINUX_DEFAULT="boot=zfs noplymouth"|' /etc/default/grub

update-grub

adduser <myuser>
adduser <myuser> sudo

/etc/init.d/mdadm stop
umount /boot
umount /sys
umount /proc
exit

You are back in the host system now

umount /mnt/dev
zpool export rpool
reboot

Unlock your server via SSH

apt-add-repository universe
apt-get update

apt-get install openssh-server
#make sure that openssh-server is installed before dropbear
apt-get install dropbear

#use the same host key in initramfs as in real system
cp /etc/dropbear/dropbear_dss_host_key /etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key
cp /etc/dropbear/dropbear_rsa_host_key /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key

#add your public keys to /etc/initramfs-tools/root/.ssh/authorized_keys

Add the file /etc/initramfs-tools/hooks/unlock with the following contents:

#!/bin/sh -e

PREREQS=""

prereqs() { echo "$PREREQS"; }

case "$1" in
    prereqs)
    prereqs
    exit 0
    ;;
esac

## hook-functions provides copy_exec()
. /usr/share/initramfs-tools/hook-functions

echo "/sbin/cryptsetup luksOpen /dev/md/1 cryptroot">$DESTDIR/bin/unlock
echo 'kill $(pidof cryptsetup)'>>$DESTDIR/bin/unlock
echo 'kill $(pidof plymouth)'>>$DESTDIR/bin/unlock

chmod a+x $DESTDIR/bin/unlock

 

chmod a+x /etc/initramfs-tools/hooks/unlock
update-initramfs -u -k all

You can now log into your initramfs during boot via shh with the root user and unlock the disks by calling:

unlock
exit

 

Leave a Reply

Your email address will not be published. Required fields are marked *