Passphrase-less SSH keys allow one to automate remote tasks by not requiring user intervention to enter a passphrase to decrypt the key. While this is convenient, it poses a security risk, as the plain key can be used by anyone who gets hold of it to access the remote server. To this end, the developers of SSH made it possible to restrict, via .ssh/authorized_keys, the commands that can be executed by specific keys. This works great for simple commands, but because using rsync requires executing remote commands with different arguments on the remote end, depending on the invocation on the local machine, it gets quite complicated to properly restrict it via .ssh/authorized_keys.
Luckily, the developers of rsync foresaw this problem and wrote a script called rrsync (for restricted rsync) specifically to make it easier to restrict keys to be used only for rsync via .ssh/authorized_keys. If you have rsync installed, rrsync should have been distributed alongside it. On Debian/Ubuntu machines, it can be found under /usr/share/doc/rsync/scripts/rrsync.gz. If you cannot find it there, you can download the script directly from here. On the remote machine, copy the script, unpack it if needed, and make it executable:
user@remote:~$ gunzip /usr/share/doc/rsync/scripts/rrsync.gz -c > ~/bin/rrsync
user@remote:~$ chmod +x ~/bin/rrsync
On the local machine, create a new SSH key and leave the passphrase empty (this will allow you to automate the rsync via cron). Copy the public key to the remote server.
user@local:~$ ssh-keygen -f ~/.ssh/id_remote_backup -C "Automated remote backup"
user@local:~$ scp ~/.ssh/id_remote_backup.pub user@remote:~/
Once the public key is on the remote server, edit ~/.ssh/authorized_keys and append the public key.
user@remote:~$ vim ~/.ssh/authorized_keys
(Vim tip: Use :r! cat id_remote_backup.pub to directly insert the contents of id_remote_backup.pub into a new line). Now prepend the following to the newly added line:
command="$HOME/bin/rrsync -ro ~/backups/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding
The command="..." restricts access for that public key by executing the given command and disallowing others. All the other no-* stuff further restricts what can be done with that particular public key. As the SSH daemon will not start the default shell when accessing the server using this public key, the $PATH environment variable will be pretty empty (similar to cron), so you should specify the full path to the rrsync script. The two arguments to rrsync are -ro, which restricts modifying the directory (drop it if you want to upload stuff to the remote directory), and the path to the directory you want to enable remote access to (in my example ~/backups/).
The result should look something like:
command="$HOME/bin/rrsync -ro ~/backups/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-rsa AAA...vp Automated remote backup
After saving the file, you should be able to rsync files from the remote server to the local machine, without being prompted for a password.
user@local:~$ rsync -e "ssh -i $HOME/.ssh/id_remote_backup" -av user@remote: etc2/
Two things need to be noted:
- You need to specify the passphrase-less key in the
rsynccommand (the-e "ssh -i $HOME/.ssh/id_remote_backup"part). - The remote directory is always relative to the directory given to
rrsyncin the~/.ssh/authorized_keysfile.
Thank you for this tutorial. I found it very useful. Also quite rare: there’s very few guidelines out there about how to allow a third party to access a single directory. This was the only usefu one I found.
TRiG.
It may also be useful to pass
-o IdentitiesOnly=yes, which instructs ssh not to use the agent, in rsync’s-eargument.Thanks. This was very useful. This site was also useful and prvided the other half of what i needed.
https://www.v13.gr/blog/?p=216#comment-75138
A very nice write up and I thank you!
VIM tip: just use
:r id_remote_backup.pub. There is no need for the exclamation mark to run ‘cat’, as ‘r’ by itself will already read the file.I found it helpful to specify the single
restrict' option rather than a bunch ofno-*’ options (which might not be enough in the future, as new restrictions become necessary); perhaps `restrict’ is relatively new.Anyway, thanks a lot!
man sshd' describes this stuff in section "AUTHORIZED_KEYS FILE FORMAT", but it is nice to see a concrete example, especially one that deals withrrsync’ explicitly.Thanks for this tutorial! Exactly what I needed! 🙂
Two annotations have to be made:
1:
The argument “command=…” in authorized_keys has to be put in front of the other arguments. I tried different varieties, but neither worked.
2:
When you try to “ssh user@remotemachine -i keyfile”, you are presented this message:
PTY allocation request failed on channel 0
/home/backup/bin/rrsync: Not invoked via sshd
Use ‘command=”/home/backup/bin/rrsync [-ro|-wo] SUBDIR”‘
in front of lines in /home/backup/.ssh/authorized_keys
Connection to 192.x.x.x closed.
I consider this a bit of a security breach, because of the information being given, e.g. the internal IP, the directory structure and the involved files. Can this message be suppressed somehow?
yeah definitely not a security breach. There’s no information there that’s useful to an attacker.
Unfortunalty doesn’t work when using internal-sftp. Any idea to have sftp AND rsync WITHOUT a interactive shell ? All solutions that I have seen seems to be outdated… (scponly, rssh, …)
Thank you for taking the time to publish this guide!