About the author

My name is Solène Rapenne. I like learning and sharing experiences about IT stuff. Hobbies: '(BSD OpenBSD h+ Lisp cmdline gaming internet-stuff Crossbow). I love % and lambda characters. OpenBSD developer solene@.

Contact : solene on Freenode or solene+www at dataswamp dot org

Safely allow commands through SSH

Written by Solène, on 08 November 2018.
Tags: #ssh #security #openbsd64 #highlight

sshd(8) 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.

Faster SSH with multiplexing

Written by Solène, on 22 May 2018.
Tags: #unix #ssh

I discovered today an OpenSSH feature which doesn’t seem to be widely known. The feature is called multiplexing and consists of reusing an opened ssh connection to a server when you want to open another one. This leads to faster connection establishment and less processes running.

To reuse an opened connection, we need to use the ControlMaster option, which requires ControlPath to be set. We will also set ControlPersist for convenience.

  • ControlMaster defines if we create, or use or nothing about multiplexing
  • ControlPath defines where to store the socket to reuse an opened connection, this should be a path only available to your user.
  • ControlPersist defines how much time to wait before closing a ssh connection multiplexer after all connection using it are closed. By default it’s “no” and once you drop all connections the multiplexer stops.

I choosed to use the following parameters into my ~/.ssh/config file:

Host *
ControlMaster auto
ControlPath ~/.ssh/sessions/%h%p%r.sock
ControlPersist 60

This requires to have ~/.ssh/sessions/ folder restricted to my user only. You can create it with the following command:

install -d -m 700 ~/.ssh/sessions

(you can also do mkdir ~/.ssh/sessions && chmod 700 ~/.ssh/sessions but this requires two commands)

The ControlPath variable will creates sessions with the name “${hostname}${port}${user}.sock”, so it will be unique per remote server.

Finally, I choose to use ControlPersist to 60 seconds, so if I logout from a remote server, I still have 60 seconds to reconnect to it instantly.

Don’t forget that if for some reason the ssh channel handling the multiplexing dies, all the ssh connections using it will die with it.

Benefits with ProxyJump

Another ssh feature that is very useful is ProxyJump, it’s really useful to access ssh hosts which are not directly available from your current place. Like servers with no public ssh server available. For my job, I have a lot of servers not facing the internet, and I can still connect to them using one of my public facing server which will relay my ssh connection to the destination. Using the ControlMaster feature, the ssh relay server doesn’t have to handle lot of connections anymore, but only one.

In my ~/.ssh/config file:

Host *.private.lan
ProxyJump public-server.com

Those two lines allow me to connect to every servers with .private.lan domains (which is known by my local DNS server) by typing ssh some-machine.private.lan. This will establish a connection to public-server.com and then connects to the next server.