I've had an idea brewing for a while. I'd like to be able to use a single command, available on any device with SSH, to load a fresh image of any operating system with any configuration at all.

Seems crazy, but Docker's doing 95% of the work already! The docker run command will automatically download any docker images that aren't already present on the machine, and spin up a new instance of that image to use.

So that's step one: running Docker locally. The next step is to run it over SSH: I could run the full command (something like ssh user@box docker run -ti docker/image) but that seems overly verbose. Ideally I'd just be able to run ssh user@box and then enter the image I want. Luckily, this isn't too hard: after some playing around with bash aliases, python scripts on startup etc., I settled on writing my own login shell.

It turns out, this is really easy:

#!/usr/bin/env python3

import shlex
import subprocess

image_unsanitized = input("Enter docker image name: ")
image = shlex.quote(image_unsanitized)
cmd = "docker run -ti {}".format(image)

subprocess.call(cmd, shell=True)

All I'm doing here is accepting user input for a docker image name, making sure it's parsed as a single shell token (so we don't get any ; rm -rf / nonsense) and calling the docker run command.

The benefit of writing a login shell, instead of just running the Python script from a Bash startup file, is that there's no time at all during which the user could cause the program to crash and exit into a Bash shell as the "run" user. It happens that the "run" user has very few rights on the machine, but it still seems prudent to limit access to the container host. (I also considered execing the Python script, but there's still a short period of time where Bash is running and therefore an attack vector). If and when the Python script exits, the SSH session has ended: no parent Bash process to drop into by mistake.

I made this script executable with chmod +x myshell and moved it to /bin/myshell. I made sure to add it to /etc/shells, then created a new user called run and changed their shell to /bin/myshell using chsh.

To make sure I could SSH into this account, I made sure the fingerprint of my PEM file was allowed in my SSHD config.

At some point I'd like to remove the requirement for a PEM file entirely... but I'll need to think pretty carefully about the security implications. Luckily this particular instance is on a separate VPC to any other AWS project I've worked on, so a compromise wouldn't be the end of the world.

I'd also like to write a front-end interface using jquery-console and Flask (or maybe AWS Lambda...?) which would let you navigate to, say, https://debian.box.bede.io, and would present a console interface in the browser. But that's for another time!