Initramfs with systemd & LUKS
TL;DR
[me@mycomputer]# cat /etc/sbupdate.conf | grep "^CMDLINE_DEFAULT"
CMDLINE_DEFAULT="rd.luks.uuid=c1f995f5-a8f7-47f0-b085-6d3a159e1874 rd.luks.allow-discards resume=UUID=51384ac6-f197-41d9-b8c8-c9607d7e01c8 rd.udev.log-priority=3 nvme.noacpi=1 quiet splash root=UUID=a645810c-ef87-4a9a-9239-afdeaf292e6e rw"
[me@mycomputer]# cat /etc/mkinitcpio.conf | grep "^HOOKS"
HOOKS=(systemd keyboard autodetect sd-vconsole modconf block sd-encrypt lvm2 filesystems fsck)
My old boot process looks like this:
- UEFI (with secure boot on)
- systemd-boot
- unified kernel.efi (initramfs + kernel params + kernel all rolled into one efi and signed)
- initramfs (busybox)
- encrypt hook: detects that a password is needed -> prompt for password
- Unlock LUKS partition
- LVM hook detects the LUKS partition and loads the logical volume groups/volumes
- The root partition is loaded and control gets passed off to the real kernel
Which was set up via the following configs:
[me@mycomputer]# parted --list
Model: SHPP41-2000GM (nvme)
Disk /dev/nvme0n1: 2000GB
Sector size (logical/physical): 4096B/4096B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 1074MB 1073MB fat32 boot boot, esp
2 1074MB 2000GB 1999GB luksy
[me@mycomputer]# /dev/mapper/luksyvg-swap: UUID="51384ac6-f197-41d9-b8c8-c9607d7e01c8" TYPE="swap"
/dev/nvme0n1p1: UUID="00BA-48B3" BLOCK_SIZE="4096" TYPE="vfat" PARTLABEL="boot" PARTUUID="b6ed23fd-986e-4976-a499-410fbeff438e"
/dev/nvme0n1p2: UUID="c1f995f5-a8f7-47f0-b085-6d3a159e1874" TYPE="crypto_LUKS" PARTLABEL="luksy" PARTUUID="62278a82-aa36-4ead-afd7-86eebd1d8ba8"
/dev/mapper/luksyvg-root: UUID="a645810c-ef87-4a9a-9239-afdeaf292e6e" BLOCK_SIZE="4096" TYPE="ext4"
/dev/mapper/luks-c1f995f5-a8f7-47f0-b085-6d3a159e1874: UUID="JtyrtA-F0ee-roqi-tVdN-KRly-l4Oo-kHwHfo" TYPE="LVM2_member"
/dev/mapper/luksyvg-home: LABEL="home" UUID="394fa3e0-4539-43ca-a7ca-66158c2156f8" UUID_SUB="cf062892-876f-448e-b030-3d47dc5a7419" BLOCK_SIZE="4096" TYPE="btrfs"
[me@mycomputer]# cat /etc/sbupdate.conf | grep "^CMDLINE_DEFAULT"
CMDLINE_DEFAULT="cryptdevice=UUID=c1f995f5-a8f7-47f0-b085-6d3a159e1874:luksy root=/dev/luksyvg/root rw resume=UUID=51384ac6-f197-41d9-b8c8-c9607d7e01c8 quiet splash rd.udev.log-priority=3 nvme.noacpi=1"
[me@mycomputer]# cat /etc/mkinitcpio.conf | grep "^HOOKS"
HOOKS=(base udev autodetect keyboard keymap modconf block encrypt lvm2 filesystems resume fsck)
The main thing here is the addition of cryptdevice
for the command line flags which triggers the code to unlock /dev/nvme0n1p2
I wanted to switch steps 4-8 to use systemd, rather than busybox. Arch has a decent amount of info about configuring mkinitcpio.conf, however it wasn’t clear to me exactly what to do for LUKS encryption. Should I mess with /etc/crypttab.initramfs? What should the kernel options be? After a lot of searching, I eventually figured out a setup for my system from the combination of dm_crypt wiki docs, dracut man pages, and a forum post (self-answered at that) about setting up resume
Once you know what to do, it’s pretty easy, but the key is knowing what to do :). Let’s dig in:
Modify mkinitcpio.conf to switch to systemd
This is pretty straightforward. Just follow the wiki and replace hooks with their corresponding systemd ones. My new HOOKS section looks like this:
HOOKS=(systemd keyboard autodetect sd-vconsole modconf block sd-encrypt lvm2 filesystems fsck)
Figure out your commandline parameters
This is the least-documented part. First, you need to tell systemd to unlock your file. You’ll need the UUID of the partition (e.g. /dev/nvme0n1p2 in my case), and then just add rd.luks.uuid=c1f995f5-a8f7-47f0-b085-6d3a159e1874
matching the UUID to your partition.
Next, especially when using LVM, I found it much simpler to just use the UUID for the root parameter to boot from. When booted into your current system, just use blkid
to figure out the UUID of your /root LVM partition, then set root=UUID=a645810c-ef87-4a9a-9239-afdeaf292e6e rw
as the corresponding command line argument (changing the UUID to match) Obviously this is going to be different than the UUID you have in rd.luks.uuid since that refers to your encrypted partition, and this value would be the sub-partition once you’ve unlocked it.
Getting hibernate to work
Once I had the above system, the only thing I needed to do for hibernation was to set resume=UUID=51384ac6-f197-41d9-b8c8-c9607d7e01c8
(this time matching the UUID to my swap partition)
I originally followed the steps from this forum post, and added the rd.lvm.lv flags. However, once I figured out my current setup, I realized it wasn’t needed for me. YMMV. I did learn about the rd.luks.options=discard
from that post and added it to make sure my trim commands worked