Encrypting my Debian 11 non-LVM BTRFS root partition post-installation
Additional Reading⌗
- Encrypt an existing unencrypted file system - dm-crypt/Device encryption from the Arch Linux Wiki
- Install and Configure GRUB Bootloader - How To Encrypt Root Filesystem on Linux by Schkn on devconnected
- Using A Live CD/USB To Fix Your Current System - GrubEFIReinstall from the Debian Wiki
- Tom Hale’s answer to “Resize btrfs filesystem to the minimum size in a single step” on the Unix & Linux Stack Exchange
- Robert Cutajar’s question “Initramfs in debootstrap chroot of fully encrypted system” on the Unix & Linux Stack Exchange
- “Full disk encryption (including boot) on Debian” by Daniel Wayne Armstrong
This guide presumes the following
- That your
/boot
mount corresponds to a distinct partition with/boot/efi
being on your ESP (which itself, is a distinct partition independent of/boot
) - That your root filesystem uses BTRFS (multiple guides exist on the internet if you use EXT4)
- That you do not use the Logical Volume Manager and are just dealing with plain BTRFS
- You are willing to deal with some system downtime and that you are booting and following this guide from a Debian live USB with an internet connection
- That
/dev/sdX1
is your ESP,/dev/sdX2
is your root partition,/dev/sdX4
is your/boot
drive (it’s very likely that it’s not, I’m just mentioning this so that you change it instead of possibly doing destructive actions to a completely unrelated disk) - You have a backup… on a distinct physical disk if this blows up in your face or you have a power outage or thermonuclear warfare ensues
- That your computer is modern enough that it doesn’t have to deal with USB keyboard shenanigans as this guide does not account for it
Encrypting your root partition⌗
Mounting and resizing your BTRFS filesystem (not partition, filesystem)⌗
Did you know… You can resize a filesystem without resizing the partition it lies on! Turns out, they are two distinct things. For this guide, as we need to introduce a LUKS header, we need to shrink our drive’s filesystem (while maintaining the partition size) before we get going.
Let’s first create a folder that will contain our mounted root directory
# mkdir /mnt/btrfs
Then mount our BTRFS root partition and query its available size
# mount /dev/sdX1 /mnt/btrfs
# btrfs filesystem usage -b /mnt/btrfs
btrfs filesystem usage -b /mnt/btrfs
should return information to the tune of
[...]
Used: 77960871936
Free (estimated): 136431190016 (min: 136431190016)
Free (statfs, df): 136430141440
Data ratio: 1.00
Metadata ratio: 1.00
[...]
Let’s take the Free (statfs, df)
value of 136430141440
for my drive (naturally, yours will differ) and multiply it by 0.9
(use a calculator or better yet, a search engine so you can just Ctrl+C, Ctrl+V that) and then you’ll get 122787127296
.
Make sure that the difference at least provides you with 128M of buffer space to play with. Now let’s resize our BTRFS filesystem by running.
# btrfs filesystem resize -122787127296 /mnt/btrfs # The minus sign indicates that this is a shrink operation
Now that we have resized our filesystem, it’s time to encrypt the partition.
Unmounting and encrypting your filesystem using LUKS2⌗
First, we must unmount our BTRFS filesystem.
# umount /mnt/btrfs
Then we can encrypt the filesystem using cryptsetup and ask it to allocate 128M
for our LUKS header.
# cryptsetup reencrypt --encrypt --reduce-device-size 128M /dev/sdX1 # You need to set your password here
Once that succeeds, we will now mount our freshly encrypted LUKS partition.
Mounting your encrypted filesystem and resizing it again⌗
Our new LUKS parition will be mapped to the name cryptroot
(you can change this to anything you want but the rest of the guide operates on the presumption that you’re naming it cryptroot
). Let’s mount it.
# cryptsetup luksOpen /dev/sdX1 cryptroot # You will be prompted your password
Once we have done that, our unlocked container is now mapped to /dev/mapper/cryptroot
so now let’s mount the BTRFS filesystem it contains.
# mount /dev/mapper/cryptroot /mnt/btrfs
Once we have achieved that, let’s reclaim the space and undo the shrinking operation from last time.
# btrfs filesystem resize max /mnt/btrfs
Good news! You now have an encrypted root partition. Bad news, you cannot boot from it.. yet.
Setting up our chroot environment⌗
We will be setting up an environment such that we re-define /
(root) to be the root directory of our filesystem instead of
the root directory of our live environment (hence, we’re changing our root directory… so chroot
). We will use the chroot
command to do that but before we do, we have to do some setup.
Have two terminal tabs, one for the chroot
'ed environment and one for your live installation. Let’s go to the live installation, first.
Let’s start by mounting our /boot
and /boot/efi
partitions for our chroot
ed environment to eventually access
P.S. All commands inside the chroot
will be prefixed with a %
to distinguish them while commands in the live environment are prefixed with #
# mount /dev/sdX4 /mnt/btrfs/boot
# mount /dev/sdX1 /mnt/btrfs/boot/efi
Now we need to give our chroot the ability to access block devices. To do so, we will need to bind mount /dev/
# mount -B /dev /mnt/btrfs/dev
Now go to the chroot
'ed tab (if you don’t have one, you can open a new tab and type in chroot /mnt/btrfs
to get into a chrooted environment) and have the chrooted environment mount /proc
and /sys
filesystems.
% mount --types=proc proc /proc
% mount --types=sysfs sys /sys
Now return to the live environment tab and mount the directory that contains your NVRAM variables (important for when you update GRUB) so that your chroot
'ed environment can access them
# mount -B /sys/firmware/efi/efivars /mnt/btrfs/sys/firmware/efi/efivars
Modifying our operating system configuration files⌗
Installing dependencies⌗
We need to install cryptsetup-initramfs
package into the chroot
so that the bootloader and bootstrapping process can read and understand encrypted filesystems. But running apt
won’t work because our chroot
doesn’t know how to resolve domain names, which our package managers rely on, so to fix that we must first go to our live environment and run…
# cp /etc/resolv.conf /mnt/btrfs/etc/resolv.conf
Once we’ve done that, now we can install the package within our chroot
!
% apt update && apt install cryptsetup-initramfs -y
Telling our operating system that root is mounted from an encrypted partition⌗
Now that we’ve setup our chroot, we can use it to modify our existing installation, its boot partition and the EFI System Partition (as we mounted them in our earlier steps).
First, let’s tell our operating system that there is an encrypted filesystem in the first place by modifying /etc/crypttab
. Before we do that, we need to know the UUID of the LUKS partition (not the underlying BTRFS partition) and to do that, we will run lsblk -f
, which will give you an output similar to
[...]
sdX
├─sdX1 vfat FAT32 AAAA-AAAA 1017.9M 0% /mnt/btrfs/boot/efi
├─sdX2 crypto_LUKS 2 ffffffff-ffff-ffff-ffff-ffffffffffff
│ └─cryptroot btrfs f0f0f0f0-f0f0-f0f0-f0f0-f0f0f0f0f0f0 127G 36% /mnt/btrfs/
├─sdX3 btrfs Home aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa 163.4G 38% /mnt/btrfs/home
└─sdX4 vfat FAT32 FFFF-FFFF 682M 33% /mnt/btrfs/boot
[...]
We’re interested in the UUID of crypto_LUKS
, not BTRFS
and so we’ll take ffffffff-ffff-ffff-ffff-ffffffffffff
(yours will naturally, vary)
Then open up /etc/crypttab
with an editor of your choice and ensure that it looks something like this
# <name> <device> <password> <options>
cryptroot UUID=ffffffff-ffff-ffff-ffff-ffffffffffff none luks
Done? Not quite. Now we need to modify /etc/fstab
and tell it that we’re no longer booting off an unencrypted BTRFS partition but to a map of an encrypted partition…
Once you open /etc/fstab
, you’ll probably have something akin to this…
[...]
# <file system> <mount point> <type> <options> <dump> <pass>
UUID=f0f0f0f0-f0f0-f0f0-f0f0-f0f0f0f0f0f0 / btrfs defaults,noatime 0 1
[..]
You should change it in a way such that it results in looking like this..
[...]
# <file system> <mount point> <type> <options> <dump> <pass>
/dev/mapper/cryptroot / btrfs defaults,noatime 0 1
[...]
Telling the bootloader (GRUB) that we’re booting off an encrypted partition⌗
Now that we’ve changed our /etc/crypttab
and /etc/fstab
(these files are read by the operating system in this order), now it’s time to tell GRUB all about it. Just remember your crypto_LUKS
UUID (ffffffff-ffff-ffff-ffff-ffffffffffff
) somewhere.
Open up /etc/default/grub
with your preferred text editor and ensure these lines are present in them
# Setting up GRUB (/etc/default/grub)
GRUB_PRELOAD_MODULES="cryptodisk luks"
GRUB_ENABLE_CRYPTODISK=y
Then find the GRUB_CMDLINE_LINUX_DEFAULT
variable and ensure that cryptdevice=UUID=ffffffff-ffff-ffff-ffff-ffffffffffff root=/dev/mapper/cryptroot
is appended to whatever may or may not be there.
Mine for example, ends up looking like…
[...]
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash cryptdevice=UUID=ffffffff-ffff-ffff-ffff-ffffffffffff root=/dev/mapper/cryptroot"
[...]
As long cryptdevice
detection by UUID and root
mapping by crypttab
name is in the variable, you’re good (hint: the delimiter between each instruction is a space)
Now we need these changes to be reflected.
% grub-install /dev/sdX # Presuming /dev/sdX is the destination drive, do not append numbers
% update-initramfs -c -k all # Updates the ramdisk...
% update-grub2 # Remember to add encrypted root to /etc/crypttab and /dev/mapper/cryptroot is in fstab
Hopefully, we’re now done with what we’ve needed to do, so now let’s do a cleanup because cleanup good (you can close the chroot, we’re done with it)
# sync # Ensure everything we've done is flushed to disk
# umount /mnt/btrfs/sys/firmware/efi/efivars
# umount /mnt/btrfs/sys
# umount /mnt/btrfs/proc
# umount /mnt/btrfs/boot/efi
# umount /mnt/btrfs/boot
# umount /mnt/btrfs/dev
# umount /mnt/btrfs
# sync # For good luck
Reboot, fingers crossed and hope things work. If they don’t, then Google is your friend and hope you have a backup!
Additional Observations⌗
Due to a bug in GRUB, when I followed other guides which recommended to additionally add usb usb_keyboard ehci ohci uhci
to my GRUB_PRELOAD_MODULES
, it bricked my bootloader by breaking hard drive detection.
I remember reading some forum post at 1AM where the same thing was talked about but I can’t find it. It is quite possible you’ll need to read additional guides that talk about enabling USB keyboard support in GRUB but I’ve omitted it from my guide as my computer didn’t need it and it bricked my bootloader (these guides come from stuff that I work on during off hours and figure that it’s neat to write about it by going through my command history and retracing my steps).