Add vsock port wiring + WithoutSSH option#85
Merged
Conversation
Add the krun_add_vsock_port symbol to the vendored libkrun.h header and
expose it as Context.AddVsockPort in krun/context.go. This is the lowest
layer needed for the bbox-k8s ttrpc-over-vsock guest channel; higher
layers (runner.Config, microvm.WithVsock) will plumb host configuration
through to this call.
Signature matches the upstream libkrun-1.18 ABI:
int32_t krun_add_vsock_port(uint32_t ctx_id,
uint32_t port,
const char *c_filepath);
Add VsockPort{Port, SocketPath} to runner.Config and hypervisor.VMConfig
(plus the matching duplicate in runner/cmd/go-microvm-runner/main.go,
per the CLAUDE.md duplication note). The runner subprocess loops over
VsockPorts and calls Context.AddVsockPort for each entry before starting
the VM.
JSON tags match between runner.Config and the runner main.go duplicate
so the JSON round-trip is identical. The libkrun backend maps
hypervisor.VsockPort -> runner.VsockPort one-to-one.
Top-level microvm.WithVsock and the option struct field are added in
the next commit.
WithVsock(port, socketPath) wires a guest vsock port to a host UNIX socket. May be called multiple times to add multiple ports; entries are processed in order by the runner subprocess via krun_add_vsock_port. Used by the bbox-k8s ttrpc-over-vsock guest channel. WithoutSSH signals to the guest init that the in-guest SSH server should not be started. The signal is written into the rootfs at /etc/go-microvm.json (vmconfig.Config.DisableSSH) and read by the caller's init binary, which can pass guest/boot.WithoutSSH() through to boot.Run. Purely a guest-side signal; the host process and runner subprocess are unchanged. The brood-box CLI does NOT set either option, so its SSH-based path is unchanged.
Add DisableSSH field to vmconfig.Config (host->guest signal) and a matching boot.WithoutSSH() option. When set, the guest boot sequence skips: - step 8: authorized_keys parsing - step 8b: host-key loading - step 10: SSH server creation and listener All other steps (mounts, networking, hardening, capability drops, no_new_privs, seccomp) run normally. The shutdown closure is a no-op when SSH is disabled. Backward compatibility: when neither vmconfig.Config.DisableSSH nor boot.WithoutSSH is set, behavior is identical to the previous implementation. brood-box continues to work unchanged.
Covers: - microvm.WithVsock appends entries in order, defaults to empty - microvm.WithoutSSH sets disableSSH; default config leaves SSH enabled - microvm.buildVMConfig propagates DisableSSH into vmconfig.Config - toHypervisorVsockPorts maps nil/empty to nil - runner.Config JSON round-trip includes vsock_ports; omitempty when nil - VsockPort.JSON has expected snake_case keys - runner.Config JSON decodes cleanly into a struct that mirrors the duplicate Config in runner/cmd/go-microvm-runner/main.go (the explicit drift guard for the intentional duplication) - vmconfig.Config.DisableSSH round-trips through readFrom - guest/boot.WithoutSSH sets the disableSSH flag Together these guarantee: - The new public API surface behaves as documented. - Hosts that don't call WithVsock/WithoutSSH produce identical JSON to before this WP, preserving backward compatibility for brood-box. - The duplicate runner Config struct can decode every field the runner.Config struct can emit (drift guard).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two new public options on top of
microvm.Runso callers that drive theirown guest init binary (host channel = vsock IPC, not SSH) can use go-microvm
without paying for an unused SSH bring-up:
microvm.WithVsock(port, socketPath)— wires a guest vsock port to ahost UNIX socket via
krun_add_vsock_port. May be called multiple times;entries are processed in order.
microvm.WithoutSSH()— host-side flag that writesvmconfig.Config.DisableSSH = trueinto/etc/go-microvm.json. The guestinit reads it (via the matching
guest/boot.WithoutSSH()option) and skipssteps 8 (authorized_keys), 8b (host-key load), and 10 (SSH listener). All
other hardening — mounts, networking, capability drops, no_new_privs,
seccomp — runs unchanged.
These plumb cleanly through the existing layers:
microvm→hypervisor→runner→ CGOkrun, plus guest sidevmconfig→guest/boot.Driving consumer:
brood-box-k8s, which uses ttrpc-over-vsock for thehost↔guest channel and ships its own
bbox-agentinit binary. The brood-boxCLI does not call either option, so its SSH-based path is unchanged.
What's in here
5 commits, ~503 LOC across 15 files (250 LOC is tests).
77423e6krun_add_vsock_portin CGO layer (vendoredlibkrun.hextension +Context.AddVsockPort)d096934VsockPortthrough runner + hypervisor configs (incl. the duplicateConfiginrunner/cmd/go-microvm-runner/main.go)62969d4microvm.WithVsockandmicrovm.WithoutSSHpublic options525eec4DisableSSHinguest/boot.Run(skip steps 8, 8b, 10; shutdown closure becomes a no-op)7ec4267omitempty, drift guard against the duplicate runner Config struct, vmconfig round-trip, guest boot option propagationDesign notes
vsock_ports,omitempty— older runner binaries that pre-date this fieldignore an absent
vsock_portskey cleanly, so the JSON wire isforward-compat.
runner.Configstruct — the runner main binary already keepsa parallel
Configstruct (it can't import therunnerpackage without acycle). This PR keeps the duplication but adds a reflection-based test
(
runnerMainConfigMirrorinrunner/config_test.go) that fails if the twodiverge on field name/JSON tag/type.
libkrun.hvendored declaration —krun_add_vsock_portis in upstreamlibkrun 1.18 (already pinned in
versions.env); just needed in thevendored header. No ABI change.
WithoutSSH()on the host is a signal; the guestinit must choose to honor it.
guest/bootdoes. Consumers shipping acustom init binary can ignore the flag if they have other reasons to keep
SSH on.
Backward compatibility
WithVsockorWithoutSSHproduce byte-identicalJSON to before this change (both fields are
omitempty).vmconfig.Config.DisableSSHdefaults to false;guest/bootbehavior isunchanged when the flag is absent.
Test plan
task fmt— no difftask lint— 0 issuestask test-nocgo— all pure-Go packages passtask test(CGO) — requires libkrun-devel; defer to CIPer-package coverage (from the worktree run that produced these commits):
microvm 82.9%, hypervisor 94.8%.
Follow-up (NOT in this PR)
guest/boottransitively linksgolang.org/x/crypto/sshinto any consumerbinary even when
WithoutSSH()is set at runtime — the listener code isgated at runtime but still compiled in. The fix is to split
guest/boot↔guest/sshdalong a Go build tag so consumers can opt out atlink time. Tracked downstream; will land as a separate PR.
🤖 Generated with Claude Code