FreelancePHP

The thoughts, opinions and sometimes the rants of Mark Evans

Secure File Synchronisation With SSH and Rsync

| Comments

Quite often I want to be able to do a backup of some files / folders on a remote server. So far I have been doing this quite successfully using public/private key authentication with scp and then entering my passphrase when prompted.

This has worked pretty well for me but now I want to automate this with a cron job. Since I am human and quite forgetful automating this will ensure that I never again fail to complete a backup of some critical data. A problem now arises however in how to secure this. I don’t want to have to store a password or passphrase in the crontab so I need to find a new way.

After some googling and some experimentation I finally have working something which I am sure real sysadmins have been aware of for a while and that is the ability to restrict a ssh via public/private key to specific commands.

In order to get this to work for myself I did the following steps.

Firstly I created a new passphrase-less rsa key

ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa): /home/username/.ssh/rsync_backup
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/username/.ssh/rsync_backup.
Your public key has been saved in /home/username/.ssh/rsync_backup.pub.

Next I copied the public key to the server I wanted to backup and added this to the /home/remoteuser/.ssh/authorized_keys

I then tested to make sure that I could login to the remote server using ssh

ssh -i /home/username/.ssh/rsync_backup remoteuser@remotehost

Once I had confirmed that it was all working with ssh the next step was to lock down the key to a specific IP address. Since this was an internal system I knew which IP address would be used to connect.

I edited the /home/remoteuser/.ssh/authorized_keys to look like the following

from="192.168.1.50" ssh-rsa 

I then tested ssh login again to make sure I didn’t mess anything up

ssh -i /home/username/.ssh/rsync_backup remoteuser@remotehost

All was still working. To play devils advocate I also tried to connect from a different IP and my connection was denied successfully.

Next up I needed to check on connection what command was being called to ensure that only rsync was permitted. After a lot of googling around I came across the following

#!/bin/sh
logfile=/var/log/rsync_backup.log
case "$SSH_ORIGINAL_COMMAND" in
*\&*)
echo `date` "- SSH connection rejected" >> $logfile
;;
*\(*)
echo `date` "- SSH connection rejected" >> $logfile
;;
*\{*)
echo `date` "- SSH connection rejected" >> $logfile
;;
*\;*)
echo `date` "- SSH connection rejected" >> $logfile
;;
*\<*)
echo `date` "- SSH connection rejected" >> $logfile
;;
*\`*)
echo `date` "- SSH connection rejected" >> $logfile
;;
*\|*)
echo `date` "- SSH connection rejected" >> $logfile
;;
rsync\ --server*)
{
  echo `date` "- SSH connection accepted" >> $logfile
  $SSH_ORIGINAL_COMMAND
}
;;
*)
echo `date` "- SSH connection rejected" >> $logfile
;;
esac

This script checks the SSH command to be run and rejects it if anything other than rsync is being used.

I once again edited the /home/remoteuser/.ssh/authorized_keys to add the command restriction so that it looked like the following

from="192.168.1.50", command="/home/remoteuser/check-rsync.sh" ssh-rsa 

I then checked to see what would happen if I tried to login using ssh

ssh -i /home/username/.ssh/rsync_backup remoteuser@remotehost

This time my connection was denied. Checking my logfile I saw the following entry

Sun Feb 6 00:51:58 GMT 2011 - SSH connection rejected

Now the final test… could I use the public/private key to connect and run the rsync command. To do this I ran

rsync -avz -e "ssh -i /home/username/.ssh/rsync_backup" remoteuser@remotehost:/home/remoteuser/datatobackup /home/username/remotehost

And low and behold my files were downloaded

receiving file list ... done
home/remoteuser/datatobackup/file1.txt
home/remoteuser/datatobackup/file7.txt
sent 98 bytes  received 2331 bytes  1619.33 bytes/sec
total size is 32663  speedup is 13.45

Job Completed. I can now just set this up as a cron job to run every night and sleep easy in the knowledge that all the valuable data I need is safely backed up.

I would love to hear any feedback on this solution and any tips for ways to improve it.

Comments