Encrypting an existing Linux system's root partition

Srijan Choudhary Srijan Choudhary
- 2 min read
Tagged: linux security

Introduction

I have an Arch Linux system with an unencrypted root partition that I wanted to encrypt. I've documented the steps I followed to achieve this here.

I selected the "LUKS on a partition" option from here. I don't have an LVM setup on this system and didn't need to encrypt the boot partition.

The first step was to have a backup so that if something failed, I could at least recover my critical files. I don't have filesystem-level backups configured, so I used kopia to back up my home folder. Details on this might be in a future blog post.

Process

1. To begin, I set up a USB flash installation medium so that I could boot into a live environment to perform the actual actions. Since I needed to encrypt the root partition, this could not be performed from inside the system running off that partition.

2. After booting into the live environment using the above USB medium, I first shrank the existing filesystem by 32MiB to make space for the LUKS encryption header, which is always stored at the beginning of the device. My filesystem size is exactly 500GiB, so I set the new size to 511968M.

# echo "Check the filesystem"
# e2fsck -f /dev/nvme0n1p7

# echo "Resize"
# resize2fs -p /dev/nvme0n1p7 511968M

3. Now, I encrypted it using the default cipher. This took 37 minutes on my 500GiB partition, which was about 55% full.

# cryptsetup reencrypt --encrypt --reduce-device-size 16M /dev/nvme0n1p7

WARNING!

========

This will overwrite data on LUKS2-temp-12345678-9012-3456-7890-123456789012.new irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for LUKS2-temp-12345678-9012-3456-7890-123456789012.new: 
Verify passphrase:

4. Next, I extended the original ext4 file system to occupy all available space again on the now encrypted partition:

# cryptsetup open /dev/nvme0n1p7 root
Enter passphrase for /dev/nvme0n1p7: 

# resize2fs /dev/mapper/root

5. Now, I mounted the filesystem and chrooted into it:

# mount /dev/mapper/root /mnt
# mount /dev/nvme0n1p1 /mnt/boot
# arch-chroot /mnt

6. Since I have a systemd-based initramfs, I added keyboard, sd-vconsole, and sd-encrypt hooks in the HOOKS section of /etc/mkinitcpio.conf:

HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)
/etc/mkinitcpio.conf

7. Next, I regenerated the initramfs ( -P regenerates it for all presets ):

# mkinitcpio -P

8. Next, I configured the boot loader by adding to kernel parameters:

rd.luks.name=<device-UUID>=root root=/dev/mapper/root

I found the device UUID using: sudo blkid -s UUID -o value /dev/nvme0n1p7. Surprisingly (for me), the UUID had changed after encrypting the partition.

My final bootloader conf file looked like this:

title    Arch Linux
linux    /vmlinuz-linux
initrd   /amd-ucode.img
initrd   /initramfs-linux.img
options  rd.luks.name=1df8ea89-4274-4ef9-a670-76c13e612901=root root=/dev/mapper/root rw
/boot/loader/entries/arch.conf

9. Lastly, I updated /etc/fstab:

/dev/mapper/root  /  ext4  rw,relatime  0 1
/etc/fstab

10. All done. To test it out, I logged out of the chroot environment and rebooted the system.

It asked me for the disk encryption password. After entering the password selected in step 3, the system booted up as usual, and everything looked to be working.

Final Thoughts

This was surprisingly easy to do and did not take much time. The ArchWiki was helpful, even if the information was spread over multiple pages/sections. Taking a backup before starting also made me feel safe about the process.

I did not like the design of the decryption password prompt at bootup. Maybe there's a way to customize it to look better. Update: I found a way. Details here.

Interactions