Disk Encryption (LVM-on-LUKS)

Overview

This guide covers LVM-on-LUKS encryption for data drives on Linux workstations. This is the recommended approach for enterprise deployments requiring encryption at rest.

LVM-on-LUKS vs LUKS-on-LVM

  • LVM-on-LUKS (this guide): Raw disk → LUKS container → LVM inside

  • LUKS-on-LVM: LVM volumes → LUKS on each LV (more complex, separate keys per volume)

LVM-on-LUKS is simpler: one passphrase/key unlocks the container, then LVM manages the space inside.

Architecture

Physical Disk:     /dev/sda (raw disk)
       ↓
LUKS Container:    /dev/mapper/secure_vol (cryptsetup)
       ↓
LVM Physical Vol:  /dev/mapper/secure_vol (pvcreate)
       ↓
LVM Volume Group:  dataVG (vgcreate)
       ↓
LVM Logical Vol:   /dev/mapper/dataVG-dataLV1 (lvcreate)
       ↓
Filesystem:        ext4 (mkfs.ext4)
       ↓
Mount Point:       /data/LV1

Boot Sequence

Understanding the boot sequence is critical for troubleshooting:

Step System Action Config File

1

systemd reads crypttab

/etc/crypttab

2

Unlock LUKS container → /dev/mapper/<name>

Passphrase or keyfile

3

Activate LVM volume groups

Automatic (lvm2 service)

4

Mount filesystems from fstab

/etc/fstab

crypttab unlocks LUKS BEFORE LVM exists.

The crypttab entry points to the raw encrypted device, NOT the LVM device inside.

Prerequisites

  • Empty disk or partition for encryption (e.g., /dev/sda)

  • Root access

  • cryptsetup package installed

Step 1: Identify Target Disk

# List all block devices
lsblk -f

# Identify the disk to encrypt (e.g., /dev/sda)
# ENSURE it's the correct disk - this process destroys all data!

Double-check the device! The following commands will DESTROY all data on the target disk.

Step 2: Create LUKS Container

# Create LUKS2 container on raw disk
sudo cryptsetup luksFormat --type luks2 /dev/sda

# You'll be prompted:
# - Type uppercase YES to confirm
# - Enter passphrase (this is the master passphrase - store securely!)

Passphrase escrow: Store the master passphrase in a secure location (password manager, encrypted vault). If this passphrase is lost and no keyfile exists, the data is unrecoverable.

Step 3: Open the LUKS Container

# Open (unlock) the LUKS container
sudo cryptsetup open /dev/sda secure_vol

# Enter the passphrase when prompted

# Verify it's open
ls -la /dev/mapper/secure_vol

The unlocked container is now available at /dev/mapper/secure_vol.

Step 4: Create LVM Structure

# Create Physical Volume on the unlocked LUKS container
sudo pvcreate /dev/mapper/secure_vol

# Create Volume Group
sudo vgcreate dataVG /dev/mapper/secure_vol

# Create Logical Volume (use all available space)
sudo lvcreate -l 100%FREE -n dataLV1 dataVG

# Verify LVM structure
sudo lvs
sudo vgs
sudo pvs
Expected output:
  LV      VG     Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  dataLV1 dataVG -wi-a----- <10.91t

  VG     #PV #LV #SN Attr   VSize   VFree
  dataVG   1   1   0 wz--n- <10.91t    0

  PV                     VG     Fmt  Attr PSize   PFree
  /dev/mapper/secure_vol dataVG lvm2 a--  <10.91t    0

Step 5: Format and Mount

# Format with ext4
sudo mkfs.ext4 -L "Research Data" /dev/mapper/dataVG-dataLV1

# Create mount point
sudo mkdir -p /data/LV1

# Mount
sudo mount /dev/mapper/dataVG-dataLV1 /data/LV1

# Verify
df -h /data/LV1

Step 6: Configure crypttab

The /etc/crypttab file tells systemd how to unlock LUKS at boot.

crypttab format:

<mapper_name>  <device>  <keyfile|none>  <options>
  • <mapper_name> = Name in /dev/mapper/ after unlock

  • <device> = UUID or path to the ENCRYPTED container

  • <keyfile|none> = Path to keyfile, or none for passphrase prompt

  • <options> = LUKS options (e.g., luks, discard)

6.1 Get LUKS UUID

# Get the UUID of the LUKS container
sudo cryptsetup luksUUID /dev/sda

# Example output: a786315e-2a33-401c-bdfa-e8abd4524488

6.2 Edit crypttab

sudo vim /etc/crypttab
Add this line:
secure_vol  UUID=a786315e-2a33-401c-bdfa-e8abd4524488  none  luks

Common mistake: Using the LVM device in crypttab

# WRONG - LVM doesn't exist until LUKS is unlocked!
/dev/mapper/dataVG-dataLV1  /data/LV1  /root/.crypt_pw_file  luks

# CORRECT - Point to the LUKS container
secure_vol  UUID=a786315e-2a33-401c-bdfa-e8abd4524488  none  luks

Field-tested at CHLA (2026-02-06): This error caused boot failures until corrected.

Step 7: Configure fstab

The /etc/fstab file mounts the filesystem AFTER LUKS is unlocked and LVM is activated.

sudo vim /etc/fstab
Add this line:
/dev/mapper/dataVG-dataLV1  /data/LV1  ext4  defaults  0  2
Field Value

Device

/dev/mapper/dataVG-dataLV1 (LVM device, not LUKS)

Mount point

/data/LV1

Filesystem

ext4 (NOT luks!)

Options

defaults

Dump

0 (no backup)

Pass

2 (fsck after root)

Common mistake: Wrong filesystem type

# WRONG - luks is not a filesystem type!
/dev/mapper/dataVG-dataLV1  /data/LV1  luks  defaults  0  2

# CORRECT - ext4 is the actual filesystem
/dev/mapper/dataVG-dataLV1  /data/LV1  ext4  defaults  0  2

Field-tested at CHLA (2026-02-06): This error caused mount failures.

Step 8: Test Configuration

8.1 Test fstab

# Unmount first
sudo umount /data/LV1

# Test mount from fstab
sudo mount -a -v

# Verify
df -h /data/LV1

8.2 Full Reboot Test

# Reboot to test full boot sequence
sudo reboot

# After boot, verify:
lsblk -f
df -h /data/LV1

Keyfile Auto-Unlock (Unattended Boot)

For servers that must boot unattended, use a keyfile instead of passphrase prompt.

Security tradeoff: Keyfile on disk means anyone with physical access to the drive can decrypt. Only use this for:

  • Servers in secure data centers

  • Systems where boot-time passphrase entry isn’t feasible

  • Protecting against remote/network attacks, not physical theft

8.1 Create Keyfile

# Generate random keyfile
sudo dd if=/dev/urandom of=/root/.crypt_pw_file bs=512 count=1

# Secure permissions (root-only)
sudo chmod 400 /root/.crypt_pw_file
sudo chown root:root /root/.crypt_pw_file

8.2 Add Keyfile to LUKS

# Add keyfile as additional unlock method
sudo cryptsetup luksAddKey /dev/sda /root/.crypt_pw_file

# Enter the existing passphrase when prompted

LUKS supports multiple key slots. The keyfile is slot 1, passphrase remains in slot 0. Both can unlock.

8.3 Update crypttab

sudo vim /etc/crypttab
Change none to keyfile path:
secure_vol  UUID=a786315e-2a33-401c-bdfa-e8abd4524488  /root/.crypt_pw_file  luks

8.4 Test Keyfile Unlock

# Close the container
sudo cryptsetup close secure_vol

# Open with keyfile (no passphrase prompt)
sudo cryptsetup open /dev/sda secure_vol --key-file /root/.crypt_pw_file

# Verify it opened
ls /dev/mapper/secure_vol

8.5 Reboot Test

sudo reboot

# Should boot without passphrase prompt
# Verify after boot:
lsblk
df -h /data/LV1

Verification Commands

# LUKS status
sudo cryptsetup status secure_vol

# LUKS header info
sudo cryptsetup luksDump /dev/sda

# LVM structure
sudo pvs
sudo vgs
sudo lvs

# Mount status
mount | grep dataLV1

# Disk usage
df -h /data/LV1
Expected cryptsetup status output:
/dev/mapper/secure_vol is active.
  type:    LUKS2
  cipher:  aes-xts-plain64
  keysize: 512 bits
  key location: keyring
  device:  /dev/sda
  sector size:  512
  offset:  32768 sectors
  size:    23433854951 sectors
  mode:    read/write

Troubleshooting

Boot Fails at crypttab

Symptom: System hangs at boot, waiting for LUKS passphrase or showing errors about missing device.

Cause: crypttab references wrong device or wrong format.

Fix:

# Boot from live USB
# Open the LUKS container manually
sudo cryptsetup open /dev/sda secure_vol

# Mount root filesystem
sudo mount /dev/mapper/root /mnt  # adjust for your root device

# Edit crypttab
sudo vim /mnt/etc/crypttab

# Verify UUID matches
sudo cryptsetup luksUUID /dev/sda

fstab Mount Fails

Symptom: System boots but mount fails with "wrong fs type" or "special device does not exist."

Causes: 1. Wrong filesystem type in fstab (luks instead of ext4) 2. LVM not activated before mount

Fix:

# Check what filesystem is actually on the LV
sudo blkid /dev/mapper/dataVG-dataLV1

# Fix fstab
sudo vim /etc/fstab
# Change luks to ext4

# If LVM not active, activate it
sudo vgchange -ay dataVG

# Then mount
sudo mount -a

"No key available with this passphrase"

Symptom: When using keyfile, LUKS reports no key available.

Cause: Keyfile not added to LUKS key slots.

Fix:

# Add the keyfile (requires existing passphrase)
sudo cryptsetup luksAddKey /dev/sda /root/.crypt_pw_file

Recovering After Wrong crypttab Entry

Symptom: Boot loops or fails to find LUKS device.

Fix (from live USB):

# Mount root
sudo mount /dev/sdX1 /mnt  # your root partition

# Fix crypttab
sudo vim /mnt/etc/crypttab

# Regenerate initramfs (if using dracut/mkinitcpio)
sudo arch-chroot /mnt
mkinitcpio -P
exit

sudo reboot

Security Best Practices

  1. Use LUKS2: Modern encryption, better header protection

  2. Strong passphrase: At least 20 characters, random if possible

  3. Escrow passphrase: Store securely (password manager, physical safe)

  4. Keyfile permissions: 400 or 600, root:root only

  5. Secure boot: Consider TPM-based unlock for additional protection

  6. Backup LUKS header: cryptsetup luksHeaderBackup /dev/sda --header-backup-file header.img

Quick Reference

# Create LUKS container
sudo cryptsetup luksFormat --type luks2 /dev/sda

# Open container
sudo cryptsetup open /dev/sda secure_vol

# Create LVM
sudo pvcreate /dev/mapper/secure_vol
sudo vgcreate dataVG /dev/mapper/secure_vol
sudo lvcreate -l 100%FREE -n dataLV1 dataVG

# Format and mount
sudo mkfs.ext4 /dev/mapper/dataVG-dataLV1
sudo mount /dev/mapper/dataVG-dataLV1 /data/LV1

# Add keyfile
sudo dd if=/dev/urandom of=/root/.crypt_pw_file bs=512 count=1
sudo chmod 400 /root/.crypt_pw_file
sudo cryptsetup luksAddKey /dev/sda /root/.crypt_pw_file

# Get UUID for crypttab
sudo cryptsetup luksUUID /dev/sda