OpenSSH provides a way to limit what a user is able to execute on a remote host. This feature can be used to create users with limited rights for demos, monitoring tools, system administration tasks…
This post shows how to limit a hypothetical user account called
foo on a host named
bar, so that it can only execute the command
1 User account configuration
The command restriction functionality is part of the public key authentication method of OpenSSH. To enable it, a
/home/foo/.ssh/authorized_keys file must be created on
bar. It contains a list of public keys allowed to login into that user account:
OPTIONS KEY_TYPE KEY COMMENT ... OPTIONS KEY_TYPE KEY COMMENT
We first need to create a key pair that will be used to login into the limited account:
This will ask for a filename and a passphrase, and will create two files,
FILENAME.pub. You need to copy those to every machine you want to login from.
Then, we have to configure the
authorized_keys file on the remote host.
COMMENT are the contents of
FILENAME.pub, verbatim. For the options field, you probably want:
If the command you want to allow does not require a terminal, you may also add
no-pty to the
From now on, you can login into
[email protected] with this command, using the passphrase you provided and irrespective of
foo‘s password on
$ ssh -i FILENAME [email protected]
2 Command without arguments
In the simplest case, the user is only allowed to execute a single command, without any arguments. This can be achieved with a
command option that points to the executable.
In our example, the contents of the
/home/foo/.ssh/authorized_keys file in
bar should be:
command="./nuke",no-port-forwarding,no-x11-forwarding,no-agent-forwarding KEY_TYPE KEY COMMENT
If a relative path is used (like in the example), it refers to the (remote) home directory of the user.
3 Command with fixed arguments
The argument to the
command option is interpreted by whatever shell is configured for the user. It can thus contain arguments to the executable, shell variables, use
PATH expansion, etc. However, it may be tricky to get quoting properly with arguments containing spaces or other special characters.
In this example, the
nuke command gets the shell configured for the remote user as argument:
command="./nuke $SHELL",no-port-forwarding,no-x11-forwarding,no-agent-forwarding KEY_TYPE KEY COMMENT
4 Command with arbitrary arguments
If the user should be able to specify arbitrary arguments for the allowed command, one way to do it is using the
authorized_keys file passes the final arguments of the
ssh call to
command="./nuke $SSH_ORIGINAL_COMMAND",no-port-forwarding,no-x11-forwarding,no-agent-forwarding KEY_TYPE KEY COMMENT
To use this functionality, the user invokes
ssh with the desired arguments for the restricted command at the end:
$ ssh [email protected] arg1 arg2 ...
However, the way the restricted command uses its arguments should be audited, since this technique could pose security risks.
Excelent, the SSH_ORIGINAL_COMMAND trick is what I need.
Thank you very much.
Nice blog post! Just a question on the security risks of $SSH_ORIGINAL_COMMAND:
Do you know of any way to restrict $SSH_ORIGINAL_COMMAND to a certain set of characters, or even sandbox the execution? For example, I would just to a “cd ~/$SSH_ORIGINAL_COMMAND && git pull”, but this construct is vulnerable to injection, whether you quote it or not. :-(
Peter, those values are environment variables and are not interpolated by the SSH daemon before running the command, so you _can_ safely use them simply by quoting them e.g. you might make it so that the command looked something like this:
[[ “$SSH_ORIGINAL_COMMAND” =~ ^(a_safe_folder|another_safe_directory)$ ]] && cd “$SSH_ORIGINAL_COMMAND” && git pull
However, since those are just environment variables, my personal preference is to not try and shove a long script into the command parameter and instead do something simpler like command=”/path/to/script” then put all of the logic into the language of your choice be it Bash, Python, Perl, etc. into that one file. This also enables you to lock down the account that’s being SSH’d into by changing that user’s shell to something like /bin/sh to reduce the likelihood of being impacted by something like the “shellshock” bug. There are also various restricted shells out although some are not without their own vulnerabilities and issues.
I’ve found another interesting article about using the SSH authorized_keys file’s command feature. What’s particularly interesting, it shows how to experiment with the command using e.g. the `env` command to understand the feature better.