Raspberry Pi LVM on LUKS: Difference between revisions

From Alpine Linux
(Clarify the "Boot the Installer" instructions)
(Rephrase the introductory lines.)
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
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.
This article complements the existing installation instructions for Raspberry Pi, providing the needed changes that enable booting with an encrypted disk.


==Prepare the Installation Media==
==Prepare the Installation Media==
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. A tool such as <code>lsblk</code> gives you an overview of all disks available. In this example, the new disk becomes ''/dev/sdb''.
Plug in the disk where Alpine will be installed. <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 (e.g. ''/dev/sdb1'').
# Create a larger Linux partition (e.g. ''/dev/sdb2'') that will be LUKS-encrypted.


Install the necessary packages:
Install the necessary packages:
{{cmd|apk add cryptsetup lvm2}}
{{cmd|apk add cryptsetup lvm2 mkinitfs}}


Encrypt the Linux partition with one of the following:
Encrypt the Linux partition with one of the following:
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>, where "alpine" is a name of choice.


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==
==Boot Configuration==
''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 have installed the system to the target disk. Now we just need to verify a few things so it's ready to boot.
 
Here's a list of files to check:
* ''/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>
* ''/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>).
 
==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.
 
This assumes you've already booted a passphrase-encrypted Alpine installation, but you can include this as part of the installation procedure.
 
===Create the keyfile===
 
A keyfile can be created with ''dd'':
{{cmd|dd if{{=}}/dev/urandom of{{=}}/crypto_keyfile.bin bs{{=}}1M count{{=}}1}}
 
Make it read-only, owner only:
{{cmd|chmod 400 /crypto_keyfile.bin}}
 
Add the keyfile to the LUKS header:
{{cmd|cryptsetup luksAddKey /dev/sdb2 /crypto_keyfile.bin}}


===Prepare the Initramfs===
:1. Edit ''/mnt/etc/mkinitfs/mkinitfs.conf'' and add the features <code>lvm</code> and <code>cryptsetup</code>, if missing.
:2. Edit ''/mnt/boot/cmdline.txt'', and ensure that <code>root=</code> points to the respective LVM volume (e.g. ''/dev/alpine/root'').


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'').
::In the same file, add <code>cryptroot=UUID=</code> pointing to the LUKS device (e.g. ''/dev/sdb2'', but as UUID), and also <code>cryptdm=</code> set to a name of choice (e.g. alpine).
::These options are documented [[Setting_up_encrypted_volumes_with_LUKS#mkinitfs_and_LUKS|here]] and [https://manned.org/man/alpine-3.23/mkinitfs-bootparam.7 here].


The default path is <code>/crypto_keyfile.bin</code>, but you can change it by editing <code>/etc/mkinitfs/features.d/cryptkey.files</code>.
:3. Edit ''/mnt/etc/fstab'' and verify that all LVM volumes and the ''/boot'' partition are listed there.


The path to the keyfile must also be passed as a kernel command-line option in <code>/boot/cmdline.txt</code>:
::Add a line for the swap volume too. There's an example [[LVM_on_LUKS#Installing_Alpine_Linux|here]].
<pre>
::If your disk is an ordinary flash stick or SD card, you might want to replace all instances of <code>relatime</code> with <code>noatime</code>.
cryptkey=/crypto_keyfile.bin
</pre>


Enable the necessary features in <code>/etc/mkinitfs/mkinitfs.conf</code>:
:4. [[Initramfs_init#Usage|Regenerate the initramfs]]. Remember to point it to the ''/mnt'' path.
<pre>
features="... cryptsetup cryptkey"
</pre>


Regenerate the [[Initramfs_init|initramfs]]:
Finally, a friendly reminder: save a backup of that LUKS header. See [https://manned.org/man/cryptsetup-luksHeaderBackup cryptsetup-luksHeaderBackup(8)].
<pre>
mkinitfs -c /etc/mkinitfs/mkinitfs.conf -b /
</pre>


==See also==
==See also==


* [[Raspberry Pi|Raspberry Pi - Installation]] ''(diskless-mode installation)''
* [[Raspberry Pi|Raspberry Pi]]
* [[Classic install or sys mode on Raspberry Pi|Raspberry Pi - Sys mode install]] ''(sys-mode installation)''
* [[Setting_up_encrypted_volumes_with_LUKS|LUKS-encrypted volume setup]]
* [[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 that the Pi uses a different bootloader)''
* [[Initramfs_init|Initramfs]]


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

Latest revision as of 21:27, 2 May 2026

This article complements the existing installation instructions for Raspberry Pi, providing the needed changes that enable booting with an encrypted disk.

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 where Alpine will be installed. 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 (e.g. /dev/sdb1).
  3. Create a larger Linux partition (e.g. /dev/sdb2) that will be LUKS-encrypted.

Install the necessary packages:

apk add cryptsetup lvm2 mkinitfs

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, where "alpine" is a name of choice.

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

Boot Configuration

setup-disk should have installed the system to the target disk. Now we just need to verify a few things so it's ready to boot.

1. Edit /mnt/etc/mkinitfs/mkinitfs.conf and add the features lvm and cryptsetup, if missing.
2. Edit /mnt/boot/cmdline.txt, and ensure that root= points to the respective LVM volume (e.g. /dev/alpine/root).
In the same file, add cryptroot=UUID= pointing to the LUKS device (e.g. /dev/sdb2, but as UUID), and also cryptdm= set to a name of choice (e.g. alpine).
These options are documented here and here.
3. Edit /mnt/etc/fstab and verify that all LVM volumes and the /boot partition are listed there.
Add a line for the swap volume too. There's an example here.
If your disk is an ordinary flash stick or SD card, you might want to replace all instances of relatime with noatime.
4. Regenerate the initramfs. Remember to point it to the /mnt path.

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

See also