The way .ssh/authorized_keys
is typically used is not secure. Because
using it securely is hard, and dumping in passwordless ssh keys is easy. I
spent about 5 hours today locking down my authorized_keys
.
rsync
The only easy case is a rsync of a single directory. Follow these good instructions.
If you need to rsync multiple separate directories, it's easy to find
several
documents involving a
validate-rsync.sh
. Do not use, it is insecure -- it allows rsync to be
run with any parameters. Including parameters that allow the remote system
to rsync in a new ~/.ssh/authorized_keys
. Oops. (You can probably also
trick validate-rsync.sh
into running other arbitrary commands.) To be
secure, you have to check the rsync parameters against some form of
whitelist.
git
Locking down git should be easy. Use git-shell
.
Unless you also want to be able to log in to an interactive shell on the
same account. To do that, you'll need to generate a separate ssh key for
git. Both git servers I use are named git.*
, so I set it up like this in
~/.ssh/config
on the client:
Host git.*
IdentityFile ~/.ssh/id_rsa.git
Then on the server, I added the key to authorized_keys
, prefixed with this:
command="perl -e 'exec qw(git-shell -c), $ENV{SSH_ORIGINAL_COMMAND}'"
(I also tried the simpler command="git-shell -c $SSH_ORIGINAL_COMMAND"
; but
it didn't work with alioth's old version of openssh, and I didn't want
to worry about exposing SSH_ORIGINAL_COMMAND to the shell.)
Before arriving at that, I took a detour to using gitosis. It can make it impressively easy to manage locked down git over ssh, but you have to fit how it does things. Including repository layout, and a dedicated account. So I spent several hours changing my git repo layout. In the end, I decided gitosis was too complicated and limiting for what I needed, but I do recommend checking it out.
svn
Like git, this is fairly easy, since svn provides svnserve
. The svnbook
documents how to use it in .authroized_keys. Basically, just use
command="svnserve -t"
A similar approach as used for git can be used here if you want to have a dedicated ssh key that causes svnserve to be run.
d-i daily builds
d-i has a d-i-unpack-helper
that can be put in authorized_keys.
unison
Can probably be locked down similarly to rsync, but I haven't tried yet.
duplicity
The only way seems to not use duplicity over ssh at all, and instead use a different transport.
too hard
What if you want to allow locked down git, and a rsync, and maybe unison too, all to the same account? You'll end up with some nasty mismash of all of the above, and there are plenty more things using ssh as a transport that need other techniques to lock them down.
Until this becomes easier, a majority will just dump passwordless ssh keys
in ~/.ssh/authorized_keys
, creating exploitable trust paths that don't
need to exist.
I found that
command="git shell -c \"$SSH_ORIGINAL_COMMAND\""
works.command="git shell -c $SSH_ORIGINAL_COMMAND"
doesn't work because$SSH_ORIGINAL_COMMAND
will contain spaces and git-shell will see too many arguments and throw the error: "fatal: What do you think I am? A shell?".Since git 1.7.4, you can extend git-shell with custom commands by placing executables in ~/git-shell-commands (see the git-shell man page for details). The user must have read and execute permissions on this directory and (as with all commands) execute permission on the executables. According to user mimrock in answer to his "Custom commands with git-shell" question, these commands only work in interactive mode as of 1.7.10. For earlier and later versions of git, you can use a shell script to run commands in git-shell-commands in non-interactive mode:
Use this in place of git-shell in the authorize_keys "command" option. Invocation is basically the same as for git-shell. Assuming the script is named "sshsh", and following svend's example, we have:
If you'd rather not require
$SSH_ORIGINAL_COMMAND
to be quoted, use the following script:The authorized_key entry then becomes:
Any other commands you wish to allow through ssh can be created within ~/git-shell-commands as links or scripts. For example, to allow rsync as well as git:
Add that to your authorized_keys file on the host to restrict usage of the key to unison:
[Disclosure: I wrote sshdo which is described below]
There's a program called sshdo for doing this. It controls which commands may be executed via incoming ssh connections. It's available for download at:
It has a training mode to allow all commands that are attempted, and a --learn option to produce the configuration needed to allow learned commands permanently. Then training mode can be turned off and any other commands will not be executed.
It also has an --unlearn option to stop allowing commands that are no longer in use so as to maintain strict least privilege as requirements change over time.
It is very fussy about what it allows. It won't allow a command with any arguments. Only complete shell commands can be allowed.
But it does support simple patterns to represent similar commands that vary only in the digits that appear on the command line (e.g. sequence numbers or date/time stamps).
It's like a firewall or whitelisting control for ssh commands.