Encrypt btrfs partitions with luks on ubuntu
Preface
I ‘ve just been given a new laptop as replacement for my old 4 year old friend thinkpad, according to company policy about equipment depreciation. While waiting to receive new friend, I just happened to have thoughts:
- Should I encrypt my data on new laptop? (1)
- A raid 1 to protect my data against disk failure would be nice (2)
- Has new equipments is nice, I wish depreciation replacement policy also apply to my wife. (3)
NOTE:
(1): This thing has bugged me for a long time. As a system admin, I have many important credentials. That ‘s dangerous, as losing the laptop could be a disaster, even if we react fast enough to change/remove my rights from system.
(2): Recently, I was thinking of using btrfs as replacement for ext4, as it ‘s more friendly with flash drives (nvme and ssd). Besides, a raid setup with btrfs could give you cool thing like filesystem snapshot, compression, bit rot protection … (in case you don’t know what bit rot is, just google it).
(3): My wife is allergic with tech, so this would be safe to list— I guess.
Preparation
The first thing I must do is some dirty background work. As I mentioned, my laptop will be replaced by new one, but I must return back the old laptop to company, I don’t have the basic condition for raid setup anymore: at least 2 block devices. So after some bribing, threatening, and negotiating, I throw out my ultimate move: I said that I need to study encryption on a complex raid setup, so I need 2 disks on my new laptop. This surely is critical hit, as I get my desired old ssd on new laptop along with default nvme drive.
Both my drives: nvme and ssd don’t need to be the same size, as btrfs support unbalanced devices raid setup.
The second thing is backup, of course. Just rsync my home dir at old laptop to external drive — EZ game.
I decided to install ubuntu 22.04, as it ‘s the newest LTS ubuntu distribution at this time, and I need kernel 5.x come with it for custom compression level of btrfs.
Next thing is reading and just try to imagine what you need to do. As my purpose is secure my data, just encrypt my home dir is enough. So my disk layout should look like this
Because I’m not sure how boot progress works with btrfs, I make /boot partition ext4 instead. / mount point is formatted as btrfs, however /home also should be encrypted to protect my personal data, include credentials. However, as btrfs doesn’t have encryption feature yet, I must build it on top of luks.
The action
You may wonder where the raid is? Yeah, I want to talk about the layout without raid first, for the sake of simplicity. The raid setup is more complicated, and I did made some mistakes along the way, before I could get it right.
From user point of view, raid setup in fig.2 is the same as fig.1, they both create 3 mount point: /boot, / and /home. However, the later config is much more complicated, which I did:
- /boot: I used traditional ext4 on top of mdadm raid 1, which is setup during installation. There ‘s no much to say here, you could find the guide easily on internet.
- /: at installation, I format nvme0n1p2 as btrfs single and mount it to /. After the installation complete, I add sda2 to / and convert the partition from single to raid 1:
btrfs device add /dev/sda2 /
btrfs balance start -dconvert=raid1 -mconvert=raid1 /
- /home: This one is complicated. We must create 2 luks partitions on both devices first, and then create btrfs on top of them. Don’t forget the passwords for those partitions, else you will loose your data later.
cryptsetup -y -v luksFormat /dev/sda3
cryptsetup -y -v luksFormat /dev/nvme0n1p3
# open encrypted partitions
cryptsetup luksOpen /dev/nvme0n1p3 home1
cryptsetup luksOpen /dev/sda3 home2
# 2 commands above will create 2 mapping partitions /dev/mapper/home{1,2}. We will work with them instead of real partitions
# create btrfs raid on top of /dev/mapper/home*
mkfs.btrfs -d raid1 -m raid1 -L home /dev/mapper/home1 /dev/mapper/home2
Next, we need to make the settings permanent. There ‘re 2 things that need to set here: the luks volumes settings and mount point settings. Note that crypttab using device partition UUIDs, while in fstab we use mapping devices UUID (you could find those uuid by using blkid command)
- luks setting: edit /etc/crypttab
home1 UUID=7d43926c-03a7–4b4b-8287-b92b26dcdd76 none luks,discard
home2 UUID=75c302e2–96fa-4883-be1c-49a3fbd19b11 none luks,discard - mount points: edit /etc/fstab
UUID=ce260a22–6d89–49f1-bee3–1343831e8ade / btrfs subvol=@,compress=zstd:1,noatime 0 0
UUID=2c70c713-e227–4a1c-abb6–0b87821b24e7 /home btrfs subvol=@home,compress=zstd:1,noatime,nofail 0 0
That ‘s it, just sync my home dir back from portable drive and reboot my laptop to see if things work well.
The trouble of typing password and solution
After reboot, I could see a screen to enter password to decrypt my partition, so enter it and BAM - the same screen appear, even though I’m quite confident that I entered the right password. After viewing the screen carefully, I see that the drive name changed. That makes sense, as we have 2 luks partitions, which needed 2 separated passwords to open. That said, if I decided to encrypt both / partitions, I need to enter password 4 times for luks and 1 more time for my account login — It sounds painful.
I decided to set 1 password for all luks partitions, so no matter how many luks partitons you have, you only need to type password 1 time. But beware that if you type it wrongly the first time, then you must retype it repeatedly for each partition.
Later, I think that typing 1 luks password ‘s also trouble, so I purchased a usb key online, and use it to store luks keys. Just some steps and you no need to type luks password anymore
- Add usb key entry to fstab, to make it mount at boot, but with nofail so it won’t fail your boot process if missing
UUID=7298bf4e-f28a-4b63-b67c-98e93785f50c /secrets btrfs noatime,nofail 0 0 - Create key for decrypt partitions (I use single key for all parts)
openssl genrsa -out /secrets/omni.key 4096
- Add key to luks partitions
cryptsetup luksAddKey /dev/sda3 /secrets/omni.key
cryptsetup luksAddKey /dev/nvme0n1p3 /secrets/omni.key
- Edit /etc/crypttab, replace 3rd field ‘none’ with key path
home1 UUID=7d43926c-03a7–4b4b-8287-b92b26dcdd76 /secrets/omni.key luks,discard
home2 UUID=75c302e2–96fa-4883-be1c-49a3fbd19b11 /secrets/omni.key luks,discard
UPDATE: Later after, I feel trouble again because I must eject the usb key after login, as it ‘s mounted to /secrets. So I think of auto eject the device, after it completed its purpose. There ‘re 2 things needed to handle: only eject after login and the eject permission with root privilege.
- To solve the problem of running a command/script at login, I create a file with extension .desktop at `~/.config/autostart`.
$ vim ~/.config/autostart/reject_luks_keys_usb.desktop
[Desktop Entry]
Type=Application
Name=eject luks usb
Exec=~/scripts/eject_luks_usb.sh
Icon=system-run
X-GNOME-Autostart-enabled=true
$ vim ~/scripts/eject_luks_usb.sh
#!/bin/bash
MOUNT_PATH=/secrets
if [[ -f ${MOUNT_PATH}/omni.key ]]; then
sudo /usr/bin/eject ${MOUNT_PATH}
fi
$ chmod +x ~/scripts/eject_luks_usb.sh
- Next, just make the script run without typing sudo password. We need to grant my user privilege to run command `sudo /usr/bin/eject /secrets` without password: just run
visudo
command as root and add the following line to the bottom `MY_USER ALL=(root) NOPASSWD:/usr/bin/eject /secrets`
I just realize that laziness is the second most motivation for technology and creativity. The first one is poverty.