Background

Let's assume you want to mirror a directory on one system to another remote system using rsync. This is easy to do but let's also assume you want to do it in some unattended way (eg. via crontab) and you want to do it as securely as possible. This page describes how you can do this using ssh keys in a way that should be about as secure as possible without user intervention (eg. manually typing a passphrase).

Please note that we will be using empty passphrase ssh keys, which is generally a really bad idea. However, we are going to mitigate the risk by severely limiting what this key can do. Please take care that you get the authorized_keys file correct and don't blame me if you botch it.

Procedure

Here are the steps you can follow for the creation of the key and configuration of the authorized keys file to allow unattended rsync.

  1. Create A Keypair - You first need to create an openssh keypair using ssh-keygen. Just run the "ssh-keygen" command giving it the name of the key and just hit enter when asked for a passphrase. For example:
    $ ssh-keygen
    Generating public/private rsa key pair.
    Enter file in which to save the key (/u/robh/.ssh/id_rsa): /u/robh/.ssh-noautoload/unattended-rsync
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    Your identification has been saved in /u/robh/.ssh-noautoload/unattended-rsync.
    Your public key has been saved in /u/robh/.ssh-noautoload/unattended-rsync.pub.
    

    Note that we are not saving the keys in the standard .ssh directory but, rather, are saving them in a .ssh-noautoload directory. The reason for this is to prevent the gnome-keyring-daemon from automatically loading these keys. If they get auto-loaded, then you may find that any attempt to run a normal ssh between these systems is limited to only running your rdist command which you almost certainly do NOT want. You can save these keys anywhere you want other than ~/.ssh, and this example just uses the .ssh-noautoload directory.

    This will create two files, the public key (unattended-rsync.pub) and the private key (unattended-rsync), both of which we will need later.

    If you want to be able to do multiple rsync between the same 2 hosts, you can create separate keys for each rsync.

  2. Copy the Private Key To the Local System - The private key (/u/robh/.ssh-noautoload/unattended-rsync in the above example) must be accessible on the machine where you are running the rsync. On the SoIC systems, your home directory may not be accessible via cron on all systems (namely workstations outside of the machine room). As a result, you will need to copy this private key to the local drive on the system if you are using such a system. For the rest of the example, the private key file will be assumed to be at the path /some/local/directory/unattended-rsync that is assumed to be accessible via crontab.

  3. Come Up With rsync Command - You will be running some rsync command to sync files from one system to another. It is beyond the scope of this document to give a complete treatise on using rsync, but we will use the following simple example:
    $ rsync -avr /some/source/directory targethost:/some/target/directory
    
    In this example, we are syncing /some/source/directory on the local system to /some/target/directory on targethost.

  4. Determine the rsync Server Command - We are going to use the command= feature in the openssh authorized_keys file to limit how our empty passphrase key can be used. To do this, we need to determine the exact command that rsync is running on the target server. You can do this using the -v flag to ssh using something like the following:
    $ export RSYNC_RSH="ssh -v -i /some/local/directory/unattended-rsync"
    $ rsync -avr /some/source/directory targethost:/some/target/directory
    ...
    ... lots of verbose output here
    ...
    debug1: Sending command: rsync --server -vlogDtpre.iLs . /some/target/directory
    ...
    
    You will need to replace the path to the key file and the rsync command to match your specifics. But, you should see the 'Sending command:' line in the output. Save that command and we will be using it next.

  5. Set Up authorized_keys File - Armed with the public key created in step 1 (/u/robh/.ssh-noautoload/unattended-rsync.pub), the hostname of the system you are running the rsync on, and the rsync server command from the previous step, you can create a file named ~/.ssh/authorized_keys (or add a new line to that file if it already exists) on the remote system. The line will be of the form:
    from="<local hostname>",command="<rsync server command>" <contents of public key>
    
    For example, it may look like this:
    from="tank.soic.indiana.edu",command="rsync --server -vlogDtpre.iLs . /some/target/directory" ssh-rsa AAAAB3NzaC1yc2EA...rest of public key here...
    
    What this does is severely limit what this empty passphrase key can do. It can only be used from the specified host (eg. tank.soic.indiana.edu) and it can only be used to run the exact rsync server command specified.

  6. Set Up rsync Script - You can then run the rsync via a script that looks like this:
    #!/bin/bash
    export RSYNC_RSH="ssh -i /some/local/directory/unattended-rsync"
    rsync -avr /some/source/directory targethost:/some/target/directory
    

Troubleshooting

There are a number of things that can go wrong, but here are the most common mistakes:

  1. Improper rsync server command - The rsync server command you specify with the command= directive in the authorized_keys file must exactly match what rsync would normally run. When you specify this command=, ssh will completely ignore what rsync is telling it to run and only run that exact command. So, if you make any changes to your rsync command you must make the corresponding change to your command= directive.

  2. Authentication Failures - You should run the rsync script manually to verify that it works. If you normally have ssh keys loaded (via the ssh-agent) it may work for you from the command line but fail from crontab. You should try it in an environment where you don't have any keys loaded to be sure it runs without asking you for a passphrase.

  3. Cut/Paste Errors - In step 5 above, you created an entry in your authorized_keys file that contained the contents of the public key file. Note that this must all be on a single line. If you crated that line by cutting/pasting the public key, make sure you didn't introduce any stray newlines in the process.