Raspberry Pi LVM on LUKS: Difference between revisions

From Alpine Linux
m (Remove obsolete link in "See also")
(Rewrite some sections to improve clarity. Sorry for the huge changeset.)
Line 5: Line 5:


==Boot the Installer==
==Boot the Installer==
Insert the installation disk into the pi and turn it on. To make sure it boots the right device, unplug any other storage media.
Insert the installation disk into the pi and turn it on. To make sure it will boot the right device, unplug any other storage media.


Once Alpine is initialized, log in and perform a "diskless installation" with <code>setup-alpine</code>. Next, we will setup the disk manually.
Once Alpine is initialized, log in and perform a "diskless installation" with <code>setup-alpine</code>. Next, we will setup the disk manually.


==Disk Setup==
==Disk Setup==
Plug in the disk to be used as the encrypted root. <code>fdisk -l</code> should give you an overview of all available disks. In this example, the new disk becomes ''/dev/sdb''.
Plug in the disk to be used as the encrypted root. <code>fdisk -l</code> and <code>blkid</code> should give you an overview of all available disks. 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. Important: if you plan to [[Raspberry_Pi_LVM_on_LUKS#Optional:_Decrypt_with_a_Keyfile|decrypt with a keydisk]], create the ''/boot'' partition on the keydisk instead.
# Initialize the disk with a new empty DOS partition table.
# Create a bootable FAT32 partition ([[Raspberry_Pi#Manual_method|as described here]]) that will later be mounted as the (unencrypted) ''/boot'' filesystem. Important: if you plan to [[Raspberry_Pi_LVM_on_LUKS#Optional:_Decrypt_with_a_Keyfile|decrypt with a keydisk]], create the ''/boot'' partition on that disk instead.
# Create a larger Linux partition (e.g. ''/dev/sdb2'') that will be LUKS-encrypted.


Install the necessary packages:
Install the necessary packages:
Line 21: Line 23:
{{cmd|cryptsetup luksFormat -c xchacha12,aes-adiantum-plain64 /dev/sdb2    # Raspberry Pi 4 and older}}
{{cmd|cryptsetup luksFormat -c xchacha12,aes-adiantum-plain64 /dev/sdb2    # Raspberry Pi 4 and older}}


At this point you can follow the [[LVM_on_LUKS#Creating_the_Logical_Volumes_and_File_Systems|LVM on LUKS page]] to create and format the LVM volumes.
Then unlock the disk with <code>cryptsetup open /dev/sdb2 alpine</code>


Mount the new root partition at ''/mnt'', the boot partition at ''/mnt/boot'' (after creating the directory), then run ''setup-disk'' like this:
At this point you may follow the [[LVM_on_LUKS#Creating_the_Logical_Volumes_and_File_Systems|LVM on LUKS page]] to create and format the LVM volumes.
 
Mount the root volume at ''/mnt'', and the boot partition at ''/mnt/boot''; then run ''setup-disk'' like this:
{{cmd|setup-disk -m sys /mnt}}
{{cmd|setup-disk -m sys /mnt}}


==Verify the Installation==
==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.
''setup-disk'' should setup most things for us, but it's a good idea to inspect the results before you reboot.


Here's a list of files to check:
Here's a list of files to check:
* ''/etc/mkinitfs/mkinitfs.conf'' should have the features <code>lvm</code> and <code>cryptsetup</code>.
* ''/mnt/etc/mkinitfs/mkinitfs.conf'' should have the features <code>lvm</code> and <code>cryptsetup</code>.
* ''/boot/cmdline.txt'' should contain the following options: <code>root=/dev/vg0/root cryptroot=UUID=<encrypted_disk_uuid> cryptdm=root</code>
* ''/mnt/boot/cmdline.txt'' should contain the following options: <code>root=/dev/vg0/root cryptroot=UUID=<LUKS_DEVICE_UUID> cryptdm=alpine</code>
* ''/etc/fstab'' should have a line for <code>/dev/vg0/root</code> (and any other LVM volumes), and <code>/boot</code> (by UUID).
* ''/mnt/etc/fstab'' should have a line for <code>/dev/vg0/root</code> (and any other LVM volumes), and <code>/boot</code> (by UUID).


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


==Optional: Decrypt with a Keyfile==
==Optional: 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, ''mkinitfs'' does not yet support decryption keys on external devices, but there is a [https://gitlab.alpinelinux.org/alpine/mkinitfs/-/merge_requests/108 pending merge request] to implement it, as well as a decent workaround: move the entire ''/boot'' partition onto a separate device.
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, ''mkinitfs'' does not yet provide a way to specify the decryption keyfile on an external device, but there is a [https://gitlab.alpinelinux.org/alpine/mkinitfs/-/merge_requests/108 pending merge request] to add the functionality, as well as a workaround: '''move the entire ''/boot'' filesystem onto another device.''' That is what we will be doing.


This assumes you've already booted a passphrase-encrypted Alpine installation, but you can include this as part of the installation procedure.
This assumes you've already booted a passphrase-encrypted Alpine installation, but with some adjustments you should be able to include this as part of the installation procedure.


===Create the keyfile===
===Create the keyfile===


A keyfile can be created with ''dd'':
Create an empty file and fix its permissions:
{{cmd|dd if{{=}}/dev/urandom of{{=}}/crypto_keyfile.bin bs{{=}}1M count{{=}}1}}
{{cmd|touch /crypto_keyfile.bin}}
{{cmd|chmod 600 /crypto_keyfile.bin}}


Make it read-only, owner only:
Use ''dd'' to fill it with random data:
{{cmd|chmod 400 /crypto_keyfile.bin}}
{{cmd|dd if{{=}}/dev/urandom of{{=}}/crypto_keyfile.bin bs{{=}}512 count{{=}}1}}


Add the keyfile to the LUKS header:
Add the keyfile to the LUKS header:
Line 54: Line 61:
===Prepare the Initramfs===
===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 root disk decryption takes place in a temporary environment named [[Initramfs_init|initramfs]]. Once we generate it, the keyfile we created earlier will be copied into the initram filesystem, which sits inside the ''/boot'' disk. Because this disk is separated from the rest of the system, it can function as a decryption key — the system won't boot without it.


The default path is <code>/crypto_keyfile.bin</code>, but you can change it by editing <code>/etc/mkinitfs/features.d/cryptkey.files</code>.
The default path for the keyfile is <code>/crypto_keyfile.bin</code>, but you can change it by editing <code>/etc/mkinitfs/features.d/cryptkey.files</code>.


The path to the keyfile must also be passed as a kernel command-line option in <code>/boot/cmdline.txt</code>:
It must also be passed as a kernel command-line option in <code>/boot/cmdline.txt</code>:
<pre>
<pre>
cryptkey=/crypto_keyfile.bin
cryptkey=/crypto_keyfile.bin
Line 68: Line 75:
</pre>
</pre>


Regenerate the [[Initramfs_init|initramfs]]:
Regenerate the [[Initramfs_init#Usage|initramfs]]:
<pre>
<pre>
mkinitfs -c /etc/mkinitfs/mkinitfs.conf -b /
mkinitfs -c /etc/mkinitfs/mkinitfs.conf -b /
Line 76: Line 83:


* [[Raspberry Pi|Raspberry Pi]]
* [[Raspberry Pi|Raspberry Pi]]
* [[LVM_on_LUKS|LVM on LUKS]] ''(encryption and LVM, but beware not everything applies to the pi)''
* [[LVM_on_LUKS|LVM on LUKS]] ''(encryption and LVM, but beware not everything applies to the Pi)''


[[Category:Storage]]
[[Category:Storage]]
[[Category:Security]]
[[Category:Security]]
[[Category:Raspberry]]
[[Category:Raspberry]]

Revision as of 04:04, 2 May 2026

Installing Alpine on an encrypted root 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

Write the downloaded image or tarball to a disk. In this example, this bootable disk (referred to as /dev/sda) will be used as a read-only installation media. The target root disk is referred to as /dev/sdb.

Boot the Installer

Insert the installation disk into the pi and turn it on. To make sure it will boot the right device, unplug any other storage media.

Once Alpine is initialized, log in and perform a "diskless installation" with setup-alpine. Next, we will setup the disk manually.

Disk Setup

Plug in the disk to be used as the encrypted root. fdisk -l and blkid should give you an overview of all available disks. In this example, the new disk becomes /dev/sdb.

  1. Initialize the disk with a new empty DOS partition table.
  2. Create a bootable FAT32 partition (as described here) that will later be mounted as the (unencrypted) /boot filesystem. Important: if you plan to decrypt with a keydisk, create the /boot partition on that disk instead.
  3. Create a larger Linux partition (e.g. /dev/sdb2) that will be LUKS-encrypted.

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

Then unlock the disk with cryptsetup open /dev/sdb2 alpine

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

Mount the root volume at /mnt, and the boot partition at /mnt/boot; 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 the results before you reboot.

Here's a list of files to check:

  • /mnt/etc/mkinitfs/mkinitfs.conf should have the features lvm and cryptsetup.
  • /mnt/boot/cmdline.txt should contain the following options: root=/dev/vg0/root cryptroot=UUID=<LUKS_DEVICE_UUID> cryptdm=alpine
  • /mnt/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)).

Optional: 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, mkinitfs does not yet provide a way to specify the decryption keyfile on an external device, but there is a pending merge request to add the functionality, as well as a workaround: move the entire /boot filesystem onto another device. That is what we will be doing.

This assumes you've already booted a passphrase-encrypted Alpine installation, but with some adjustments you should be able to include this as part of the installation procedure.

Create the keyfile

Create an empty file and fix its permissions:

touch /crypto_keyfile.bin

chmod 600 /crypto_keyfile.bin

Use dd to fill it with random data:

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

Add the keyfile to the LUKS header:

cryptsetup luksAddKey /dev/sdb2 /crypto_keyfile.bin

Prepare the Initramfs

The root disk decryption takes place in a temporary environment named initramfs. Once we generate it, the keyfile we created earlier will be copied into the initram filesystem, which sits inside the /boot disk. Because this disk is separated from the rest of the system, it can function as a decryption key — the system won't boot without it.

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

It must also be passed as a kernel command-line option in /boot/cmdline.txt:

cryptkey=/crypto_keyfile.bin

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

features="... cryptsetup cryptkey"

Regenerate the initramfs:

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

See also