Launch OpenBSD vmd Guests on Demand from SSH

Abusing ssh_config's ProxyCommand 20 March 2023
Posted in: OpenBSD SSH Virtualization

I was annoyed that Other people are annoyed that Signal doesn’t exist and wrote helpful writeups. don’t run on my OpenBSD laptop so I decided to run them inside a virtual machine. Unfortunately, this laptop is underpowered by 2023 standards & persistent Linux virtual machines would be competing with all the other memory . gopls

I’d been kicking around the idea of using an ssh ProxyCommand to launch transient EC2 instances connected to long-lived EBS volumes so I figured – why not implement this for vmd hosts? I could forward Linux X11 apps to my desktop & be able to use Signal. But not Visual Studio Code; there is no way that is usable with 4GB of memory. I tried!

How does this work?

OpenSSH has the concept of session multiplexing] over a single connection. By wrapping the master connection with a ProxyCommand, I tie the master connection to the lifetime of the virtual machine. When it starts, the VM starts; when it exits the VM exits.

vmctl-ssh-wrapper.sh, when invoked by OpenSSH, parses the output of vmctl to determine if the vm is already running. If it isn’t, we try to bring it up, and schedule it for eventual shutdown – we will not shutdown vms that were manually started.

We determine the guest’s IP address by parsing the output of ifconfig tap and looking for interfaces with a “description” field matching the name of our requested virtual machine. By convention, the guest’s DHCP-assigned ip is immediately above the address assigned to the host’s tap interface.

Once we have the IP, we poll until the guest’s ssh server comes up. When it does, the socket is connected to our ssh client. When the script exits, we (may) invoke vmctl once again to schedule a shutdown.

VM Setup

vmd is the OpenBSD virtualization daemon. There’s plenty of tutorials on how to install Linux over the fake serial port, including the one I linked earlier.

A fresh wrinkle is that newer Linux kernels . MMIO is unfinished in vmd(8).” So stick to an OS release known to be working, and don’t blindly jump to the next major release.

/etc/vm.conf

vm "ubuntu" {
    memory 2G 
#    boot device cdrom
    cdrom "/home/jon/vm/mini.iso"
    disk "/home/jon/vm/ubuntu.img"
    interfaces 1
    local interface tap
    owner jon
    disable

}

SSH Client Configuration

I added a block to my ssh configuration so that requests to ubuntu.vmctl.host are be serviced by the virtual machine defined as ubuntu. The ControlPersist block allows a 10 minutes idle period (no active X or ssh clients) before shutting down.

~/.ssh/config:

Host *.vmctl.host
  ProxyCommand ~/.skel/bin/vmctl-ssh-wrapper.sh %h %p
  ControlMaster auto
  ControlPersist 10m
  ForwardX11 yes

Just Let Me Install It, Already!

Source here. This is my first shell script in a while, so gentle feedback is welcome.

This works pretty well for Signal! Who knows, maybe Slack or VSCode might even be possible on a nicer laptop.