How to unlock a LUKS volume on boot on Raspberry Pi OS

LUKS (Linux Unified Key Setup) is the de facto standard encryption method used on Linux-based operating systems. As we saw in previous tutorials, when we want a partition or raw disk encrypted using LUKS to be automatically unlocked at boot, we need to enter a dedicated line into the /etc/crypttab file. Doing so, we are prompted to provide the encryption password interactively. This is quite straightforward on laptop or desktop machines, but how can we unlock a volume on an headless server? One solution is to use dropbear to get ssh access at an early boot stage, in the initramfs, in order to provide the volume password. In this tutorial we see how to use dropbear-initramfs to get ssh access at an early boot stage, in order to unlock a LUKS volume.

In this tutorial you will learn:

  • How to install and configure dropbear-initramfs on Raspberry-pi os
  • How to generate an initramfs
  • How to configure a static IP address in the initramfs
  • How to create a crypttab entry for the LUKS device
  • How to ssh at an early boot stage and provide the LUKS volume password
How to unlock a LUKS volume on boot on Raspberry Pi OS
How to unlock a LUKS volume on boot on Raspberry Pi OS
Software requirements and conventions used
Category Requirements, Conventions or Software Version Used
System Raspberry Pi OS
Software dropbear-initramfs
Other None
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command $ – requires given linux-commands to be executed as a regular non-privileged user

Introducing and installing Dropbear

Dropbear is a free and open source SSH server and client available on a vast range of Unix platforms. Since it is very lightweight, it is often used in embed devices where resources are limited. On Debian, and Debian-based distributions like Raspberry Pi OS, a package called dropbear-initramfs provides support for integrating Dropbear into the system initramfs. To proceed with this tutorial, we need to install it, so we run:

$ sudo apt install dropbear-initramfs



As part of the installation some SSH keys will be generated, and stored into the /etc/dropbear-initramfs directory:

$ ls -l /etc/dropbear-initramfs
[...]
-rw------- 1 root root 141 Jun 27 16:03 dropbear_ecdsa_host_key
-rw------- 1 root root 83 Jun 27 16:03 dropbear_ed25519_host_key
-rw------- 1 root root 805 Jun 27 16:03 dropbear_rsa_host_key

Don’t worry if you are already using OpenSSH on the system, those keys will only be used in the context of the initramfs.

Configuring dropbear-initramfs

Once we installed the dropbear-initramfs package, we must configure it. We can do this by writing the appropriate line into the /etc/dropbear-initramfs/config file. What we want to change in the file is the value of the DROPBEAR_OPTIONS variable. The options we specify as value of the variable are passed to Dropbear when we login via SSH in the initramfs context:

#
# Command line options to pass to dropbear(8)
#
DROPBEAR_OPTIONS="-jks -p 2222 -c cryptroot-unlock"

The -j and -k options are used to disable local and remote SSH port forwading, respectively. Local port forwarding is a technique which is used to tunnel traffic received on a specific port on the SSH client to a specific port on the machine used as SSH server; remote port forwarding works in the opposite way: it is used to forward the traffic received on a port on the SSH server to a port on the client machine. One usage of SSH port forwarding is to provide encryption for the traffic generated by applications which use unencrypted protocols like FTP. We don’t need port forwarding in this context, so we disable this feature.

The -s option is used to disable password login. To login via SSH into the temporary system provided by the initramfs we use public key authentication. We need to log in as the root user, and in this context, even if we wanted to, it would not be possible to login with a password.



By default, SSH servers listen to port 22; in this case, however we used the -p option to specify we want to use another port, 2222. This is needed because, as we said before, dedicated host keys are generated when dropbear is installed, and those are obviously different from the ones used when connecting to the “real” system. The first time we connect to an SSH server, the server key is written to our local “known_hosts” file. This key is checked on subsequent connections, to avoid possible “man in the middle attack”. If the key of the server changes, a message similar to the following is displayed:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx.
Please contact your system administrator.
Add correct host key in /home/hostname /.ssh/known_hosts to get rid of this message.
Offending RSA key in /var/lib/sss/pubconf/known_hosts:4
RSA host key for pong has changed and you have requested strict checking.
Host key verification failed.

If we use the same port to connect via SSH when using dropbear in the initramfs and on the booted system, we will see this message. By specifying a different port for dropbear, we can avoid the error.

The last option we set in the example above is -c.  This option takes a command as argument: said command is forcibly run when the connection is established, no matter if another one is specified by the user. In this case, we used the cryptroot-unlock command. Cryptroot-unlock is a script provided by the cryptsetup-initramfs package: it is used to unlock devices specified in the /etc/crypttab file at boot.

Authorizing our key

As we mentioned before, we will login using public key authentication, therefore we need to copy the public key of our client into the /etc/dropbear-initramfs/authorized-keys file, which must be owned by root, and have 600 as permission mode, so it should be readable and writable only by its owner. If we normally login as a standard user into the system, and we want to use the same key, we can simply copy the ~/.ssh/authorized_key file existing in the home directory of the user we connect as in the server, to the aforementioned position:

$ sudo cp ~/.ssh/authorized_keys /etc/dropbear-initramfs/

We could also generate a dedicated keypair, and copy the content of the public key into the file.

Setting up crypttab and fstab

We need to create an entry for the LUKS encrypted block device which should be automatically unlocked at boot in the /etc/crypttab file. Here we will not describe in detail the crypttab syntax, as we described it in a dedicated tutorial. Here is what our crypttab entry must look like:

luks-200ce9d7-72de-443f-b669-e50d0a23f01a UUID=200ce9d7-72de-443f-b669-e50d0a23f01a none luks,initramfs



We identified the encrypted device by its UUID and configured it so it is will accessible as /dev/mapper/luks-200ce9d7-72de-443f-b669-e50d0a23f01a when unlocked.The very important thing to notice is that we used the initramfs option: this is not a standard cyrpttab option, but a Debian implementation and is needed for the entry to be included in the initramfs.

In this example, I want this device to be automatically mounted on /srv, so we need to add this line in /etc/fstab:

/dev/mapper/luks-200ce9d7-72de-443f-b669-e50d0a23f01a /srv ext4 defaults,noatime 0 2

By the way, if you are not familiar with fstab, we wrote a tutorial about its syntax, too.

Setting a static IP in the initramfs

To be able to login via SSH at an early boot stage, when the initramfs is used, we need to set a static IP for our machine. One way to do this is to set static leases in our router (if the device supports this feature), so that it statically assigns IP addresses to specific MAC addresses. If we use this strategy we don’t need to change anything on the client machine. The other way is to set a static IP on the client directly by using the “ip” kernel parameter. We can set this in the /etc/initramfs-tools/initramfs.conf file, using the following syntax:

IP=<client-ip>:<server-ip>:<gateway-ip>:<netmask>:<hostname>

Elements are separated by a colon; the first one is the client-ip, the second one, server-ip, is not needed in this context: it is used when connecting to a NFS server. The third element is the ip of the gateway, which in a home setup is typically the modem/router. The fifth element is the netmask, and the third is the machine hostname. Here is an example. We assign the static 192.168.0.39 IP to the machine:

IP=192.168.0.39::192.168.0.1:255.255.255.0:feanor

Generating the initramfs

We can now generate our initramfs and specify it should be used on boot. To generate the initramfs, we use the mkinitramfs command:

$ sudo mkinitramfs -o /boot/initramfs.gz



In the example above we used the -o option (short for --outfile) which takes as argument the path where the generated initramfs archive should be saved. In this case we saved it as /boot/initramfs.tar.gz. Once the initramfs is generated, for it to be used on boot, we need to append the following line to the /boot/config.txt file:

initramfs initramfs.gz followkernel

The initramfs command is used to specify the ramfs which should be used and the memory address where it should be loaded. By using “followkernel” we basically telling that the initramfs should be loaded in memory after the kernel image (you can learn more about this in this Raspberry Pi documentation page).

Unlocking the device at boot

At this point all is set, and everything should work fine. We reboot the Rasberry Pi OS and wait few seconds for it to come back online; than, from our client machine we login via SSH:

$ ssh root@192.168.0.39 -p 2222

If this is the first time we connect, the system fingerprint will be displayed, and we will be prompted to confirm we want to connect to it:

The authenticity of host '[192.168.0.39]:2222 ([192.168.0.39]:2222)' can't be established.
ED25519 key fingerprint is SHA256:TjCUX3ZG0blPkuRwyCCKM9Dv2JPtnHUivoC9nVP78XI.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes

Once we confirm, we are notified the server has been added to the list of known hosts, than we are prompted to provide the password to unlock the device LUKS encrypted device we specified in the crypttab file:

Please unlock disk luks-200ce9d7-72de-443f-b669-e50d0a23f01a:



Since the Raspberry Pi has limited CPU power, it could take a while to unlock the LUKS device, especially if it was formatted on a more powerful machine. If the process takes too much we may receive a timeout error. If we provide the right passphrase the device will be unlocked, the connection will be closed, and the boot process will continue.

cryptsetup: luks-200ce9d7-72de-443f-b669-e50d0a23f01a set up successfully
Connection to 192.168.0.39 closed.

Conclusions

In this article we saw how to use dropbear-initramfs to get SSH access at an early boot stage, when the initramfs is loaded, in order to unlock a LUKS encrypted device on a headless Raspberry Pi. The instructions in this tutorial, with some little modifications, may be applied to other Debian-based systems.



Comments and Discussions
Linux Forum