Using rsnapshot for push backups

In the previous section we investigated how we could perform remote backups using the rsnapshot application. Whilst the technique we demonstrated is suitable for use with systems which are always connected to the network and can be relied upon to be powered and ready at a specific time it is not really suitable for machines which are often not connected to the network or may be switched off or otherwise unavailable such as lap-top or palm-top computers. A better strategy with systems such as these is to "push" the backups to the server when the client device is known to be ready and able to do so.

In this section we shall examine how we can implement such a system using the rsnapshot application. We shall be making use of the scripts and configurations we developed in the Using rsnapshot for local backups and Using rsnapshot for remote backups chapters so if you have not followed those sections of this guide you will probably need to refer to them.

Configuring password-less login over SSH

When we configured remote backups in the previous section we used ssh to provide authentication and encryption services allowing the backup server to connect to each client and execute the rsync application as needed. As we shall be "pushing" the backups from the client to the server we now need to configure the clients to connect to the server using ssh with no password in the same, but opposite, way that we configured the server to be able to connect to the clients in the previous section.

The first step in this process is to create a new ssh key pair on the client as shown in the example below. This key pair will be used to log in to the backup server without using a password.

client ssh-keygen -t dsa -N "" -f ~/.ssh/rsnapshot_dsa

Next we need to create a new user on the backup server that the client machines will use to log in. In the example below we have called this user backup. As you can see we have specified that they will have a predefined user id, in this case 900, will not have a corresponding group created and will only be a member of the nogroup group. We have also created them a home directory which is critical if we are to log in without a password.

backup useradd --create-home --no-user-group --gid nogroup --uid 900 backup
Information:
If you have configured the backup server to be backed-up onto another system for maximum redundancy then the backup user will already exist. There is no reason to create another user to be used for "push" backups if this is the case although if you wish to create another user for administrative convenience feel free to do so.
 

Now that we have created the backup user account on the backup server we can append the public part of the key pair we created earlier to the ~/.ssh/authorized_keys file for that user account. This will enable us to log-in to that account using the private part of the key pair which we still have only on the client machine. As we may have already configured some clients, and therefore cannot simply overwrite the authorized_keys file, this becomes a two step process as shown below.

client scp ~/.ssh/rsnapshot_dsa.pub root@backup:/home/backup/new_authorized_key
backup cat /home/backup/new_authorized_key >> /home/backup/.ssh/authorized_keys
backup rm /home/backup/new_authorized_key

We can test that the configuration is correct and that password-less log-in is working for the backup user when connecting from the client to the backup server by using the command shown in the example below.

client ssh backup@backup -i ~/.ssh/rsnapshot_dsa
backup@backup exit

Restricting the backup user's abilities

Whilst granting our clients the ability to log-in as the backup user without a password is very convenient it does pose a certain security risk. Should the private part of the key pair we have configured for password-less log-in be compromised, and this is extremely likely if this is a lap-top or palm-top computer, anyone could log-in to our backup server and have full run of the system as if they were the backup user. Clearly we cannot prevent anyone with the private key from logging-in, they are as legitimate as anyone else as far as we can tell, but we can restrict what they can do once connected.

The modifications to the ~/.ssh/authorized_keys file shown below will restrict the use of password-less log-in by automatically running the command specified instead of providing full shell access. As you can see we pass the name of the client whose authorised key this entry corresponds to as the only parameter to the script so that it can use this information to load the correct configuration files later.

/home/backup/.ssh/authorized_keys
ssh-dss AAAAB3NzaC1kc3MAAACBANmhP/Q19dajVhWDfqe1GSpXZ4sTlLZBYHr85u9mqdd+tj1a/hP9AUjs8vWwrrQYZFgsQnPjQco+Q+BhRc7KcU4ESG+qrJ
command="/home/backup/do-push-rsync.sh client" ssh-dss AAAAB3NzaC1kc3MAAACBANmhP/Q19dajVhWDfqe1GSpXZ4sTlLZBYHr8

Clearly we now need to create the script we specified in the command parameter when we made the modification above. The example below, which we shall be using for testing purposes, simply runs the original command that we attempted to execute.

/home/backup/do-push-rsync.sh
#! /bin/bash

$SSH_ORIGINAL_COMMAND

We also need to make the script we just created executable as shown below.

backup chmod +x /home/backup/do-push-rsync.sh

We can now test that our password-less log-in is still functioning as expected using the example command shown below. We have specified that the hostname command should be executed on the remote machine which should provide a good indication that things worked.

client ssh backup@backup -i /root/.ssh/rsnapshot_dsa hostname
backup 

Enabling the backup user to rsync as root

Although the backup user can now connect to our server from our clients without using a password and can run, at the moment at least, any command they choose they still cannot create files with all the permissions and attributes that might be required to backup a complete system. To enable the backup user to create these files we must first install the sudo application, if it is not already installed, as shown below.

backup emerge -pv sudo
These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild      ] app-admin/sudo-1.7.4_p5  USE="pam -ldap -offensive -skey"
 
backup emerge sudo

Once the sudo application is installed its configuration can be edited using the visudo command as shown below.

backup visudo

The example entry below will allow the backup user to execute the /usr/local/sbin/push-rsync.sh script, which we shall create in a later step, as the root user without supplying a password.

/etc/sudoers.tmp
# User privilege specification
root ALL=(ALL) ALL

backup ALL=(root) NOPASSWD: /usr/local/sbin/push-rsync.sh

We can now modify the script we created earlier to use the sudo application to execute the /usr/local/sbin/push-rsync.sh script as shown below.

/home/backup/do-push-rsync.sh
#! /bin/bash

$SSH_ORIGINAL_COMMAND
sudo /usr/local/sbin/push-rsync.sh $1

The next step is to create the /usr/local/sbin/push-rsync.sh script. This script will perform two discrete tasks. The first is to copy an rsyncd.conf template file and append two additional configuration lines to this generated file specific to the client which has started execution of the script. The first of these additional lines of configuration specifies the path to the snapshot sync directory whilst the second specifies another script to be executed on completion of the sync process. We also create the snapshot directory if it does not already exist just to be on the safe side. The second task is to start the rsync application in server mode using the configuration file which was generated in the first step.

/usr/local/sbin/push-rsync.sh
#! /bin/bash

cp /etc/rsnapshot/push/rsyncd.conf.template /etc/rsnapshot/push/rsyncd.conf
echo "path = /mnt/snapshots/$1" >> /etc/rsnapshot/push/rsyncd.conf
echo "post-xfer exec = /usr/local/sbin/start-rsnapshot.sh $1" >> /etc/rsnapshot/push/rsyncd.conf
mkdir -p /mnt/snapshots/$1/.sync

rsync --server --daemon --config=/etc/rsnapshot/push/rsyncd.conf /mnt/snapshots/$1

We also need to make the script executable before it can be used as shown below.

backup chmod +x /usr/local/sbin/push-rsync.sh

Clearly the next part of the puzzle is the rsyncd.conf template file we mentioned in the previous paragraph. The example below creates a module called push which will be executed using root user and group permissions inside a chroot. It will provide write only access to a single connection at a time and will not appear in any listing requested by clients. As the path and post-xfer exec entries will be added by the script we created above they must not appear here. We also specify the files.exclude list we created in the previous chapter so that extraneous files are ignored.

/etc/rsnapshot/push/rsyncd.conf.template
[push]
uid = root
gid = root
use chroot = true
max connections = 1
read only = false
write only = true
list = false
exclude from = /etc/rsnapshot/files.exclude

Finally we need to create the /usr/local/sbin/start-rsnapshot.sh script we specified as the post-xfer exec command to be run after the synchronisation process is completed. The example below simply tests that the calling rsync process exited without issue and, if so, calls rsnapshot to perform the backup rotation.

/usr/local/sbin/start-rsnapshot.sh
#! /bin/bash

[ $RSYNC_EXIT_STATUS -eq 0 ] && rsnapshot -c /etc/rsnapshot/files.$1 push

As before it is important that we remember to make the script executable as shown below.

backup chmod +x /usr/local/sbin/start-rsnapshot.sh

Example rsnapshot configuration for push snapshots

The example file below implements a backup rotation strategy for the host named client in exactly the same was as the backup configurations we created in the previous sections. As you can see we have not specified a daily retention period firstly because it makes no sense when using push backups but also because we don't want this configuration to be run by the script we created in the first section. Instead we create a primary retention period called push which will store the last 14 push backups we performed. We also specify weekly and monthly retention periods so that these are performed automatically by the /usr/local/sbin/do-snapshots.sh script. The final trick hidden in this file is to specify the sync directory as the backup location and specify that it should be synchronised onto itself to ensure that if a sync action is ever accidentally performed nothing will be modified.

/etc/rsnapshot/files.client
# Include the common configuration for all snapshots
include_conf /etc/rsnapshot/rsnapshot.base

# Set the snapshot_root for this host
snapshot_root /mnt/snapshots/client

# Configure the retention period for backups
retain push 14
retain weekly 8
retain monthly 12

# Ensure that we never sync unless instructed to do so
sync_first 1

# Configure the backup source locations
backup /mnt/snapshots/client/.sync ./

Example client configuration for push snapshots

Assuming that we wish to backup all the files on our client machine, including system files and all user generated files, the simplest method is to perform an rsync specifying the root directory as the source and the backup server as the destination as shown below. Before we can use such a simple method we first need to create the local files.exclude file so that we do not attempt to transfer any files we do not need. An example of such a file is given below.

/root/files.exclude
lost+found
ld.so.cache
modules.conf
/dev/***
/mnt/***
/proc/***
/sys/***
/tmp/***
/usr/portage/***
/usr/src/***
/var/tmp/***
/var/log/***

The complete command required to initiate such a backup is shown below. As you can see we are specifying the exclude file we created in the previous step using the --exclude-from parameter and also instructing the rsync application to use ssh for the transport identifying ourselves using the private-key we created earlier using the -e option. The -ar parameters simply instruct the rsync application to perform an archival transfer and to recurse over the directory tree.

client rsync -ar --exclude-from=/root/files.exclude -e 'ssh -i /root/.ssh/rsnapshot_dsa' / backup@backup::push

For convenience the command can be placed in a script, which in the example below also mounts the /boot partition read-only and then un-mounts it after the snapshot is complete. This script can then be initiated manually whenever a "push" backup is desired or instead can be added to a cron job, possibly with the addition of some code to detect a connection to the home or office network, for a fully automated solution.

/usr/local/sbin/do-snapshot.sh
#! /bin/bash

mount -r /boot
rsync -ar --exclude-from=/root/files.exclude -e 'ssh -i /root/.ssh/rsnapshot_dsa' / backup@backup::push
umount /boot