Raspberry Pi LVM on LUKS

From Alpine Linux
Revision as of 21:00, 24 May 2024 by Harpia (talk | contribs) (Remove unnecessary "run as root" note)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Installing Alpine on an encrypted root

This article complements the existing installation instructions for Raspberry Pi, providing only the needed changes that enable booting from an encrypted media. Use it only as a reference, not as a complete walk-through for installation.

Prepare the Installation Media

Create a bootable disk. Basically, you'll create and format a FAT32 partition in an MBR partition table, set the boot flag on it, mount it and extract the downloaded tarball into it. You may skip those bootloader steps, because the tarball already has everything you need to boot.

As a preference of the author, this bootable disk (referred to as /dev/sda) is just an installer, and will not be changed during the installation. The target root disk is referred to as /dev/sdb.

Boot the Installer

Insert the bootable disk we created earlier into the pi, and boot from it. Login and perform a diskless installation with setup-alpine. Next, we'll setup the disk.

Disk setup

Plug in the disk to be used as the encrypted root. A tool such as lsblk gives you an overview of all disks available. In this example, the new disk becomes /dev/sdb.

Create a bootable FAT32 partition (/dev/sdb1) that will hold the unencrypted /boot, and then a larger Linux partition (/dev/sdb2) that will hold the LVM physical volume.

Install the necessary packages:

apk add cryptsetup lvm2

Encrypt the Linux partition with one of the following:

cryptsetup luksFormat /dev/sdb2 # Raspberry Pi 5

cryptsetup luksFormat -c xchacha12,aes-adiantum-plain64 /dev/sdb2 # Raspberry Pi 4 and older

At this point you can follow the LVM on LUKS page to create and format the LVM volumes.

Mount the new root partition at /mnt, the boot partition at /mnt/boot (after creating the directory), then run setup-disk like this:

setup-disk -m sys /mnt

Verify the Installation

setup-disk should setup most things for us, but it's a good idea to inspect some critical files to avoid ending up with a system that won't boot.

Here's a list of files to check:

  • /etc/mkinitfs/mkinitfs.conf should have the features lvm and cryptsetup.
  • /boot/cmdline.txt should contain the following options: root=/dev/vg0/root cryptroot=UUID=<encrypted_disk_uuid> cryptdm=root
  • /etc/fstab should have a line for /dev/vg0/root (and any other LVM volumes), and /boot (by UUID).

Finally, a friendly reminder: save a backup of that LUKS header (see cryptsetup-luksHeaderBackup(8)).

Decrypt with a Keyfile

The "keydisk" - a storage device used as a decryption key — is a convenient method to enable full-disk encryption, especially for a headless server. Unfortunately, this functionality is not yet supported, but there is a pending merge request to implement it.

For now, we can achieve the same by moving the entire /boot partition to a separate device.

This assumes you've already booted a passphrase-encrypted Alpine installation, but you can include this as part of the installation procedure, and even use a keyfile alone instead of a passphrase.

Create the keyfile

A keyfile can be created with dd:

dd if=/dev/urandom of=/crypto_keyfile.bin bs=1M count=1

Make it read-only, owner only:

chmod 400 /crypto_keyfile.bin

Add the keyfile to the LUKS header:

cryptsetup luksAddKey /dev/sdb2 /crypto_keyfile.bin

Prepare the Initramfs

The root disk decryption takes place in the temporary environment called initramfs. mkinitfs will copy your keyfile into the initramfs filesystem, and place it in the exact same path it was copied from (e.g. /boot/cryptkey, /var/root.key).

The default path is /crypto_keyfile.bin, but you can change it by editing /etc/mkinitfs/features.d/cryptkey.files.

The path to the keyfile must also be passed as a kernel command-line option in /boot/cmdline.txt:


Enable the necessary features in /etc/mkinitfs/mkinitfs.conf:

features="... cryptsetup cryptkey"

Regenerate the initramfs:

mkinitfs -c /etc/mkinitfs/mkinitfs.conf -b /

See Also