Skip to content

feat(chopper): add microvm host support - #118

Merged
devusb merged 1 commit into
mainfrom
feat/microvm-framework
Aug 30, 2026
Merged

feat(chopper): add microvm host support#118
devusb merged 1 commit into
mainfrom
feat/microvm-framework

Conversation

@devusb

@devusb devusb commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Brings in microvm.nix and everything a guest needs, without declaring one. Adding a guest becomes a file in hosts/chopper/microvm/ plus an import.

The shape was worked out by actually running a guest — see #115, which adds an echoip VM on top of this and is kept as a draft for reference. Everything here was verified on chopper with that guest before being split out.

What's included

common.nix carries the settings every guest should share and reaches each VM through extraModules, so per-guest files only need what differs: the address, the tap interface, and the vsock CID.

Networking. Guests attach a tap interface to br0 through the existing vm-* match in virtualisation.nix, so no host networking changes are needed. Verified: tailscale ping from chopper to a guest resolved direct over the LAN at 1ms rather than falling back to a DERP relay.

State. Each guest gets a small volume at /var/lib for what it must not lose — ssh host keys, and the tailscale node identity, which under tailnet lock has to be signed by hand if regenerated. Bulk storage stays a per-guest concern on a nested volume, so recreating it can't take the identity with it. Volumes are only sized at creation and there is no resize upstream, so /var/lib is deliberately small and stable. The image path is relative, so each guest gets its own under /var/lib/microvms/<name>.

Secrets. ts_key reaches guests as a systemd credential rather than a share; virtiofs-mounting the host's /run/secrets is a known-broken pattern, since virtiofsd resolves the symlink once and loses the contents when sops rotates a generation. qemu opens the credential as the microvm user, so the key is granted to a tailscale-key group rather than being reowned — the same shape security.acme uses for cert access.

It's an OAuth client secret, which means nodes register ephemeral and unapproved unless told otherwise, and a tag is mandatory. Both are set explicitly.

Access. Guests register with systemd-machined for visibility through machinectl, and run sshd over VSOCK so microvm -s <name> reaches one with no network path — useful for guests that are deliberately unreachable.

Effect of merging this alone

No guests are declared, so nothing new runs. The host module creates the microvm user and the systemd templates, and ts_key moves from 0400 root:root to 0440 root:tailscale-key. Every existing consumer of that secret reads it as root, so the mode change takes nothing away from them.

Bring in microvm.nix and the plumbing a guest needs, without declaring one
yet. Adding a guest is now a file in hosts/chopper/microvm/ plus an import.

common.nix carries the settings every guest should share and reaches each VM
through extraModules, so per-guest files only need what differs: the address,
the tap interface and the vsock CID. Guests attach a tap interface to br0
through the existing vm-* match, so no host networking changes are required,
and boot against the host's nix store over virtiofs with posixAcl disabled,
since zroot has acltype=off and a read-only store carries no ACLs.

Each guest gets a small state volume at /var/lib for the things it must not
lose: ssh host keys, and the tailscale node identity, which under tailnet
lock has to be signed by hand if it is ever regenerated. Bulk storage stays
a per-guest concern and belongs on a nested volume, so recreating it cannot
take the identity with it. Volumes are only sized at creation and cannot be
resized. The image path is relative, so each guest gets its own under
/var/lib/microvms/<name>.

ts_key reaches guests as a systemd credential rather than a share, since
virtiofs-mounting the host's /run/secrets breaks whenever sops rotates it.
qemu opens it as the microvm user, so the key is readable by a tailscale-key
group instead of root alone, the way security.acme grants cert access. It is
an OAuth client secret, so nodes register ephemeral and unapproved unless
told otherwise, and a tag is mandatory.

Guests register with systemd-machined for visibility through machinectl and
run sshd over VSOCK, so `microvm -s <name>` reaches one without a network
path to it.
@devusb
devusb merged commit 1cb2abe into main Aug 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant