Launch OpenBSD vmd Guests on Demand from SSH
Abusing ssh_config's ProxyCommand
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.
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.
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.