encrypted backup appliance with raspberry pi and rsnapshot

*** I actually ended up replacing rsnapshot with obnam as detailed in this post. ***  

Today, I decided to switch up my backup routine. Before I was using a mix of bash and python scripts to backup different machines, but I wanted to set up a single appliance that could take care of all of my servers and keep backups in a centralized, encrypted location. What I ended up with is a raspberry pi with an encrypted  4TB usb drive.

First, I installed raspbian lite on the raspberry pi, then I changed the root password and removed the pi user.

Next, run updates.

apt-get update

apt-get upgrade

Install software.

apt install rsnapshot lvm2 cryptsetup

Encrypt the Storage Drive

Next, I set up the encrypted usb drive as a dm-crypt device in LUKS encryption mode.

cryptsetup -v luksFormat /dev/sda

You can also manually specify any options if you don’t like the defaults.

cryptsetup -v --cipher aes-xts-plain64 --key-size 256 --hash sha256 --iter-time 2000 --use-urandom --verify-passphrase lusFormat /dev/sda

Enter your passphrase and your drive is now encrypted.

To be of any use, you will need to mount the drive and create a filesystem.

cryptsetup open --type luks /dev/sda backups

The ‘backups’ in the above command is the name I chose for the device mapper. This will open the encrypted drive as /dev/mapper/backups and you can then create a filesystem.

mkfs.ext4 /dev/mapper/backups

Create a mount point.

mkdir -p /mnt/backups

Mount the drive.

mount -t ext4 /dev/mapper/backups /mnt/backups

At this point, your drive is encrypted and unlocked and mounted to /mnt/backups. To close the drive, unmount and close it.

umount /mnt/backups

cryptsetup close backups

Now this is all good if you just intend to unlock your drive, copy some files, and then lock it back again, but I wanted this to be an appliance. I need the drive available all the time while it is connected to the raspberry pi. To do this, I will need to add a keyfile to the system to unIock the drive when the raspberry pi boots.  The problem with this, is that the keyfile is readable by anyone on the system which means that your drive is available to anyone who can access the pi. I only really care about the drive being encrypted when it is removed from the appliance and stored elsewhere so this is fine for my purposes.

Create a folder /etc/keyfiles.

mkdir -p /etc/keyfiles

Create a keyfile.

dd if=/dev/urandom of=/etc/keyfiles/luks_key bs=1024 count=4

Set permissions on the keyfile.

chmod 0400 /etc/keyfiles/luks_key

Now add the key to the drive so that it can be unlocked with your key.

cryptsetup luksAddKey /dev/sda /etc/keyfiles/luks_key

You can dump the luks header and see that your key has been added to slot 2.

crytpsetup luksDump /dev/sda

Now, to have the disk auto unlock and mount at boot, get the disk’s UUID.

blkid

Make a new entry in /etc/crypttab using the UUID from output of the previous command.

backup UUID=b432dd1-87a3-439f-80ce-1a2cddef13a /etc/keyfiles/luks_key luks

Update the initial ramdisk.

update-initramfs -u -k all

Then test.

cryptdisks_start backups

It should report back:

* backups (started)

Make sure the device is mapped.

ls /dev/mapper

Make sure backups is listed.

Make a new entry in /etc/fstab.

/dev/mapper/backups /mnt/backups ext4 defaults 0 2

Make sure it mounts correctly.

mount -a

Now your encrypted drive will be mounted on boot. Reboot and make sure that /dev/mapper/backups is available and mounted to /mnt/backups.  

Set up backup service

Earlier, we installed rsnapshot. rsnapshot is a filesystem snapshot utility based on rsync. This will allow us to backup remote systems over ssh with rsync.

The rsnapshot config file is located at /etc/rsnaphot.conf. Edit this file and set your snapshot_root to the encrypted drive.

snapshot_root /mnt/backups/

Uncomment the external program dependencies.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# LINUX USERS:   Be sure to uncomment "cmd_cp". This gives you extra features.
# EVERYONE ELSE: Leave "cmd_cp" commented out for compatibility.
#
# See the README file or the man page for more details.
#
cmd_cp          /usr/bin/cp

# uncomment this to use the rm program instead of the built-in perl routine.
#
cmd_rm          /usr/bin/rm

# rsync must be enabled for anything to work. This is the only command that
# must be enabled.
#
cmd_rsync       /usr/bin/rsync

# Uncomment this to enable remote ssh backups over rsync.
#
cmd_ssh /usr/bin/ssh

# Comment this out to disable syslog support.
#
cmd_logger      /usr/bin/logger

# Uncomment this to specify the path to "du" for disk usage checks.
# If you have an older version of "du", you may also want to check the
# "du_args" parameter below.
#
cmd_du          /usr/bin/du

# Uncomment this to specify the path to rsnapshot-diff.
#
cmd_rsnapshot_diff      /usr/bin/rsnapshot-diff

Set up the backup retentions.
retain  hourly  24
retain  daily   7
retain  weekly  4
retain  monthly 12
Next, scroll down and set up your backup targets. To backup remote systems, you will need to have your remote servers set up with ssh keys. For more information, check [here](https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys--2).
###############################
### BACKUP POINTS / SCRIPTS ###
###############################

# example.com
backup      root@example.com:/etc/     example.com/

# example with alternate ssh port on 1234
backup      root@example.com:/etc/     example.com    +ssh_args=-p 1234

Those are the basic settings. The rest of the config file is fairly self-explanatory so make any other changes you would like and save the file. You can test your configuration with:

rsnapshot configtest

It will tell you exactly what is wrong if there are any errors.  

Automate the backups

To have the backups automatically run on a schedule, you will need to set up a systemd service and timer. Create /etc/systemd/system/rsnapshot@.service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
[Unit]
Description=rsnapshot (%I) backup

[Service]
Type=oneshot
Nice=19
IOSchedulingClass=3
ExecStart=/usr/bin/rsnapshot %I


Create /etc/systemd/system/rsnapshot-hourly.timer
[Unit]
Description=rsnapshot hourly backup

[Timer]
OnCalendar=hourly
Persistent=true
Unit=rsnapshot@hourly.service

[Install]
WantedBy=timers.target

Finally, enable and start the service and it should perform an hourly backup of all of your backup targets.

systemctl enable rsnapshot-hourly.timer

systemctl start rsnapshot-hourly.timer

You can extend this by adding daily, weekly, and monthly timers to archive longer periods of time.

To manually run a backup:

# systemctl start rsnapshot@hourly # or rsnapshot@daily, rsnapshot@weekly, ...

Restore

The backups drive will contain folders named, daily.0, daily.1 etc. The latest backup will be daily.0 and daily.6 will be a week ago. Each of these folders contain a full backup, so to restore the previous days files, just copy the contents of daily.0 back to its original location. Its as simple as that. You can find more info at rsnapshot.org