Boot time unlocking of encrypted disk via IPv6 SSH (Debian 8 Jessie)

Sometimes I have to deploy servers that require full disk encryption (FDE). Either for compliance reasons or just because I do not fully trust the data center they end up in.

Unlocking FDE means interfacing with the machine at boot time. This, however, has proofed to be quite a challenge. Especially remote management and KVM solutions like IPMI or IMM are sometimes buggy, usually hid away using VPN and I have my doubts about their understanding of strong cryptography ;)

Not wanting to go through all the hassle that is involved with unlocking FDE via remote management, I looked for better solutions. Luckily, boot-time unlocking of FDE via SSH over IPv6 in current Linux distributions has improved a lot lately. Read ahead to learn about my FDE setup on Debian 8 Jessi featuring dual-stack accessible SSH.

The bigger picture: We want to a server with freshly installed, and full disk encrypted, Debian 8 Jessie to boot an initial ramdisk that is capable of dual-stack networking (we still need IPv4 sometimes). A SSH server, we choose dropbear as it is small and fast, will wait for us to log in and unlock the encrypted disk. After unlocking the system continues to boot until it reaches its normal mode of operation.

Let’s assume we are logged in as super user on the corresponding machine. First step is to install the dropbear SSH server.

# apt-get install dropbear
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  dropbear
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
✂️
Preparing to unpack .../dropbear_2014.65-1_amd64.deb ...
Unpacking dropbear (2014.65-1) ...
✂️
Setting up dropbear (2014.65-1) ...
✂️
Wrote key to '/etc/initramfs-tools/root/.ssh/id_rsa'

Unfortunately, the package creates a SSH key on its own, which can be used to login via SSH. We will remove the auto-generated keys as it is not a good idea to store any private key at the unencrypted part of the system.

# rm /etc/initramfs-tools/root/.ssh/id_rsa
# rm /etc/initramfs-tools/root/.ssh/id_rsa.pub
# rm /etc/initramfs-tools/root/.ssh/id_rsa.dropbear

For authentication against the pre-boot SSH we will have to place the public SSH keys of all users who should be able to unlock the drive in /etc/initramfs-tools/root/.ssh/authorized_keys. This file will automatically become part of the initial ramdisk later.

Now that we have taken care of security, let’s move on to preparing the initial ramdisk building configuration. We edit /etc/initramfs-tools/initramfs.conf to enable dropbear, configure networking and set legacy IP address (if required).

DROPBEAR=y
✂️
DEVICE=eth0
IP=100.64.1.2::100.64.1.1:255.255.255.0::eth0:off

For IPv6 configuration we need to add a script to the initial ramdisk that gets executed before the disk is being unlocked. We create /etc/initramfs-tools/scripts/local-top/ipv6 which contains the IPv6 configuration, among with important boilerplate which makes sure it does not get executed at build-time.

#!/bin/sh

PREREQ=""
prereqs()
{
  echo "$PREREQ"
}
case $1 in
  prereqs)
    prereqs
    exit 0
    ;;
esac

ip addr add 2001:db8::1337/64 dev eth0
ip route add default via 2001:db8::1

exit 0

We now have to make sure this script is executable, as it is required by update-initramfs which we will run eventually.

# chmod +x /etc/initramfs-tools/scripts/local-top/ipv6

There are different ways of unlocking the disk once we have logged in to the pre-boot SSH server. One that makes sure we can unlock via SSH but still allows unlocking directly by connecting a keyboard and a screen to the server is the passfifo method. A simple script that uses the method might look like this and should be placed in /etc/initramfs-tools/hooks/unlock:

#!/bin/sh

PREREQ=""
prereqs()
{
  echo "$PREREQ"
}
case $1 in
  prereqs)
    prereqs
    exit 0
    ;;
esac

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

cat > "${DESTDIR}/root/unlock" << EOF
#!/bin/sh
/lib/cryptsetup/askpass 'passphrase: ' > /lib/cryptsetup/passfifo
EOF

chmod u+x "${DESTDIR}/root/unlock"

exit 0

Once again we will have to make sure the script is executable:

# chmod +x /etc/initramfs-tools/hooks/unlock

Small caveat ahead! The network interface configuration is more persistent than one might wish. We need to flush the address configuration of the interface after unlocking the disk. Otherwise it might interfere with boot-time network configuration. I therefore recommend creating another script named /etc/initramfs-tools/scripts/local-bottom/flush which flushes the interface’s configuration.

#!/bin/sh

PREREQ=""
prereqs()
{
  echo "$PREREQ"
}
case $1 in
  prereqs)
    prereqs
    exit 0
    ;;
esac

ip addr flush dev eth0
ip route flush dev eth0

exit 0

You know the drill, we have to make sure this script is executable again.

# chmod +x /etc/initramfs-tools/scripts/local-bottom/flush

And that finishes configuration! It is now time to build the initial ramdisk and reboot the system.

# update-initramfs -u
# reboot

Like to see a preview? Here is how it looks like:

$ ssh root@2001:db8::1337
BusyBox v1.22.1 (Debian 1:1.22.0-9+deb8u1) built-in shell (ash)
Enter 'help' for a list of built-in commands.

~ # ./unlock
passphrase: *********************************************

Enjoy and don’t hesitate to drop me a line if you like to comment on this post.