Problem: You have a computer running Debian 7 wheezy (also Debian 8 jessie) with an encrypted root filesystem. At startup you'd like to be able to unlock the disk over ssh, maybe because it runs headless.

There are some existing solutions to this: early-ssh worked on previous Debian versions. There are other blog posts showing some methods but I found them unwieldy (ie a 35 second delay before you can type your passphrase.)

Here's how I'm doing it. Unless otherwise mentioned, all of the following commands need to be run as root. The server name in the examples is "debian_headless"

At time of writing I was using versions Debian 7.0 Wheezy with packages cryptsetup 2:1.4.3-4, initramfs-tools 0.109.1 and dropbear 2012.55-1.3.

[EDIT Jan 2015: Page now updated with a small tweak that makes it work perfectly on Debian 8/Jessie also. Thanks to olze in the comments for figuring that out.]

These steps may work on recent Ubuntu versions as well, please let me know if you try them out. [EDIT: after some discussion in the comments, we determined Ubuntu's busybox packaging means that it won't work without more tweaks.]

Overview

The very first thing a Debian system runs at startup is a minimal initramfs ramdisk which performs basic initialisation, mounts the main filesystem and starts the rest of the boot process.

This is the stage when an encrypted rootfs gets mounted. We need to customise it so we can ssh in and unlock the rootfs.

Install prerequisites

apt-get install dropbear initramfs-tools busybox

Dropbear is a slimline SSH server. This package installs into the initramfs and runs during early boot only, allowing you to log in remotely.

Authorise the user(s) you want to be able to login as root and unlock

Hopefully you're already using SSH Key Authentication, otherwise have a read about it and why it's a good idea. Set it up for the user(s) on the client systems by having them run ssh-keygen.

You have to add the public keys for these users to Dropbear's list of authorized_keys for login.

For each client user you want to allow to unlock, take their public key file ~/.ssh/id_rsa.pub and append it to /etc/initramfs-tools/root/.ssh/authorized_keys

One way of doing it:

scp ~/.ssh/id_rsa.pub myuser@debian_headless:id_rsa.pub
ssh myuser@debian_headless
sudo sh -c "cat id_rsa.pub >> /etc/initramfs-tools/root/.ssh/authorized_keys"
rm id_rsa.pub

Alternative: Have a unique key for root/unlock

If you don't want to use your usual user-level ssh key and passphrase to provide potential root-level access to your headless machine, generate a separate key (with a different passphrase) and then copy it across to authorized_keys instead:

ssh-keygen -f ~/.ssh/id_rsa_headlessunlock
scp ~/.ssh/id_rsa_headlessunlock.pub myuser@debian_headless:id_rsa.pub
(etc, as above.)

Add network hardware module

The initramfs doesn't usually load network hardware modules, so you should add the name of the network hardware module directly to /etc/initramfs-tools/modules

You can find the module name via sysfs. For example:

$ grep DRIVER /sys/class/net/eth0/device/uevent
DRIVER=e1000

So to enable eth0 in this case, you'd add e1000 to /etc/initramfs-tools/modules.

(This may not be necessary on "normal" x86 machines with built-in ethernet, it's definitely necessary using USB Ethernet on my ARM-based GK802 stick and it's probably necessary on Raspberry Pi.)

Configure early boot IP Address

Initramfs needs to know the IP address to come up on. You could do this by passing the 'ip=' kernel command line parameter, but you can also just set it in an initramfs-tools config file:

Create /etc/initramfs-tools/conf.d/network_config with contents like this:

export IP=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>

<server-ip> can be left blank. Some possible examples:

export IP=dhcp

or

export IP=10.0.0.2::10.0.0.1:255.0.0.0:myserver:eth0

See the nfsroot kernel docs for full details. Remember if using DHCP that you'll need a static DHCP entry configured so you can predict what IP your headless machine is going to have on startup.

Annoyance: Interface doesn't reconfigure

It seems that after the main system boots, the network interface won't automatically change to whatever is set in /etc/network/interfaces (because the interface is seen to be already "up" it gets left alone.) ~~To work around this you could put a line ifdown eth0; ifup eth0 in /etc/rc.local,~~ or just keep the initramfs network settings the same as the ones in /etc/network/interfaces.

EDIT: bikepunk posted in the comments with a correct workaround for this. Add the following line to /etc/network/interfaces under your primary interface's heading:

pre-up ip addr flush dev eth0

Unlock Script

I've written a little initramfs-tools hook that generates scripts for easy unlocking of the rootfs.

Download this script file, then read it to make sure you're not suspicious about what it's going to do. Then copy it to /etc/initramfs-tools/hooks/mount_cryptroot and mark it executable:

chmod +x /etc/initramfs-tools/hooks/mount_cryptroot

There's a section at the top of mount_cryptroot that allows you to set an ALLOW_SHELL variable if you want to be able to drop to a remote root shell for diagnostics. Note that this explicitly allows a remote root shell to anyone with an authorised SSH private key. I can't guarantee it's impossible to get to a root shell otherwise, but it's at least not explicitly welcomed.

Update the initramfs

Update the initramfs so it includes all your changes:

update-initramfs -u

Add client SSH config entry

Because Dropbear has a different SSH host key to the normal system, OpenSSH will (rightly) complain if you try connecting to it on the same IP. The solution is to create a special host definition for the initramfs environment. A custom section in ~/.ssh/config:

Host headless_unlock
HostName <IP of headless>
User root
HostKeyAlias headless_unlock

Now you can log in to the unlock stage by simply typing ssh headless_unlock. (Replace headless with whatever name you want to use.)

[EDIT: Benjamin has pointed out in the comments that it's possible to have the same host key in Dropbear and OpenSSH together. So you can follow his steps instead, if you'd like the same host key for both cases. Thanks Benjamin!]

If you authorized a unique private key to use for unlocking, you can add another line IdentityFile ~/.ssh/id_rsa_headless or similar.

Putting it all together

Here's what it looks like to connect to my headless host and unlock the disk:

$ ssh headless_unlock

BusyBox v1.20.2 (Debian 1:1.20.0-7) built-in shell (ash)
Enter 'help' for a list of built-in commands.

Unlocking rootfs...
Enter passphrase: 
Success
Connection to 192.168.56.101 closed.

Easy!

Final word about security

When dealing with remote access and with encryption, it's always worth thinking about security tradeoffs.

There's the obvious risk that enabling Dropbear in the initramfs means allowing remote root logins to your system. Even with ALLOW_SHELL turned off there's no guarantee that someone with access to an authorized SSH key (or Dropbear exploit) can't log in, pop a root shell somehow, and cause havoc.

In addition, when I was looking for existing techniques to do this I came across a post exclaiming ssh unlocking was a terrible idea, because someone with physical access to your machine can then impersonate you remotely and you'll never know.

I think this is worth considering, but it's not as bad as it might seem. All encrypted disk access, with local or remote unlocking, relies on physical security of your device. Yes, if someone gets physical or root access they can steal your Dropbear host key and set up another server that pretends to be you and steals your keys. However, they already have physical or root access. They can just as easily insert malware in the initramfs that quietly captures your passphrase as you type it in in locally.

In either case, you have to be sufficiently sure noone is messing with you. With remote access that's maybe more likely, but I'm not too worried. I'm using this on a USB stick PC that fits in my pocket, and I don't want a burglar walking out my door with all my personal data. If some very dedicated person comes after my data, there would be easier ways to get it.

(Also, an obvious disclaimer - all the advice/scripts on this page is worth what you paid for it. I'm not a security professional. Please tell me if it seems broken/unsafe, but don't blame me if you use it for something important and it isn't safe enough.)

Thoughts on “Unlocking an encrypted rootfs over ssh with Debian wheezy (or jessie)