A compilation of documentation   { en , fr }

Limit rsync accesses to a specific directory

Tags:
Created on:
Last edited on:
Author:
Xavier Béguin

The two methods of rsync remote access and their limitations

When setting up automatic data synchronisations using the well-known file synchronization command rsync between two remote hosts, it is naturally better to restrict rsync accesses to a specific directory, if possible in read-only mode, to limit the number of files that can be read or modified remotely.

rsync allows for a connection to a remote host (where the rsync command is also installed) either using a remote shell (specified using the -e/--rsh option of rsync, and whose role is to open a communication channel between the hosts), or using its daemon rsyncd.

The remote shell connection method can use the SSH shell that enables the encryption of data transferred between the hosts. However, only a connection to a rsyncd daemon and its protocol can natively restrict remote rsync accesses to a specific directory (potentially in read-only mode), and this daemon cannot encrypt the data being transferred.

To benefit from the advantages of a SSH connection while still have the possibility to limit accesses to a directory (in read-only mode if we want it so), we have the possibility to rely on the helper script rrsync provided by the rsync software.

It is naturally also possible to use a SSH tunnel to the remote host to open an encrypted connection to a rsync daemon restricted to the local network interface of the host, but this solution seems rather imperfect in my opinion and requiring more maintenance than the use of SSH and rrsync. This will therefore not be covered here.

If one still wished to use rsyncd, please note that the solution presented below can be easily adapted to the use a rsyncd daemon (see the manual for rrsync), but this aspect won't be covered here either.

Solution based on SSH and the rrsync script

The solution detailed here relies on the possibility offered by OpenSSH to force the execution of a command when opening a connection authenticated by a SSH key. The command or script having access to the original command sent by the remote rsync program, it has the ability to control it before deciding upon its execution based on the files that rsync is trying to read or write.

The script rrsync is a perl script provided with the source of the rsync software. On Debian systems, it is provided by the rsync package as /usr/share/rsync/scripts/rrsync, but on other systems the path can obviously vary. Please adapt the actual path in the examples below. If your system does not provide this script rrsync, note that it is available on the rsync project forge.

Also note that on older Debian versions, this script was provided in a compressed form as /usr/share/doc/rsync/scripts/rrsync.gz. It therefore had to be uncompressed and installed in another directory.

Generating a dedicated SSH key

In practice, we'll begin by generating a SSH key dedicated to our file synchronisations on the host that initiates the rsync transfer (which we will name host1) and copy it to the host where are located the files we want to copy (we'll name it host2). This key can be generated using a command of the following type:

host1$ ssh-keygen -f ~/.ssh/id_backups

The command ssh-keygen above will generate a new SSH key pair whose private key will be written to ~/.ssh/id_backups and the public key to ~/.ssh/id_backups.pub.

Copy the content of the public key file ~/.ssh/id_backups.pub to your clipboard, or be ready to transfer it to host2, as it will be used on this host in the next step.

Force the command executed on the remote host

We now configure host2 to authorize connections using the SSH key we've just generated on host1 and at the same time force the use of rrsync in connections authenticated using this key. In order to do so, we will:

  • edit the file ~/.ssh/authorized_keys on the account we want to use in file synchronizations on host2 and on a new line with the content of the file ~/.ssh/id_backups.pub of host1 we've just generated;
  • at the begin of this line, before the public key, add a directive command= referring to the rrsync command we want to force (separate this directive from the key by a space).

The line to add to the file ~/.ssh/authorized_keys should look like this:

command="/usr/share/rsync/scripts/rrsync -ro /srv/results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmkHG1WCjC(...) user@host1

Note that:

  • on Debian, rrsync is provided as an helper script under the path /usr/share/rsync/scripts/rrsync as used above, but you will probably have to adapt this path to the actual path of rrsync on your system;
  • /srv/results here is the directory that holds the files host1 will have access to (don't forget to adapt it to your own needs). Accesses to any file or directory not under this directory will return an error. (If the provided directory isn't an absolute path, it will be considered relative to the homedir of the account used on host2.)
  • note that in order to restrict accesses to files under /srv/results, rrsync will by default reject rsync commands using the --copy-links option to avoid copying a linked file that would be outside /srv/results (as stated in the SECURITY RESTRICTIONS section of the rrsync manual).
  • the option -ro is optional and only allows read accesses to the files of the directory. -wo can be used instead to only allow write-only accesses to these files (read accesses would then be denied). If none of these options are specified, both read and write accesses are allowed.
  • rrsync also provides the options -munge, -no-del, -no-lock and -no-overwrite described in the rrsync manual but we won't detail them here.

Note that, if the script rrsync is installed in a directory included in the PATH environment variable used by the account (for example /usr/local/bin), you won't need to use its absolute path in the directive command= of the file ~/.ssh/authorized_keys, and you could simply use command="rrsync -ro /srv/results". It is however more cautious to use the full path of the script to avoid a malicious user installing a script of the same name in a directory with higher priority in PATH that would thus replace the executed command.

Should you want to further increase the security of this SSH connection, you could use the option from= similarly to command= to define a list of hosts allowed to connect to the account using the corresponding SSH key (see the note below.)

For more information on the options command= or from= associated to a SSH key, please see:

Running the file synchronization

After having generated and authorized the SSH key as described above, the rsync transfer can be run mostly as usual, for example using the command:

host1$ rsync -e 'ssh -i ~/.ssh/id_backups' host2:/srv/results/job0/ /srv/jobs/job0

The option -e of rsync here is necessary only to specify the option -i to the ssh command to specify the (private) key to use (the SSH shell is used automatically whenever the source or destination of files to synchronise has the form [user@]host:/path). This key can naturally also be specified using the user configuration file for SSH ~/.ssh/config.