Encrypt Btrfs File System on an External Hard Drive Using LUKS

4 minute read

Background/Problem

Backups are always a good idea. That’s why I was looking for a solution to the following problem:

While I like to have backups of all my data, I have one data directory which needed a little extra treatment (mainly due to security reasons). This was the reason for me to rethink my backup strategy for all my files, but I started with that one directory. Maybe I will write a post about my whole backup strategy in the future. But for now, I needed/wanted the following:

  • I wanted to have a copy of the directory in question on an external hard drive. This copy would be synchronized from my home directory to the external drive on a regular basis.
  • I wanted to be able to take time-stamped snapshots of the directory on the external drive.
  • The backup itself and the snapshots must be encrypted.

To be able to refer to the mentioned directory, let’s say it is the directory home/andreas/data/.

Solution

After some reading and thinking about the problem, I decided to use LUKS to encrypt the entire hard drive and Btrfs as the file system. I don’t want to discuss my reasons for doing so in this post, because it will be long enough anyways. Just this much: The combination of chosen technologies allows me to do, what I wanted to archive 😀.

I also won’t discuss Btrfs in general or what subvolumes on Btrfs file systems are. If you want to find out more about it, please search online. I good starting point might be the Arch Wiki.

Starting point was a new external USB hard drive with nothing on it. For the rest of the post let’s assume that the hard drive can be found under /dev/sdb.

First of all, I used cfdisk to put a single partition on the drive. This was straight forward and I won’t explain the details here.

Before putting a file system on the new partition, I setup the encryption. As mentioned this was done using LUKS. To do that, I ran:

>> sudo cryptsetup luksFormat --type luks2 /dev/sdb1

When running this command, you will be prompted for a passphrase. I use a password manager to keep track of all my passwords. This manager comes with a password generator that I used to create the passphrase. I leave it up to you to come up with a save passphrase for your device.

Afterwards one has to open the encrypted device, before it can be used:

>> sudo cryptsetup open --type luks2 /dev/sdb1 backup_drive

Of course this command will ask you for the passphrase that you used to setup the encryption. After running this command, the hard drive can be used just like any un-encrypted drive and can be found under /dev/mapper/backup_drive.

Once the device was opened, I put the Btrfs file system on it and used a lable (“backup”) for the file system:

>> sudo mkfs.btrfs -L backup /dev/mapper/backup_drive

The idea was to organize the file system and directory structur similar to what they discribed here. I wanted it to look like this:

toplevel "@"                (volume root directory, not mounted)
   +-- data                 (subvolume, to be mounted at $HOME/backup/data)
   \-- snapshots            (subvolume, to be mounted at $HOME/backup/snapshots)
       +-- data_2023-06-15  (data dir snapshot taken at the 2023-06-15)
       +-- data_2023-06-16  (data dir snapshot taken at the 2023-06-16)
       +-- ...

The first step was to create the toplevel subvolume. I named it “@” mainly because the program timeshift requires that. And even though, I don’t use it (at least not yet), I needed a name and just went with it.

>> sudo mkdir -p /run/media/andreas/backup
>> sudo mount /dev/mapper/backup_drive /run/media/andreas/backup/
>> sudo chown andreas:andreas /run/media/andreas/backup/
>> btrfs subvolume create /run/media/andreas/backup/@
>> sudo btrfs subvolume list /run/media/andreas/backup
ID 256 gen 8 top level 5 path @

This created the toplevel subvolume and listed the subvolumes. You can see that the ID 256 was assigned to “@”. This ID will be used later. Before creating the subvolume, I changed the owner of the backup directory to myself. This makes using it later easier.

After that I created the other two subvolumes:

>> sudo umount /run/media/andreas/backup
>> sudo mount -o subvolid=256 /dev/mapper/backup_drive /run/media/andreas/backup/
>> btrfs subvolume create /run/media/andreas/backup/data
>> btrfs subvolume create /run/media/andreas/backup/snapshots
>> sudo btrfs subvolume list /run/media/andreas/backup
ID 256 gen 14 top level 5 path @
ID 257 gen 12 top level 256 path data
ID 258 gen 14 top level 256 path snapshots

In the output of the last command, you can see the IDs that were assigned to the new subvolumes. They will be used later in the file /etc/fstab.

Now I wanted to add some entries in the following to files:

  1. /etc/crypttab
  2. /etc/fstab

For that I needed two UUIDs that I found with the following command:

>> sudo blkid
...
/dev/sdb1: UUID="<HARD_DRIVE_UUID>" TYPE="crypto_LUKS" PARTUUID="<PART_UUID>"
...
/dev/mapper/backup_drive: LABEL="backup" UUID="<FS_UUID>" UUID_SUB="<SUB_UUID>" BLOCK_SIZE="4096" TYPE="btrfs"
...

I added the following line(s) to /etc/crypttab and /etc/fstab using the <HARD_DRIVE_UUID> and <FS_UUID> I just found and the subvolume IDs from earlier:

# /etc/crypttab:
backup_drive UUID="<HARD_DRIVE_UUID>" none luks,noauto
# /etc/fstab:
# /dev/mapper/backup_drive
UUID=<FS_UUID> /home/andreas/backup/data      btrfs subvolid=257,rw,noauto,users 0 0
UUID=<FS_UUID> /home/andreas/backup/snapshots btrfs subvolid=258,rw,noauto,users 0 0

The line in /etc/crypttab causes the systemd-cryptsetup-genertor to generate a systemd unit file for the device automatically at startup, but the device is not opened right away. You can list all unit files generated by systemd-cryptsetup-genertor with:

>> sudo systemctl list-unit-files | grep systemd-cryptsetup
systemd-cryptsetup@backup_drive.service        generated        -

Now it is possible to open the encrypted device with:

>> sudo systemctl start systemd-cryptsetup@backup_drive.service

This opens the LUKS device and adds the device node entry /dev/mapper/backup_drive.

The lines in /etc/fstab allow me to mount the Btrfs file systems as a normal user under /home/andreas/backup/data and /home/andreas/backup/snapshots:

>> mount /home/andreas/backup/data
>> mount /home/andreas/backup/snapshots

This completes the setup. How I actually do the backups is a topic for another post.



Take care,
Andreas

Updated:

Leave a comment