We’ve looked at using LUKS on the Ubuntu Pi desktop images before but it was a rather painful process primarily as it involved shrinking the root partition. This in turn meant that a separate machine (or at the very least a Pi booting from something other than its SD card) was required to perform the changes.
Can we do better? In particular, can we reduce the requirements to just a single machine (the target Raspberry Pi) with a single storage medium? Thanks to a relatively minor change in the just-released Ubuntu Lunar (23.04) Pi desktop image, I think we can!
When you wanna go do it
You’ll need the following for any scenario:
- a Raspberry Pi 4 or 400
- a micro-SD card (or USB-attached boot drive)
- a monitor
- a keyboard and a mouse
If you’re trying to do this on a single machine (not flashing your storage device on a separate machine), you’ll also need:
- a relatively recent boot firmware
- an Ethernet connection
Newly purchased Pis (as of 2023) should all have sufficiently up to date firmwares. Older Pis may require an EEPROM update which can be accomplished under Ubuntu (or RaspiOS) by running sudo rpi-eeprom-update -a and rebooting if an update is shown as available.
Hit me with those laser beams
Start up your Raspberry Pi. The monitor should show the red and white Raspberry Pi bootloader screen, with the prompt “Press and hold <SHIFT> key to stop boot and start net install”. Follow this instruction and it should change to “If not done so already, insert ethernet cable” (this capability only works over Ethernet, not WiFi as the bootloader can only configure the former).
After a short download, you should find yourself at a full-screen version of the rpi-imager. From here you can select Ubuntu as you normally would in the desktop version of the software:
- Click “Choose OS”
- Select “Other general-purpose OS”
- Select “Ubuntu”
- Select “Ubuntu Desktop 23.04 (64-bit)”
- Back at the main screen, click “Choose Storage” and pick your boot medium (which should be the only drive connected to the Pi at this point)
- Click “Write”
The utility should prompt to ensure you want to overwrite everything and anything on the storage device and, once confirmed, you should find it writing to the storage medium.
Do not be alarmed if there is an extremely long pause in the writing process. The Ubuntu images are heavily compressed, and the “slack space” baked into the image (which may be excessive) compresses extremely well. This can lead to a potentially long pause in the progress bar while a few bytes in the compressed image expand into gigabytes of written data.
Make making it your intention
Once the OS is written to the boot medium (and verified), the Pi should reboot into Ubuntu Desktop. You’ll need to run through the initial setup wizard, configuring your locale and user details.
After the initial setup wizard, login to your new user. We now need to take a series of steps which may seem premature and in some cases a bit odd. Start a terminal and perform the following:
$ sudo -i # apt install cryptsetup-initramfs # echo "rootfs $(findmnt -n -o SOURCE /) none luks,discard" >> /etc/crypttab # sed -i -e 's,^LABEL=writable,/dev/mapper/rootfs,' /etc/fstab # sed -i -e 's,LABEL=writable,/dev/mapper/rootfs,' /boot/firmware/cmdline.txt # reboot
In order, these commands:
- Switch to the root user (everything we’re going to do requires root access and I can’t be bothered re-typing sudo).
- Re-install cryptsetup. I say “re-” because this package is actually part of the base image, but the initial setup decides it isn’t required and removes it at the end of the setup. Doh!
- Create the crypttab entry for the rootfs.
- Re-write the source of the root mount in fstab.
- … and the same in the kernel command line.
- Reboot the machine.
If you want to double check things, assuming your boot device is an SD card (/dev/mmcblk0) your crypttab, fstab and cmdline.txt files should look like this:
root@miss-piggy:~# cat /etc/crypttab # <target name> <source device> <key file> <options> rootfs /dev/mmcblk0p2 none luks,discard root@miss-piggy:~# cat /etc/fstab /dev/mapper/rootfs / ext4 discard 0 1 LABEL=system-boot /boot/firmware vfat defaults 0 1 root@miss-piggy:~# cat /boot/firmware/cmdline.txt zswap.enabled=1 zswap.zpool=z3fold zswap.compressor=zstd dwc_otg.lpm_enable=0 console=tty1 root=/dev/mapper/rootfs rootfstype=ext4 rootwait fixrtc quiet splash
Hit me, hit me!
At this point you may notice that the boot seems to be taking rather a long time. In fact, it’s going to fail because the rootfs device we told the kernel to go looking for doesn’t exist yet. But that’s okay! Be patient and let it fail; the initramfs still gets loaded and it’s got all the tools we need to create it.
Once you find yourself at a command prompt (with a notice complaining that it couldn’t mount the root file-system), do the following:
(initramfs) rootdev=$(readlink -f /dev/disk/by-label/writable) (initramfs) cryptsetup reencrypt --encrypt --reduce-device-size 16M --cipher xchacha12,aes-adiantum-plain64 $rootdev (initramfs) cryptsetup open $rootdev rootfs (initramfs) exit
- Create the rootfs device. This will prompt you to enter “YES” (for confirmation you really want to do this), and for the password to unlock the encryption key for the device (twice); don’t forget this!.
- Go make coffee; or twiddle your thumbs for an excessively long period of time while it encrypts the entire device, including all the empty space. On the plus side, after a minute it should give you a reasonably accurate estimate of how long it’s going to take to encrypt the device, so you can set a timer and come back when it’s done.
- Open the newly created rootfs device (this will prompt you once more for the password) and exit to continue the boot.
Once you’re logged into the desktop once more, you have one final task. Re-generate the initramfs now that the rootfs device exists:
$ sudo update-initramfs -u
Done! At this point all future boots should prompt you for the password to unlock the encrypted root file-system.
Obviously in an ideal world, this could all be accomplished from the installer, but there’s a slight wrinkle in that with the lunar release. The first time setup application on the Pi desktop images is oem-config which is derived from the venerable ubiquity installer. As you may have noticed in the lunar release notes the installer is being replaced by a new one based on subiquity.
However, this only applies to those platforms which need the “full fat” installer, i.e. the PC where you boot off some medium and then install to another (the internal drive). It doesn’t apply to Ubuntu’s pre-installed desktop images (like the Pi ones) yet. There seemed little point in pouring effort into adding this to ubiquity this cycle, only to see it thrown out during the next cycle when the subiquity based installer comes to replace oem-config.
Hopefully in a future cycle we can integrate all this and have a slightly friendlier experience, but for now at least it’s achievable without requiring a separate machine.