Restricting allowed ssh command with rsync
Table of Contents
It can often be quite useful to restrict ssh
access to only allow a single command on the target host.
A major use-case for this is rsync
.
In the one direction for backing up files on the target host.
And on the other direction for deploying files on the target host (say, a static website).
Fortunately, OpenSSH already supports restricting the allowed command using command
option in the authorized_keys
file.
Unfortunately, the setup is not as simple as one would wish.
So in this article, I’ll document how the feature works, and how to set it up for rsync
.
How command
works #
When specifying command="/path/to/command parameters"
for a key in authorized_keys
this will completely overwrite the command that the source host has provided.
The original command is available in the SSH_ORIGINAL_COMMAND
environment variable.
This means that either we’re OK with completely overriding the command or we need some kind of wrapper script.
In the following we’ll go the second route since it’s more flexible and makes debugging easier.
Wrapper script restrict_ssh.sh
#
In order not to write specific wrapper scripts for different target commands, here’s a version that’s more versatile:
#!/bin/sh
for pattern in "$@"; do
if echo "$SSH_ORIGINAL_COMMAND" | grep -Eq "^$pattern$"; then
exec $SSH_ORIGINAL_COMMAND
fi
done
echo "Access denied for command '$SSH_ORIGINAL_COMMAND'"
# echo "$SSH_ORIGINAL_COMMAND" >> /tmp/original_ssh_command
exit 1
The script will expect one or more POSIX extended regular expressions as parameters and check if the full ssh command line exactly matches one of the patterns.
For safety, the ^
and $
are included in the script, so we can’t forget them when invoking the script and cause a security issue that way.
If there’s a match, the script will exec
the ssh command line, which replaces the shell by executing the first token of $SSH_SSH_ORIGINAL_COMMAND
, passing the rest of the tokens as arguments.
This means that tokens like &&
or ;
will just get passed to the program, making it more secure than without exec
.
The commented out line is useful for debugging rsync
since it will not report errors in its output on the client.
You can just put this script in /usr/local/bin/restrict_ssh.sh
(don’t forget to make it executable) and use it for all ssh command restrictions.
Restricting rsync using authorized_keys
#
Now that we have our wrapper script we can go about restricting ssh access for rsync.
The general format for the authorized_keys
file is:
[options ]keytype base64-key comment
Our restrictions go into the (optional) options
field as follows:
restrict,command="/usr/local/bin/restrict_ssh.sh 'rsync --server -[a-zA-Z.]+( --(delete|partial|log-format=X))* [.] /target/'"
The restrict
option enables all restrictions at once (for instance it disables port or agent forwarding and pty allocation).
The regular expression rsync --server -[a-zA-Z.]+( --(delete|partial|log-format=X))* [.] /target/
allows all short arguments and some long arguments and requires the last parameter to be a specific directory.
If you invoke rsync
with more long option you might need to extend the regexp.
Summary #
- Put the wrapper script in
/usr/local/bin/restrict_ssh.sh
- Use the following in the
authorized_keys
file:
restrict,command="/usr/local/bin/restrict_ssh.sh 'rsync --server -[a-zA-Z.]+( --(delete|partial|log-format=X))* [.] /<target-dir>/'" <keytype> <base64-key> <comment>