Title : Safely restrict commands through SSH
Date : 08 November 2018
Tags : ssh security openbsd highlight
[sshd(8)](https://man.openbsd.org/sshd) has a very nice feature that is often
overlooked. That feature is the ability to allow a ssh user to run a specified
command and nothing else, not even a login shell.
This is really easy to use and the magic happens in the file
**authorized_keys** which can be used to restrict commands per public key.
For example, if you want to allow someone to run the "uptime" command on your
server, you can create a user account for that person, with no password so the
password login will be disabled, and add his/her ssh public key in
~/.ssh/authorized_keys of that new user, with the following content.
restrict,command="/usr/bin/uptime" ssh-rsa the_key_content_here
The user will not be able to log-in, and doing the command `ssh remoteserver`
will return the output of `uptime`. There is no way to escape this.
While running uptime is not really helpful, this can be used for a much more
interesting use case, like allowing remote users to use **vmctl** without
giving a shell account. The vmctl command requires parameters, the configuration
will be slightly different.
restrict,pty,command="/usr/sbin/vmctl $SSH_ORIGINAL_COMMAND" ssh-rsa the_key_content_here"
The variable *SSH_ORIGINAL_COMMAND* contains the value of what is passed as
parameter to ssh. The **pty** keyword also make an appearance, that will be
If the user connects to ssh, vmctl with no parameter will be output.
$ ssh remotehost
usage: vmctl [-v] command [arg ...]
vmctl console id
vmctl create "path" [-b base] [-i disk] [-s size]
vmctl load "path"
vmctl log [verbose|brief]
vmctl reset [all|vms|switches]
vmctl show [id]
vmctl start "name" [-Lc] [-b image] [-r image] [-m size]
[-n switch] [-i count] [-d disk]* [-t name]
vmctl status [id]
vmctl stop [id|-a] [-fw]
vmctl pause id
vmctl unpause id
vmctl send id
vmctl receive id
If you pass parameters to ssh, it will be passed to vmctl.
$ ssh remotehost show
ID PID VCPUS MAXMEM CURMEM TTY OWNER NAME
1 - 1 1.0G - - solene test
$ ssh remotehost start test
vmctl: started vm 1 successfully, tty /dev/ttyp9
$ ssh -t remotehost console test
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?
The ssh connections become a call to vmctl and ssh parameters become vmctl
Note that in the last example, I use "ssh -t", this is so to force allocation
of a pseudo tty device. This is required for vmctl console to get a fully
working console. The keyword **restrict** does not allow pty allocation, that
is why we have to add **pty** after restrict, to allow it.