This puts the remote server at risk because if the originating server is compromised an attacker would easily gain access to the remote server as well. To reduce the damage of a compromised private key, one often restricts the access of the key to the minimum required to get the script's job done. This can be accomplished by using SSH-key options in the authorized_keys file.
Example:
from="fromserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="/home/user/bin/script.sh" ssh-rsa AAAAB3NzA..Dxq= user@fromserver.example.com
This is quite effective, and restricts the attacker to executing the specified forced command, and only from a specified host, with no terminal or X11 access.
Other times one needs to do a sync job using rsync. Let's see how that works out with the above scheme.
Example command:
/usr/bin/rsync /some/dir/ user@remote.example.com:/some/other/dir/
Example entry in authorized_keys:
from="fromserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="/usr/bin/rsync" ssh-rsa AAAAB3NzA..Dxq= user@fromserver.example.com
Trying that, you'll soon noticed that all your command line arguments are ignored, and you'll get the help text from rsync as output. The forced command option does not allow arbitrary command line arguments to the command.
There is a workaround by using the
$SSH_ORIGINAL_COMMAND
environment variable that the ssh program creates. The problem with that is that you'll need a wrapper script to deal with the arguments because it will have the executable twice in the argument list:from="fromserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="/usr/bin/rsync $SSH_ORIGINAL_COMMAND" ssh-rsa AAAAB3NzA..Dxq= user@fromserver.example.com
This will produce this command:
/usr/bin/rsync /usr/bin/rsync /some/dir/ user@remote.example.com:/some/other/dir/
A solution to this is the wrapper script that interprets the environment variable and executes the correct command:
#!/bin/bash case $SSH_ORIGINAL_COMMAND in "/usr/bin/rsync "*) $SSH_ORIGINAL_COMMAND ;; *) echo "Permission denied." exit 1 ;; esac
This adds complexity and requires a script to be installed on the remote server. It is also possible to achieve a similar solution without the wrapper script:
from="fromserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="/usr/bin/rsync ${SSH_ORIGINAL_COMMAND#* }"
Notice the
'#* '
right after SSH_ORIGINAL_COMMAND
. The #
modifier in bash is used to remove the smallest prefix pattern, and so '#* '
will remove everything up until and including the first space.There are some security concerns however. For instance this would be possible from the machine "fromserver.example.com":
rsync authorized_keys user@server:/home/user/.ssh/authorized_keys
That would allow an attacker to swap the file with anything, and thus the security is easily breached. To prevent that, make the file owned by root and remove write permissions on the file, or make it immutable with chattr.
chown root:root /home/user/.ssh/authorized_keys
chmod a-w /home/user/.ssh/authorized_keys
chattr +i /home/user/.ssh/authorized_keys
Allowing the unrestricted use of the rsync program will allow an attacker to replace any files the user has write access to. Beware that there probably are other holes in this that I didn't find.