Title : Safely restrict commands through SSH
Author: Solène
Date  : 08 November 2018
Tags  : ssh security openbsd68 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
explained later.

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 reload
        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
parameters.

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.