LUKS and Full-Disk Encryption: Root Partitions, TPM Unlock, and Key Management
Linux Unified Key Setup (LUKS) is the standard full-disk encryption on Linux. It ships in every mainstream distro installer, backs the volume encryption for ext4/XFS/Btrfs on top of dm-crypt, and quietly protects laptops, servers, and removable drives around the world. Like most things that ship by default, the installer gets you 80% of the way — the remaining 20% (key rotation, TPM-backed unlock, headers, keyslots, recovery plans) is where production use lives, and where most people run into trouble years later when a drive fails and they realize they never actually thought about recovery.
This post covers LUKS from the working-engineer perspective: the format, the tools, common deployment patterns (root, home, removable drives, TPM unlocking), and the mistakes that turn “I encrypted it” into “I can’t get my data back”.
What LUKS actually is
Underneath everything on Linux, block-level encryption is provided by the kernel’s dm-crypt device mapper target. dm-crypt takes a raw block device and a key, and exposes a new mapped device (/dev/mapper/encrypted_root) that transparently encrypts and decrypts reads and writes using that key.
dm-crypt by itself is stateless — you provide a key, it does the math. It has no idea what password you used, whether you want multiple passwords, how to survive a key change, or how to distinguish “bad password” from “this isn’t an encrypted device”. LUKS is the metadata layer that adds all of those:
- A header at the start of the device describing cipher, hash, key size, and slot layout.
- Up to 8 keyslots (LUKS1) or 32 keyslots (LUKS2), each holding a copy of the master key encrypted with a different passphrase-derived key.
- Anti-forensic splitting of keyslot data so even shredding a keyslot is robust.
- Per-keyslot KDF parameters so you can cheaply decrypt on a server while making brute-force expensive.
The practical consequence: the master key is stored once, encrypted N times with N different passphrases (keyslot entries). Changing a passphrase re-encrypts a keyslot with a new passphrase-derived key but doesn’t touch the master key, so data does not need to be re-encrypted. Removing all keyslots — or destroying the header — makes the data cryptographically unrecoverable.
LUKS2 is the current format and the default on modern distros. LUKS1 still exists for legacy reasons and for bootloaders that don’t support LUKS2 (older GRUB). If you have a choice, use LUKS2.
The tools
cryptsetup— the canonical userspace tool. Every LUKS operation goes through this.dmsetup— lower level, for inspecting the live device mapper state.systemd-cryptsetup— systemd’s unlocker, consumed by/etc/crypttab.systemd-cryptenroll— LUKS2-aware tool for enrolling TPMs, FIDO2 tokens, and recovery keys.clevis— alternative policy-based enrollment (TPM, Tang network unlock).
If you only remember one command, remember cryptsetup luksDump /dev/sdX — it shows the entire header, every keyslot, the cipher, and the KDF parameters, and it’s the starting point for any debugging.
Encrypting a fresh disk
The canonical flow for setting up a new encrypted volume:
|
|
To unmount and close:
|
|
The luksFormat defaults on modern cryptsetup are good: LUKS2 format, aes-xts-plain64 cipher, 512-bit key, argon2id KDF with parameters tuned to take ~2 seconds on the encrypting machine. Don’t override unless you know why.
Explicitly setting parameters
If you need to pin parameters (often for compliance or reproducible builds):
|
|
The KDF choice matters. argon2id resists GPU and ASIC attacks; pbkdf2 does not. LUKS2 defaults to argon2id. LUKS1 is stuck with pbkdf2. This alone is a reason to prefer LUKS2.
The --iter-time 2000 tells cryptsetup to choose KDF parameters that take roughly 2000 ms on this machine. This calibrates to your machine’s speed, so a fast server gets strong KDF parameters and a Raspberry Pi gets survivable ones. If you encrypt on a fast machine and expect to decrypt on a slow one, lower this number or unlock will feel eternal.
Keyslot management
Adding a second keyslot
Every LUKS volume starts with one keyslot. Add more with:
|
|
Useful reasons to add keyslots:
- A recovery key held in a safe, separate from the daily-use passphrase.
- An automation key used for scripted unlock on provisioning.
- A shared key used by multiple administrators (though per-admin keys are better for auditability).
Adding a key file
Instead of a passphrase, LUKS can accept a file’s contents as the unlock material:
|
|
This is the foundation for unattended unlocks (secondary disks unlocked by a file stored on the encrypted root disk), but note: a key file stored on another encrypted volume is only as secure as that other volume’s unlock. If the root is unlocked via TPM with no user interaction, so is every secondary volume keyed to a file on root.
Removing a keyslot
|
|
Always remove old keyslots when rotating. A LUKS volume with an ex-employee’s passphrase still enrolled is a half-rotated volume.
Inspecting keyslots
|
|
Output shows every keyslot, its KDF, memory/iteration/parallel parameters, and any token associations (for TPM/FIDO2 enrollments). Learn to read this — you cannot operate LUKS without it.
The LUKS header: the most important thing to back up
The header contains the encrypted master key. If the header is lost or corrupted, your data is unrecoverable, even if you remember every passphrase.
This is the single most important operational fact about LUKS.
Back up the header immediately after luksFormat:
|
|
Store this backup somewhere offline, because it is sufficient (with a passphrase) to decrypt the volume — so don’t leave it on a shared network drive. A safe, a password manager attachment, or burned to a physical medium are appropriate.
Restore with:
|
|
Detached headers
For high-assurance setups, store the header on a separate device entirely:
|
|
The header device can be a USB key that stays in a safe except when mounting. Without the header, the disk looks completely random — no indication it’s even encrypted, let alone with LUKS. Plausible deniability, in a sense. Operationally fragile; use only when the threat model justifies it.
Encrypting the root filesystem
At install time, every major distro offers “encrypt disk” in the installer. For manual setups:
- Format the disk with LUKS2.
- Open the LUKS volume.
- Create a filesystem on the mapped device.
- Install the OS.
- Configure
/etc/crypttabwith an entry for the root volume. - Rebuild the initramfs to include LUKS tooling and the correct device mapping.
- Configure the bootloader (GRUB needs
GRUB_ENABLE_CRYPTODISK=y).
The initramfs part is where people get stuck. The kernel at boot time has no filesystem; it needs a minimal userspace (initramfs) that contains cryptsetup, the right kernel modules, and instructions to unlock the LUKS device before mounting root.
Every distro handles this slightly differently:
- Debian/Ubuntu:
update-initramfs -uafter editing/etc/crypttab. - Fedora/RHEL:
dracut -f— dracut reads/etc/crypttabautomatically. - Arch: edit
/etc/mkinitcpio.confHOOKS to includeencrypt(orsd-encryptfor systemd-based init), thenmkinitcpio -P.
The /etc/crypttab entry looks like:
root UUID=<uuid-of-/dev/sda2> none luks,discard
none here means “prompt for passphrase at boot”. discard enables TRIM passthrough — see the section on discard below.
For the root volume only, the kernel command line also matters. With GRUB and systemd:
GRUB_CMDLINE_LINUX="rd.luks.uuid=luks-<uuid> root=/dev/mapper/root"
After grub-mkconfig -o /boot/grub/grub.cfg, the system will prompt for the LUKS passphrase at boot.
TPM-backed unlock
Typing a passphrase at every boot gets old. TPM (Trusted Platform Module) unlock binds the LUKS unlock to the hardware state of the machine — the TPM releases a key only if the boot chain (BIOS, bootloader, kernel, initramfs) hashes match the expected values. Modify any of those, and the TPM refuses to release the key.
For laptops, this gives you: power on → boot straight to login, without typing a passphrase, but with no way for an attacker to unlock the disk by booting their own OS.
The risk: if the system’s boot chain changes (firmware update, kernel update), the PCRs (Platform Configuration Registers) change, and the TPM won’t release the key. Always keep a passphrase keyslot as recovery.
systemd-cryptenroll (modern approach)
|
|
Then update /etc/crypttab:
root UUID=<uuid> none luks,discard,tpm2-device=auto
PCR selection matters:
- PCR 0: BIOS/firmware. Changes on firmware update.
- PCR 1: BIOS configuration.
- PCR 4: Boot loader code. Changes on bootloader update.
- PCR 7: Secure Boot state. Changes if Secure Boot is disabled or keys change.
- PCR 8–9: Bootloader config.
- PCR 11: Unified kernel images (systemd-boot with UKI).
- PCR 14: Extensible — shim-enrolled MOK state.
Binding to PCR 7 alone is the most stable choice: it only changes if someone tampers with Secure Boot. Binding to PCR 4 is stricter but breaks on every kernel update. Choose deliberately.
Re-sealing after updates
When a kernel or bootloader update changes PCRs, re-seal:
|
|
Some distros handle this with hooks. On Arch, systemd provides systemd-pcrlock for predictable PCR policies that survive updates without re-sealing. It’s new and complex; evaluate for your use case.
Clevis (the older approach)
Clevis handles TPM2 unlock as one of several “pins”:
|
|
Clevis also provides Tang — network-bound disk encryption. A Tang server on your network offers unlock material; the encrypted disk unlocks only when it can reach the Tang server. Useful for servers in a locked room that should refuse to boot if stolen.
Recovery keys
Whatever automated unlock you set up (TPM, Tang, FIDO2), always keep a passphrase. Hardware fails. Firmware updates brick enrolled PCRs. TPMs get cleared.
|
|
This prints a 48-character string. Write it down. Put it in a safe. Don’t skip this.
Key rotation
Changing a passphrase
|
|
This does not re-encrypt data. It only re-encrypts the keyslot’s copy of the master key.
Rotating the master key
Sometimes you genuinely want to rotate the master key — compliance, suspicion of compromise, etc. LUKS2 supports this via reencrypt:
|
|
This is slow: every block on the disk is read, decrypted with the old master key, re-encrypted with the new one, and written back. A 1 TB disk takes hours. It is crash-safe — if interrupted, resume with cryptsetup reencrypt /dev/sdb again.
Changing cipher
|
|
Same performance caveat. Useful if an old volume was created with weaker defaults.
The discard (TRIM) question
discard on an encrypted SSD has a tradeoff:
Pro: The SSD’s flash wear leveling works properly, TRIM discards unused blocks, write amplification stays low, performance over time is preserved.
Con: An attacker observing the disk can see which blocks are in use vs discarded. They don’t see what’s in used blocks, but the allocation pattern itself leaks information (filesystem type, approximate free space, that the disk is encrypted at all).
For most users, turn discard on. The threat model that defeats discard (an attacker who can read the physical disk periodically over time) is unusual, and the performance cost of no-TRIM on SSDs is real.
Enable per-volume in /etc/crypttab:
root UUID=<uuid> none luks,discard
And at the filesystem layer: prefer fstrim.timer over the discard mount option — weekly batched TRIM beats per-unlink synchronous TRIM for most workloads.
Removable drives
For USB drives you want portable:
|
|
GNOME and KDE desktops will detect the LUKS drive on insertion and prompt for a passphrase. Store the passphrase in a password manager; no TPM here because the drive needs to unlock on arbitrary hosts.
For drives meant for archival (data you’ll decrypt again years later), back up the LUKS header separately and make sure you’re using LUKS2 with a current cipher. Cipher choices that looked fine in 2013 may not be recommended in 2030. If the default aes-xts-plain64 shifts, reencrypt is your migration path.
Things that will bite you
Lost passphrase, no backup
No recovery. LUKS is designed exactly so that nobody — including you — can bypass the KDF. Offline brute-force is the only option, and argon2id makes that infeasible. Restore from your off-disk backup. You do have one, right?
Header corruption from dd accidents
Every few months someone tries to dd if=/dev/zero of=/dev/sda bs=1M count=1 and nukes the first megabyte of their encrypted disk. The LUKS header lives there. luksHeaderBackup before doing anything risky. And always put backups offline.
Boot order surprises
If your system has both a TPM-unlock and a passphrase keyslot and the TPM is working, systemd-cryptsetup uses the TPM silently. If the TPM fails, it falls back to prompting. If the TPM fails to respond but thinks it’s still valid, you’ll wait 30 seconds at boot for the TPM timeout. Verify by rebooting after enrollment — don’t ship a configuration you haven’t tested.
Encrypted swap
Swap can be encrypted with a random per-boot key (/dev/urandom as the “keyfile”):
swap /dev/sda3 /dev/urandom swap,cipher=aes-xts-plain64:sha256,size=512
Every boot generates a new key — suspended memory cannot survive a reboot in recoverable form. Don’t use this with hibernate, which writes RAM to swap and needs it back after power-off. For hibernate-compatible swap, use a real LUKS volume with a persistent key.
UEFI Secure Boot + TPM
Secure Boot state lives in PCR 7. If you ever disable Secure Boot (even temporarily to troubleshoot), the TPM will no longer release the key. Re-enroll with the new PCR state or stick a recovery passphrase in from the systemd prompt.
discard leaks on snapshotting backups
If you dd a raw encrypted disk to a backup image, discarded blocks may still be zeroed and compressible. An attacker who gets the image can identify non-allocated blocks, even without the passphrase. For image-level backups of encrypted disks, use LUKS-aware tools or accept the leak.
A sensible pattern for a daily-use laptop
- LUKS2 root partition, default cipher (aes-xts-plain64), argon2id KDF.
- TPM2 unlock bound to PCR 7 for user-invisible boot.
- Recovery passphrase generated with
systemd-cryptenroll --recovery-key, stored in a password manager. - LUKS header backup stored in a password manager attachment.
discardenabled for SSD health.fstrim.timerenabled weekly.- Kernel update testing: verify boot after every
dnf updateorapt upgradethat touches the kernel or bootloader. Re-seal TPM if needed.
A sensible pattern for a server
- LUKS2 for the data volume, root unencrypted (or Tang-unlocked via clevis).
- Unlock automation via Tang network-bound policy — requires the Tang server to be reachable at boot.
- Two enrolled keyslots: one for the Tang pin, one recovery passphrase known to on-call.
- LUKS header backed up to an off-server encrypted vault.
- Key rotation scheduled annually;
luksChangeKeyfor passphrases, fullreencryptonly on compromise suspicion. - Document the recovery flow in your runbooks. Test it on a scratch machine before you need it at 3 a.m.
When LUKS is the wrong choice
- File-level encryption needs. Use
fscrypt(native on ext4/F2FS) orgocryptfs/CryFSon top of a normal filesystem. - Multi-user systems where users should have independent encryption.
fscryptwith per-user keys is a better match. - Cloud volumes where the cloud provides encryption at rest. Layering LUKS on top of AWS EBS or Azure Managed Disk encryption is occasionally useful (defense in depth, customer-held keys) but more often just adds operational complexity with no real threat model improvement.
- Databases doing their own encryption. PostgreSQL TDE, MySQL keyring-based encryption — if the DB does it, LUKS is redundant for that tablespace.
LUKS is not magic. It’s a well-designed key-management wrapper around the kernel’s already-good block encryption. The failure modes are procedural, not cryptographic: lost headers, unrotated keyslots, TPM bindings that break on kernel updates, backups that were never tested. Treat the header like a precious artifact, document your recovery paths, test them, and LUKS will quietly do its job for a decade.
Comments