Skip to main content

LUKS on LVM (encrypted, cached, Desktop)

LUKS (Linux Unified Key Setup) is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not only facilitate compatibility among distributions, but also provides secure management of multiple user passwords. LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.

Management of LUKS encrypted devices is done via the cryptsetup utility.

Nomenclature

Term Description
Physical Volume (PV) On-disk partitioning format to be combined in a VG to a common storage pool
Volume Group (VG) Grouping of one or more PVs to provide a combined storage pool from which storage can be requested in the form of LVs.
Logical Volume (LV) Logical partition format which can be accessed like a block device to hold file systems and data.
Cache device Fast storage used for caching reads/writes to slow storage
Origin device Slow primary storage holding the actual data

Partitioning Setup

LUKS on LVM has the benefit of a LUKS container being able to span multiple disks, thanks to the machanisms of the underlying LVM. This, however, comes with the downside that if you want to have multiple volumes (e.g. for your root volume and a separate home volume or encrypted SWAP) you will have to take extra steps to unlock these volumes during the boot process.

NOTE: If you want to utilize LVM cache this is the desired partioning scheme to use, as the encrypted LUKS container will reside inside an LVM LV and the LVM caching mechanism will cache the LV instead of the unlocked LUKS container, thus not leaking any secrets into the cache.

This guide assumes the following:

  • This is used on a desktop computer without the need to resume (no SWAP partition)
  • There are multiple drives: /dev/nvme0n1 (SSD) and /dev/sda (HDD)
  • The HDD will be cached by the SSD
  • The root file system will be btrfs, with subvolumes for / and /home
  • To tighten security, this setup assumes a unified kernel image and booting via EFISTUB, with the ESP mounted at /efi. Extra steps will be necessary to make the machine bootable.

Preparing partition layout

Start by listing available disks:

fdisk -l

Create a partition layout with cfdisk by pointing it to the first disk, e.g. /dev/nvme0n1:

ATTENTION: cfdisk expects a device file, not a partition.

cfdisk /dev/nvme0n1

If cfdisk asks you about the partition table scheme to use, select gpt.

Create the following partition layout:

FS Type Size Mount Point Comment
vfat 1G /efi EFI System
LVM (remaining) Linux LVM

Start cfdisk for the second disk, e.g. /dev/sda:

cfdisk /dev/sda

Create the following partition layout:

FS Type Size Mount Point Comment
LVM (all) Linux LVM

Setting up LVM

Start by creating LVM PVs on the partitions we just laid out:

pvcreate /dev/nvme0n1p2   # SSD
pvcreate /dev/sda1        # HDD

Next, create a VG spanning both PVs:

NOTE: vg0 is used as an example here. Name your VG whatever you like.

vgcreate vg0 /dev/nvme0n1p2 /dev/sda1

Create an LV inside vg0, using 100% of the available space on the PV at /dev/sda1 and label it lv_root:

lvcreate -l 100%FREE -n lv_root vg0 /dev/sda1

Create an LV inside vg0, using 100% of the available space on the PV at /dev/nvme0n1p2 and label it lv_cache:

lvcreate -l 100%FREE -n lv_cache --type cache-pool vg0 /dev/nvme0n1p2
lvconvert --type cache --cachepool vg0/lv_cache vg0/lv_root

Creating the LUKS container

Create the LUKS container inside the LV of the origin device:

WARNING: Do NOT forget your passphrase! In case of loss you won't be able to access the data inside the container anymore!

cryptsetup luksFormat /dev/mapper/vg0-lv_root

Open the newly created LUKS container and supply the passphrase you just set:

NOTE: cryptroot is used as an example here. Use whatever you like.

cryptsetup open /dev/mapper/vg0-lv_root cryptroot

Formatting and mounting partitions

Create file systems for the ESP and the root file system:

mkfs.fat -F 32 /dev/nvme0n1p1
mkfs.btrfs /dev/mapper/cryptroot

Mount the root btrfs file system and create the subvolumes:

mount /dev/mapper/cryptroot /mnt

btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home

Unmount the root btrfs file system:

umount -R /mnt

Mount the @ subvolume:

mount /dev/mapper/cryptroot -o noatime,compress-force=zstd,space_cache=v2,subvol=@ /mnt

Create mount points for /efi and /home:

mkdir -p /mnt/{efi,home}

Mount the remaining partitions and subvolumes:

mount /dev/nvme0n1p1 /mnt/efi
mount /dev/mapper/cryptroot -o noatime,compress-force=zstd,space_cache=v2,subvol=@home /mnt/home