Linux experts Seravo background Linux Debian SUSE
Seravo blog: Linux and open source – technology and strategy

Secure and flexible backup server with dm-crypt and btrfs

In our previous article we described an idea setup for a modern server with btrfs for flexibility and redundancy. In this article we describe another kind of setup that is ideal only for a backup server. For a backup server redundancy and high availability are not important, but instead maximal disk space capacity and the amount of backups it can hold. Additionally it is good if the disks are encrypted to protect agains physical theft.

In this article we explain how to encrypt the disks with LUKS/dm-crypt so that all files are encrypted, and how all disks can be automatically opened using one single password entered by the administrator at boot time, as having multiple passwords would just add complexity without any gain, since all passwords are equally strongly protected by the same encryption technology.

Use Ubuntu installer to get the basic LUKS/dm-crypt in place

The easiest way to get started and get all pieces of software, Grub modules and other in place is to run the Ubuntu installer and install on a single disk a standard system using the option Encrypted disk. This will deploy an unencrypted /boot partition, and an encrypted LUKS/dm-crypt, LVM and a ext4 / (root) partition and an encrypted swap partition on the first disk.

Once booted into this freshly installed system you can start tweaking it.

Create one big encrypted btrfs filesystem as /data

Next we will explain how to encrypt additional disks and how to use btrfs to glue multiple differently sized physical disks together for maximal disk space, and how to use btrfs snapshots to enable as much historical backups as needed with minimal additional disk usage.

The following commands dmsetup ls -tree and dmsetup status will list what devices Device Mapper knows about. To view all physical devices and the block devices they map to, the tool lsblk is also excellent. The following command will show information about the encryption:

$ cryptsetup -v luksDump /dev/sda5
LUKS header information for /dev/sda5

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha256
Payload offset: 4096
MK bits:        512
MK digest:      aa bb cc ddaa bb cc dd ee ff aa bb cc dd ee ff aa bb cc dd
MK salt:        aa bb cc dd ee ff aa bb cc dd ee ff aa bb cc dd 
                aa bb cc dd ee ff aa bb cc dd ee ff aa bb cc dd
MK iterations:  37500
UUID:           6507313f-d061-4150-9ca2-7966b17cdce2

Key Slot 0: ENABLED
    Iterations:             149532
    Salt:                   aa bb cc dd ee ff aa bb cc dd ee ff aa bb cc dd
                            aa bb cc dd ee ff aa bb cc dd ee ff aa bb cc dd
    Key material offset:    8
    AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: ENABLED
    Iterations:             153845
    Salt:                   aa bb cc dd ee ff aa bb cc dd ee ff aa bb cc dd
                            aa bb cc dd ee ff aa bb cc dd ee ff aa bb cc dd
    Key material offset:    3536
    AF stripes:             4000
Command successful.

This is the encrypted device created by the Ubuntu installer. There is one single device, which Ubuntu assigns as a LVM device, and then splits into a root and swap partition.

sda 8:16 0 232,9G 0 disk 
├─sda1 8:17 0 487M 0 part /boot
└─sda5 8:21 0 232,4G 0 part 
 └─sda5_crypt 252:0 0 232,4G 0 crypt 
 ├─ubuntu--gnome--vg-root 252:1 0 230,5G 0 lvm /
 └─ubuntu--gnome--vg-swap_1 252:2 0 1,9G 0 lvm [SWAP]

This can be left as is, and we will create a new /data partition for our btrfs filesystem using multiple encrypted hard disks.

Encrypted disks

After adding more physical disks to the server, boot it and run the following commands to get the software part done.

First format all disks with fdisk so you have something like this:

$ fdisk -l /dev/sdb
Disk /dev/sdb: 931,5 GiB, 1000204886016 bytes, 1953525168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x8a63d658

Device     Boot  Start        End    Sectors  Size Id Type
/dev/sdb1  *      2048 1953525167     997376  999G 83 Linux

Then create a keyfile containing some random data. The keyfile will be stored on the encrypted system disk and used to open the encrypted drives.

dd bs=512 count=4 if=/dev/urandom of=/etc/cryptkey iflag=fullblock

This makes the boot process smooth: you only need to enter a password to unlock the system disk, and after that all other disks will open and mount automatically.

Then format the new partitions as encrypted LUKS devices that can be opened using the one and same keyfile:

cryptsetup -s 512 -v luksFormat /dev/sdb1 /etc/cryptkey
cryptsetup -s 512 -v luksFormat /dev/sdc1 /etc/cryptkey

Then test that you can open the devices with the command:

cryptsetup open --key-file=/etc/cryptkey --type luks /dev/sdb1 wdc1tb

The last parameter defines which name the device should have when presented by Device Mapper. In my naming scheme I use the disk brand (Western Digital) and size (1TB) so that it is easier later to somehow map which physical disk is which partition.

To have the devices opened automatically at boot, add to /etc/crypttab

wdc1tb /dev/sdb1 /etc/cryptkey luks,noearly
wdc1tc /dev/sdc1 /etc/cryptkey luks,noearly

A LUKS device can have multiple keys. There are up to 8 key slots available.

A new key for slot 7 on device sdb1 can be added like this:

sudo cryptsetup luksAddKey --key-slot 7 /dev/sdb1 -d /etc/cryptkey

Once dm-crypt/LUKS devices are set up and opened, the system will see a new block device, which you can format to btrfs with:

Create a btrfs filesystem

mkfs.btrfs -m raid1 -d raid0 /dev/mapper/wdc1tb1 /dev/mapper/wdc1tc1

Add as many devices to this command as you like. You can also later add more devices with ‘btrfs device add’. With these parameters the disks will be joined to form one big logical paritition with the size of all disks combined (RAID0). Only metadata is duplicated (RAID1).

Finally mount the new btrfs filesystem with:

mount -t btrfs -o defaults,noatime,compress=lzo /dev/mapper/wdc1tb1 /data

After this you’ll have at /data a big btrfs filesystem. Now you can start making your backups to /data using your preferred backup software. For most cases, simple rsync is enough.

Using snapshots to get some backup history

To make a read-only snapshot of all data in /data, run:

btrfs subvolume snapshot -r /data /data/snapshot.$(date +%Y-%m-%d)

Delete a snapshot with: btrfs subvolume delete snapshot.2017-08-12

To show how much disk space is used, run: btrfs qgroup show. Unfortunately on certain systems using quota groups makes the btrfs-cleaner run amok, so only enable quotas if your system is not affected by btrfs bug #116801.

Using external USB disks?

The default settings in Ubuntu are set to turn off external USB disks after a certain time of inactivity. This can be harmful is the disks are used as a part of an btrfs array. Disable autosuspend by running:

for i in /sys/bus/usb/devices/*/power/autosuspend; do echo 2 > $i; done
for i in /sys/bus/usb/devices/*/power/level; do echo on > $i; done

How to add more disks

If you ever need to extend the setup, you need to remember to:

  1. Partition the new disk with fstab.
  2. Encrypt the new disk with cryptsetup.
  3. Mount the new encrypted device with cryptsetup open.
  4. Add it to the the btrfs pool with btrfs device add /dev/sdX1 /data
  5. And finally update /etc/crypttab so that at boot the encrypted device is automatically mounted. Btrfs does not need any fstab changes as the pool will detect its members automatically.

One thought on “Secure and flexible backup server with dm-crypt and btrfs

Leave a Reply

Your email address will not be published.