Mounting LUKS Encrypted Drive on Rasperry Pi on Boot
LUKS provides support for encrypted drives on Linux and we can provide password for decryption during the boot sequence over SSH with dropbear so that encrypted drive can mount on startup. I had an itch to set up an encrypted drive on a Raspberry Pi to give the data some protection in case the Raspberry Pi went missing. Given I was upgrading a Raspberry Pi I was using as a small media server, I thought it would be a good time to try out LUKS and dropbear SSH.
Create the partition
Drop into a sudo interactive shell which I'll stay in throughout this article.
sudo -i
Let's create this partition with parted
, for example I used the last 10% of my
240 SSD drive for the LUKS partition.
parted /dev/sda mkpart primary 90% 100%
LUKS and cryptsetup
The Linux Unified Key Setup (LUKS) standards defines for disk encryption.
cryptsetup provides an
implementation to conveniently set up disk encryption. We'll need to install
cryptsetup
to create our LUKS partition.
apt install -y cryptsetup
Format the partition we have just created providing a password for the device.
cryptsetup --cipher xchacha20,aes-adiantum-plain64 \
luksFormat /dev/sda3
Open the LUKS device and provide the password to unlock. This sets up a mapping for the name given, e.g. this command creates a mapping of /dev/mapper/crypt with the name crypt. Mappings a virtual device blocks managed by the Linux device mapper framework.
cryptsetup luksOpen /dev/sda3 crypt
Make the file system on this LUKS device.
mkfs.ext4 /dev/mapper/crypt
Mount the file system
mkdir -p /data/
mount /dev/mapper/crypt /data/
We now have an encrypted drive mounted at /data. We've mounted it manually for now and will cover how to mount it during the boot sequence later in this article.
Why Adiantum cipher?
When we format the LUKS partition we need to choose an appropriate cipher. The default cipher is aes-xts-plain64. Raspberry Pi 4 devices do not provide AES acceleration. LUKS on Raspberry Pi suggests that Adiantum cipher runs faster and Raspberry Pi Encrypted Boot with SSH indicates that aes-xts-plain64 is only fast on a Raspberry Pi 5 due to its hardware AES acceleration
We can benchmark the ciphers with the cryptsetup benchmark
command.
cryptsetup benchmark -c xchacha12,aes-adiantum-plain64
cryptsetup benchmark -c xchacha20,aes-adiantum-plain64
cryptsetup benchmark -c aes-xts-plain64
Algorithm | Key | Encryption | Decryption |
---|---|---|---|
xchacha12,aes-adiantum | 256b | 198.4 MiB/s | 213.2 MiB/s |
xchacha20,aes-adiantum | 256b | 170.5 MiB/s | 179.3 MiB/s |
aes-xts | 256b | 106.4 MiB/s | 108.1 MiB/s |
This confirms that the Adiantum cipher runs about 80% faster for my setup. Read Fast cipher without needing hardware support (like ChaCha20) for disk encryption for a background on ChaCha20 vs ChaCha12 vs AES for disk encryption. ChaCha12 may be more than adequate for my needs, but ChaCha20 is more future proofed.
IO performance of encrypted drive
We can also do a quick read / write performance check of a file system with
dd if=/dev/zero of=./speed-test.dat bs=20M count=50 oflag=direct ; \
dd if=./speed-test.dat of=/dev/zero bs=20M count=50 oflag=dsync
For my SSD I see:
Type | Read | Write |
---|---|---|
unencrypted | 380 MB/s | 229 MB/s |
encrypted (Adiantum) | 146 MB/s | 172 MB/s |
encrypted (AES) | 127 MB/s | 154 MB/s |
We can see there is a performance penalty on the encrypted drive, which is one of the reasons I didn't want to encrypt the whole drive. At some point I'll benchmark this on a Raspberry Pi 5 to see how the AES acceleration fairs. On a Raspberry Pi 5 full disk encryption may have less of a penalty.
Re-encryption
If at any time you want to re-encrypt a device if, perhaps to apply an alternative
encryption strategy, you can do so with the cryptsetup reencrypt
command.
crypsetup reencrypt --hash sha256 /dev/sda4
Have patience, since this can take some time. For my drive it took 20 minutes to re-encrypt a 10GB partition.
Unlocking an encrypted drive
I would like to mount the encrypted drive on restart. To open the LUKS partition we need to supply the appropriate secret. We have a few options for this, such as providing a key file on removable media or with Trusted Platform Module (TPM) such as the LetsTrust TPM for Raspberry Pi. Or perhaps clevis client to unlock from key provided by tang server.
For my situation, this Raspberry Pi is only managed by me and a USP powers it. This means it rarely has unexpected restarts and I'm on hand to restart when I need it. I can provide the password during the boot process when needed, although I do want to do this remotely from my local machine so I can script it up and trigger it with low effort.
dropbear initramfs
This is where dropbear initramfs comes in.
initramfs is a root file system that loads temporarily into memory during the boot sequence of the Linux kernal. It can perform operations before the real root file system mounts. We can use the initramfs to open up the LUKS partition on system startup.
dropbear provides a lightweight SSH server that can run during the initramfs sequence that allows us to open the LUKS partition at boot time.
Unlocking drive on start up over SSH
Install dropbear-initramfs.
apt install -y dropbear-initramfs
Update /etc/crypttab to define how to open the LUKS partition setting the
appropriate UUID for your LUKS partition. We can get the UUID from the blkid
command.
LUKS_UUID=$(blkid | grep LUKS | sed 's/.* UUID="\([^"]*\)".*/\1/')
cat >> /etc/crypttab << EOF
crypt UUID=${LUKS_UUID} none luks,initramfs
EOF
Update /etc/fstab to define the mount point for the mapping device from the LUKS partition
cat >> /etc/fstab << EOF
/dev/mapper/crypt /data ext4 defaults,noatime,nofail 0 1
EOF
Configure the dropbear SSH service that will run during the initramfs sequence.
You can configure SSH to listen on a specific port, e.g. 2222, so that there is
no confusion (like known hosts fingerprints in ~/.ssh/known_hosts
) between SSH
during initramfs and SSH to the fully started machine.
sed -i \
'/DROPBEAR_OPTIONS/c\DROPBEAR_OPTIONS="-jks -I 180 -p 2222 -c cryptroot-unlock"' \
/etc/dropbear/initramfs/dropbear.conf
Copy SSH authorized_keys file from the local admin user so that the same key used for the admin user SSH login is authorised for use during the initramfs sequence.
cp /home/admin/.ssh/authorized_keys /etc/dropbear/initramfs/
Update the initramfs image.
update-initramfs -u
Reboot
reboot now
When the system reboots the system will wait in the initramfs boot step until you SSH in to provide the password to unlock the LUKS device. We've set up dropbear to listen on port 2222, so let's SSH now into port 2222 with the root user and set the password.
ssh -p 2222 root@angus
Once you enter the password for the encrypted drive, the boot sequence will continue, the SSH connection will drop and once the machine has started up you can connect again with
ssh admin@angus
The encrypted drive should now have mounted.
$ df -k
Filesystem 1K-blocks Used Available Use% Mounted on
...
/dev/mapper/crypt 22868764 28 21681736 1% /data
...
Thanks
This article has covered how to set up an encrypted drive with LUKS and gives a way to connect remotely to decrypt a drive before the boot sequence completes. It's a little simpler to set up than encrypting the root partition and for my needs, more than adequate.
Many thanks to the following articles for guiding me on this area.