Restrict SSH login to a single command

One of OpenSSH coolest features is the ability to force a command for a given SSH access. You can use this to create limited access for demos, monitoring tools, administration tasks and backup process.

Command without arguments

This is the simplest case, you want to restrict the user to a single command without any arguments. This can be achieved with the command= option into the authorized_keys file like this:

command="/usr/bin/command",no-port-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB...YrAFnVw== foobar_public_key

Note that in addition to enforcing the command, i also disabled terminal and a number of advanced SSH features, such as TCP and X11 forwarding.

Command with fixed arguments

Same as before, just add the complete chain into the command= block. For example with rsync :

command="rsync --server --delete -logDtpre.iLsf . ~/foobar",no-port-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB...YrAFnVw== foobar_public_key

Or if you use rsync in daemon mode:

command="rsync --server --daemon .",no-port-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB...YrAFnVw== foobar_public_key

Command with arbitrary arguments

Authorize arbitrary arguments is a little more complicated. This is where the environment variable $SSH_ORIGINAL_COMMAND comes in. When forcing the user command, OpenSSH store the original user command into this variable. By forcing the user to a custom script shell parsing the content of the $SSH_ORIGINAL_COMMAND, you can authorize a specific command with arbitrary arguments:

#!/bin/sh
# /usr/local/bin/limitssh.sh

set -- $SSH_ORIGINAL_COMMAND
case "$1" in
  /usr/bin/command *)
    ;;
  *)
    exit 1
    ;;
esac

exec "/usr/bin/command" "$@"

Then modify your authorized_keys file like this:

command="/usr/local/bin/limitssh.sh $SSH_ORIGINAL_COMMAND",no-port-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB...YrAFnVw== foobar_public_key

It is important to be aware of potential security issues here, such as user escaping to a shell prompted from the listed command. Therefore i recommend you to always disable user terminal (no-pty option) and never use this technique with complex ‘command’ like rsync.

Multiple commands

You can modify your bash script to authorize multiple commands instead of one. Keep in mind this solution is kind of a patch-up job and you should really consider using a more robust restricted shell solution instead:

#!/bin/sh
# /usr/local/bin/limitssh.sh

set -- $SSH_ORIGINAL_COMMAND
case "$1" in
	"ps")
		ps -ef
		;;
	"vmstat")
		vmstat 1 100
		;;
	"apache stop")
		/etc/init.d/apache2 stop
		;;
	"apache start")
		/etc/init.d/apache2 start
		;;
	*)
		exit 1
		;;
esac