* feat(isolation): add RFC 0012 backend contract Signed-off-by: Drew Newberry <385+drew@users.noreply.github.com> * refactor(isolation): name the interface crate explicitly Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): expose trusted host gateway Signed-off-by: Drew Newberry <anewberry@nvidia.com> * docs(agents): inventory the MXC driver Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): add mediated DNS transport Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): tighten interface error and digest contracts Signed-off-by: Drew Newberry <anewberry@nvidia.com> * docs(isolation): remove unrelated driver inventory Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): define capability-free launch contract Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): seal confirmed boundary state Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): validate confirmation for external backend implementations Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): clarify mediated DNS identity Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(isolation): generalize loopback connector Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(isolation): unify typed network mediation Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): bind launches to sandbox sessions Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(mxc): initialize extended sandbox status Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): add boundary protocol and Linux primitives Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): harden signals and separate process status from transport Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): validate remote confirmation through public contract Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): validate wire state and propagate snapshot failures Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(isolation): import owned agent specification explicitly Signed-off-by: Drew Newberry <anewberry@nvidia.com> * docs(isolation): describe mediated DNS channel Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): bound mediation attach without nested retries Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(isolation): generalize loopback protocol Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): add transport-neutral session authentication Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(isolation): separate sandbox backend protocol Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): harden runtime boundary controls Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): add terminal boundary operation Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): split supervisor and sandbox runtimes Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): harden boundary isolation and lifecycle ownership Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): reject private root redirects and adopt typed errors Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): preserve accept thread ownership on musl Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(sandbox): isolate credential probes from filtered threads Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): return retained exec exit status to independent waiters Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): bound network mediation and preserve socket authorization Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): bound control admission and retire stale mediation Signed-off-by: Drew Newberry <anewberry@nvidia.com> * ci(e2e): select migrated drivers per stack layer Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(sandbox): implement loopback connector Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(isolation): authenticate the Sandbox Protocol Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(supervisor): rotate launch-scoped authentication Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(sandbox): consume dedicated backend crate Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(sandbox): align topology session fixture Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): align projected bootstrap bundle Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(auth): validate refreshed credentials before rotation Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): fail closed across supervisor disconnects Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): repair rebased sandbox CI Signed-off-by: Drew Newberry <anewberry@nvidia.com> * build(runtime): publish separate sandbox and supervisor images Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(config): configure the sandbox runtime image Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(ci): validate sandbox binary linkage Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(isolation): use backend and runtime terminology Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(sandbox): use a scratch runtime image Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(ci): refresh schema and dependency policy Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(sandbox): bind reconnects to supervisor process Signed-off-by: Drew Newberry <anewberry@nvidia.com> * docs: align runtime split operational guidance Signed-off-by: Drew Newberry <anewberry@nvidia.com> * chore(security): document Kubernetes runtime RBAC Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): enforce runtime lifecycle invariants Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(compute): identify sandbox start generations Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(server): restore sandbox launch sessions Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): support authenticated runtime replacement Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(auth): bind sandbox session successors Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(auth): retry pending sandbox successors Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(vm): run the supervisor outside the guest workload Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(vm): use sandbox backend protocol Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): repair rebase integration Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): use unified build toolchain Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(vm): use sandbox runtime terminology Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(vm): own guest network bootstrap Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): expose guest init version Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): select native supervisor artifacts Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): guard guest init Linux symbols Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): scope Linux test imports Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): avoid guest interface casts Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): reconcile admitted sandbox identity Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): share resolved sandbox identity Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): surface host supervisor failures Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): include guest logs on supervisor exit Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): rotate and clean runtime generations Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): make sandbox starts generation-aware Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): rotate restored sandbox sessions Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(vm): keep shared paths in the base layer Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): bind sandbox session lineage Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(docker): isolate workloads behind the host supervisor Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(docker): rotate launch-scoped authentication Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(docker): use sandbox backend protocol Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(docker): use host networking for supervisor Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): preserve host gateway alias resolution Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(docker): use separate sandbox and supervisor images Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): restore startup validation after rebase Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(docker): name the sandbox runtime directly Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): narrow supervisor CA runtime storage Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): close companion isolation gaps Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(docker): align mediated network expectations Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(docker): exercise mediated network paths Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): attach supervisor to managed network Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): defer supervisor recovery until gateway is ready Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): make sandbox starts generation-aware Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): rotate restored sandbox sessions Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): preserve workloads during session rotation Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(docker): remove unrelated configuration RFC changes Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): bind sandbox session lineage Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(kubernetes): add proxy-pod isolation topology Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(kubernetes): use sandbox backend protocol Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): use stable sandbox service authority Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(kubernetes): split sandbox and supervisor images Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): adapt proxy pods to current runtime APIs Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(kubernetes): describe the single runtime placement Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(kubernetes): simplify sandbox orchestration Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): validate deployment prerequisites Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): update Trivy Helm profile inventory Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(kubernetes): update Trivy scan inventory count Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): reuse preloaded runtime images in e2e Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): type and clean runtime resources Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): make sandbox restarts recoverable Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): rotate restored sandbox sessions Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): preserve supervisor egress Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): bind sandbox session lineage Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(podman): adopt isolated sandbox and supervisor containers Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): stage bootstrap archives at named volume destinations Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(podman): rotate launch-scoped authentication Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(podman): use sandbox backend protocol Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(podman): use host networking for supervisor Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(podman): split sandbox and supervisor images Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): repair rebase integration Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(podman): name the sandbox runtime directly Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): provision supervisor CA runtime storage Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): address isolation review findings Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): inspect Debian supervisor provenance Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): use libpod-compatible tmpfs options Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): bind verified sandbox runtime binary Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): provide external driver data directory Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): start sandbox before joining user namespace Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): separate supervisor user namespace Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): make sandbox starts generation-aware Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): rotate restored sandbox sessions Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): bind sandbox session lineage Signed-off-by: Drew Newberry <anewberry@nvidia.com> * perf(isolation): add TCP and DNS benchmark harnesses Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(perf): align benchmark timing and supported protocols Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(perf): report TCP benchmark metrics accurately Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(perf): cancel failed worker startup Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(docker): build matching local supervisor image Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(podman): make local sandbox smoke test runnable Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): wire local sandbox runtime image Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(kubernetes): narrow sandbox service RBAC Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(ci): validate split runtime artifacts Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): harden runtime session handling Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(supervisor): add standalone network proxy role Signed-off-by: Drew Newberry <anewberry@nvidia.com> * docs(rfc): remove implementation companion notes Signed-off-by: Drew Newberry <anewberry@nvidia.com> * refactor(vm): standardize runtime release name Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(vm): pin renamed runtime artifacts Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(auth): persist sandbox runtime identity Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(runtime): restore branch validation Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(isolation): reconcile main after rebase Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(network): close unframed HTTP 1.0 responses Signed-off-by: Drew Newberry <anewberry@nvidia.com> * chore(isolation): preserve upstream OCSF updates Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(security): close credential and TLS replay paths Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(auth): make sandbox refresh retries idempotent Signed-off-by: Drew Newberry <anewberry@nvidia.com> --------- Signed-off-by: Drew Newberry <385+drew@users.noreply.github.com> Signed-off-by: Drew Newberry <anewberry@nvidia.com>
19 KiB
openshell-driver-vm
Status: Experimental. The VM compute driver is under active development.
Standalone libkrun-backed ComputeDriver for OpenShell. The gateway spawns this binary as a subprocess and talks to it over the openshell.compute.v1.ComputeDriver Unix-socket surface. openshell-supervisor runs as a native host process, while openshell-sandbox runs as capability-free PID 1 inside each microVM and applies guest-local isolation over virtio-vsock.
The driver embeds libkrun, libkrunfw, the guest OCI unpacker, the portable guest sandbox, and the custom kernel runtime. Each sandbox boots from a cached immutable bootstrap ext4 root disk plus a per-sandbox writable overlay disk. When the requested sandbox image differs from the bootstrap image, the driver prepares a read-only image ext4 disk inside a bootstrap VM and mounts that unpacked rootfs as the sandbox lowerdir.
How it fits together
flowchart LR
subgraph host["Host"]
gateway["openshell-gateway<br/>(vm::spawn)"]
driver["openshell-driver-vm<br/>libkrun"]
supervisor["openshell-supervisor<br/>host policy supervisor"]
gateway <-->|"gRPC over UDS<br/>compute-driver.sock"| driver
supervisor <-->|"authenticated gRPC<br/>policy + relay"| gateway
end
subgraph guest["Per-sandbox microVM"]
init["/srv/openshell-vm-<br/>sandbox-init.sh"]
sandbox["openshell-sandbox<br/>capability-free guest PID 1"]
workload["sandbox workload"]
init --> sandbox --> workload
end
driver -->|"CreateSandbox<br/>boots via libkrun"| guest
supervisor <-->|"mutual TLS RFC 0012<br/>over virtio-vsock"| sandbox
client["openshell-cli"] -->|"connect / exec / forward"| gateway
client -->|"CreateSandbox / Watch"| gateway
The supervisor owns gateway credentials, admitted policy, provider resolution, middleware, the network proxy, and relay registration. The sandbox receives no gateway JWT. Each VM generation receives distinct sandbox and supervisor channel keys; the guest consumes and unlinks its private bootstrap files before launching the workload.
VM-specific RFC 0012 code under src/isolation/ only chooses the vsock transport and binds immutable VM generation and image claims into the protected guest config and host descriptor. Lifecycle, authentication, process control, binary identity, forwarding, and streaming come from openshell-isolation-interface and openshell-sandbox.
Quick start (recommended)
mise run gateway:vm
First run takes a few minutes while mise run vm:setup stages libkrun/libkrunfw/umoci and mise run vm:supervisor builds the portable Linux guest sandbox plus its small static guest-init helper. The development task also builds the native host supervisor. Subsequent runs are cached.
By default mise run gateway:vm:
- Listens on plaintext HTTP at
127.0.0.1:18081. - Configures the gateway installation name as
vm-devand registers the same name with the CLI by writing~/.config/openshell/gateways/vm-dev/metadata.json. It does not modify the workspace.env. - Persists the gateway SQLite DB under
.cache/gateway-vm/gateway.db. - Places the VM driver state (per-sandbox
overlay.ext4, image cache, andrun/compute-driver.sock) under/tmp/openshell-vm-driver-$USER-vm-dev/so the AF_UNIX socket path stays under macOSSUN_LEN. - Writes
.cache/gateway-vm/gateway.tomlwith[openshell.drivers.vm].driver_dir = "$PWD/target/debug"so the freshly builtopenshell-driver-vmis used instead of an older installed copy from~/.local/libexec/openshell,/usr/libexec/openshell, or/usr/local/libexec. - Enables OTLP trace export to
http://127.0.0.1:4317only when a local collector is listening there. Otherwise, it omits the OTLP configuration to avoid repeated export failures.
For GPU passthrough (VFIO), pass -- --gpu and run with root privileges:
sudo -E env "PATH=$PATH" mise run gateway:vm -- --gpu
GPU passthrough uses VFIO and requires host support for IOMMU, root privileges
for bind/unbind operations, and a compatible sandbox image. The public GPU
overview lives in the repository README.md.
Point the CLI at the gateway with one of:
openshell --gateway vm-dev status
openshell gateway select vm-dev # then plain `openshell <command>`
Override defaults via environment:
# custom port (fails fast if in use)
OPENSHELL_SERVER_PORT=18091 mise run gateway:vm
# custom gateway installation/CLI name + namespace
OPENSHELL_VM_GATEWAY_NAME=vm-feature-a \
OPENSHELL_SANDBOX_NAMESPACE=vm-feature-a \
mise run gateway:vm
# custom sandbox image
OPENSHELL_SANDBOX_IMAGE=ghcr.io/example/sandbox:latest mise run gateway:vm
# custom bootstrap image for the VM runtime used to prepare/boot target images
OPENSHELL_VM_BOOTSTRAP_IMAGE=ghcr.io/example/bootstrap:latest mise run gateway:vm
Teardown:
rm -rf /tmp/openshell-vm-driver-$USER-vm-dev .cache/gateway-vm
rm -rf "${XDG_CONFIG_HOME:-$HOME/.config}/openshell/gateways/vm-dev"
Manual equivalent
If you want to drive the launch yourself instead of using mise run gateway:vm (i.e. tasks/scripts/gateway-vm.sh):
# 1. Stage runtime artifacts + guest sandbox into target/vm-runtime-compressed/
mise run vm:setup
mise run vm:supervisor # builds the Linux guest sandbox and static guest-init helper
# 2. Build gateway, native host supervisor, and driver
OPENSHELL_VM_RUNTIME_COMPRESSED_DIR=$PWD/target/vm-runtime-compressed \
cargo build -p openshell-gateway -p openshell-supervisor -p openshell-driver-vm
# 3. macOS only: codesign the driver for Hypervisor.framework
codesign \
--entitlements crates/openshell-driver-vm/entitlements.plist \
--force -s - target/debug/openshell-driver-vm
# 4. Start the gateway with the VM driver
mkdir -p /tmp/openshell-vm-driver-$USER-vm-dev .cache/gateway-vm
cat > .cache/gateway-vm/gateway.toml <<EOF
[openshell]
version = 2
[openshell.gateway]
compute_driver = "vm"
disable_tls = true
[openshell.drivers.vm]
default_image = "<compatible-image>"
grpc_endpoint = "http://127.0.0.1:18081"
driver_dir = "$PWD/target/debug"
state_dir = "/tmp/openshell-vm-driver-$USER-vm-dev"
EOF
target/debug/openshell-gateway \
--config .cache/gateway-vm/gateway.toml \
--compute-driver vm \
--disable-tls \
--db-url "sqlite:.cache/gateway-vm/gateway.db?mode=rwc" \
--port 18081
The gateway resolves openshell-driver-vm in this order: [openshell.drivers.vm].driver_dir, conventional install locations (~/.local/libexec/openshell, /usr/libexec/openshell, /usr/local/libexec/openshell, /usr/local/libexec), then a sibling of the gateway binary.
Gateway And Driver Configuration
Select the VM driver with --compute-driver vm, OPENSHELL_COMPUTE_DRIVER=vm, or compute_driver = "vm" in [openshell.gateway]. Configure VM-specific settings in [openshell.drivers.vm].
| Configuration key | Default | Purpose |
|---|---|---|
grpc_endpoint |
empty | Required. URL the native host supervisor uses to reach the gateway. Host loopback such as http://127.0.0.1:<port> is valid. Legacy guest aliases are normalized to host loopback. This endpoint is never sent into the VM. |
state_dir |
target/openshell-vm-driver |
Per-sandbox overlay disks, console logs, image cache, and private run/compute-driver.sock UDS. Relative paths are resolved to absolute paths at driver startup. |
driver_dir |
unset | Override the directory searched for openshell-driver-vm. |
default_image |
OpenShell base image | Sandbox image used when a create request omits one. |
bootstrap_image |
unset | VM runtime image used as the immutable bootstrap root disk. Defaults to the sandbox image when unset. |
vcpus |
2 |
vCPUs per sandbox. |
mem_mib |
2048 |
Memory per sandbox, in MiB. |
overlay_disk_mib |
4096 |
Sparse writable overlay disk size per sandbox, in MiB. |
krun_log_level |
1 |
libkrun verbosity (0-5). |
guest_tls_ca |
unset | Historical key name for the host supervisor's gateway CA certificate. Required when grpc_endpoint uses https://; never copied into the guest. |
guest_tls_cert |
unset | Historical key name for the host supervisor's client certificate; never copied into the guest. |
guest_tls_key |
unset | Historical key name for the host supervisor's client private key; never copied into the guest. |
https_proxy |
unset | Corporate forward proxy (http://host:port or https://host:port) that host control chains policy-approved TLS CONNECT egress through. Host-loopback proxy URLs work because control runs on the gateway host. |
no_proxy |
unset | Comma-separated bypass list for the corporate proxy only. OpenShell policy evaluation still applies. |
proxy_auth_file |
unset | Gateway-host path to a validated user:pass credential file. Staged root-only into the per-sandbox overlay and removed with the sandbox; credentials never enter logs or process arguments. |
proxy_auth_allow_insecure |
unset | Required with proxy_auth_file against an http:// proxy: acknowledges that Basic auth is cleartext on the connection to the proxy. |
proxy_connect_by_hostname |
unset | Send hostnames rather than validated IPs in CONNECT. Last resort for proxies whose ACLs reject IP CONNECT targets. |
proxy_ca_bundle |
unset | Gateway-host PEM CA bundle trusted for the corporate proxy and TLS-intercepted server certificates. The driver validates it and stages it at a fixed non-secret guest path in the protected overlay. Requires https_proxy. |
provider_spiffe_workload_api_tcp_endpoint |
unset | Explicit guest-reachable tcp:IP:port SPIFFE Workload API listener for provider token exchange. It requires provider_spiffe_allow_guest_tcp = true; a host UNIX socket is never silently exposed to a VM guest. |
The proxy settings are operator-owned and deployment-level: they are not accepted through template.driver_config.vm, and the driver passes them only to native host control. Every present-but-invalid value is fatal at gateway or sandbox startup rather than degrading to a direct dial.
See openshell-gateway --help for the gateway process flag surface.
Verifying the gateway
The gateway is auto-registered by mise run gateway:vm. In another terminal:
./scripts/bin/openshell status
./scripts/bin/openshell sandbox create --name demo --from <compatible-image>
./scripts/bin/openshell sandbox connect demo
First sandbox takes 10–30 seconds to boot (image fetch/prepare/cache + libkrun + guest init). If --from is omitted, the VM driver uses the gateway's configured default sandbox image. Without either --from or --sandbox-image, VM sandbox creation fails. Subsequent creates reuse the prepared image cache and create only a sparse per-sandbox overlay.ext4 before boot.
CreateSandbox accepts the sandbox quickly and continues VM provisioning in the
background. The driver publishes platform events for image resolution, cache
hits/misses, layer pulls, rootfs preparation, overlay creation, and VM launcher
startup so the CLI can show progress through the existing sandbox watch stream.
The VM driver keeps two image caches. The bootstrap cache is a controlled
rootfs.ext4 used to boot the guest init and OpenShell supervisor. The prepared
image cache is used when the requested sandbox image differs from the bootstrap
image: the host downloads registry layers into a valid OCI layout, attaches that
payload to a temporary bootstrap VM, and guest init runs umoci raw unpack onto
Linux-owned ext4 storage. The resulting disk is cached under
<state-dir>/images/<cache-id>/rootfs.ext4 and attached read-only to later
sandboxes. Local Docker images are still exported as rootfs tar archives and
prepared inside the bootstrap VM. Set OPENSHELL_VM_IMAGE_PULL_CONCURRENCY to
tune registry layer download parallelism (default 4, maximum 16).
Both caches are scoped by source image identity and OpenShell version, so an
OpenShell upgrade builds a fresh guest rootfs instead of reusing one with an old
embedded supervisor.
Each sandbox gets its own sparse writable
<state-dir>/sandboxes/<id>/overlay.ext4. Guest init mounts overlayfs as /
with the prepared image rootfs as lowerdir when present, otherwise the bootstrap
rootfs is used directly. Writes to /sandbox and other mutable paths land in
the overlay while cached image disks remain unchanged. The overlay disk must be
large enough to hold the compressed payload, unpacked rootfs, and sandbox writes
during the first prepare.
The driver also writes the accepted DriverSandbox launch request to
<state-dir>/sandboxes/<id>/sandbox.pb. If the gateway restarts, it starts a
new VM driver process. During graceful shutdown, the gateway first sends the
shared StopSandbox request for each persisted running-intent sandbox, which
stops its launcher while retaining the launch request and overlay.ext4.
After driver initialization, the gateway sends the idempotent StartSandbox
request for that retained intent. Explicitly stopped sandboxes remain excluded.
Stop writes a marker in the sandbox state directory before terminating
the launcher and releasing host GPU and network allocations. It retains
sandbox.pb, overlay.ext4, and lifecycle-extension state. Startup registers
marked sandboxes without launching compute. Start removes the marker and uses
the normal persisted restore path with the existing overlay. Delete removes the
entire sandbox state directory, including a stop marker and overlay.
The host control writes and syncs a terminal tombstone when the canonical main process exits, before it reports completion and while it retains the boundary for exec and forwarding. Driver startup reports that sandbox as terminal instead of relaunching the VM, even when the process exited successfully.
The driver embeds a platform-native host supervisor and extracts it into
<state-dir>/host-runtime. It accepts a cached binary only when its SHA-256
content matches the embedded supervisor and it remains an executable regular
file. Replacement is written and synced under a temporary name, then atomically
renamed into place. OPENSHELL_VM_SUPERVISOR_BIN remains an explicit
development override.
Logs and debugging
Raise log verbosity for both processes:
RUST_LOG=openshell_server=debug,openshell_driver_vm=debug \
mise run gateway:vm
The VM guest's serial console is appended to <state-dir>/<sandbox-id>/console.log. Sandbox IDs must match [A-Za-z0-9._-]{1,128} before the driver uses them in host paths. The gateway-owned compute-driver socket lives at <state-dir>/run/compute-driver.sock; OpenShell creates run/ with owner-only permissions and removes same-owner stale sockets. On clean shutdown, the gateway sends the managed driver SIGTERM, waits up to five seconds for it to flush telemetry and exit, then force-kills it if necessary and removes the socket. UDS clients must match the driver UID and provide the expected gateway process PID by default. Standalone same-UID UDS mode requires the explicit --allow-same-uid-peer development flag. TCP mode is disabled by default because it is unauthenticated; use --allow-unauthenticated-tcp --bind-address 127.0.0.1:50061 only for local development.
The VM serial console is appended to <state-dir>/sandboxes/<sandbox-id>/rootfs-console.log. Host-supervisor stdout and stderr are written beside it as supervisor.log and supervisor.err.log. Sandbox IDs must match [A-Za-z0-9._-]{1,128} before the driver uses them in host paths. The gateway-owned compute-driver socket lives at <state-dir>/run/compute-driver.sock; OpenShell creates run/ with owner-only permissions, removes same-owner stale sockets, and the gateway removes the socket on clean shutdown via ManagedDriverProcess::drop. UDS clients must match the driver UID and provide the expected gateway process PID by default. Standalone same-UID UDS mode requires the explicit --allow-same-uid-peer development flag. TCP mode is disabled by default because it is unauthenticated; use --allow-unauthenticated-tcp --bind-address 127.0.0.1:50061 only for local development.
Network isolation
VM sandboxes boot without a virtual NIC. The guest exposes only the protected
vsock channel used by openshell-sandbox; openshell-supervisor performs DNS,
policy evaluation, and external networking on the host. The driver does not
create TAP devices or install nftables/iptables rules.
Prerequisites
- macOS on Apple Silicon, or Linux on aarch64/x86_64 with KVM
- Rust toolchain
- e2fsprogs (
mke2fsormkfs.ext4, plusdebugfs) for root and overlay disk image creation and QEMU environment injection - Guest-sandbox cross-compile toolchain (needed on macOS, and on Linux when host arch differs from the guest):
- Matching static guest target:
rustup target add aarch64-unknown-linux-musl(orx86_64-unknown-linux-muslfor an amd64 guest) cargo install --locked cargo-zigbuildandbrew install zig(or distro equivalent).vm:supervisorcross-compiles the Linux guestopenshell-sandboxand its matchingopenshell-supervisor.
- Matching static guest target:
- mise task runner
- Docker or Podman socket on the local CLI/gateway host when building an image
before
openshell sandbox create --from <image>; the VM driver exports the image via the local container engine. Docker is tried first; if unavailable, the driver falls back to the Podman socket. On Linux, enable the Podman API socket withsystemctl --user start podman.socket ghCLI (used bymise run vm:setupto download pre-built runtime artifacts)
Releases
openshell-driver-vm is published as a normal OpenShell release artifact:
- development builds: the rolling
devrelease - tagged builds: the corresponding
v*release - runtime tarballs: the rolling
vm-runtimerelease, rebuilt on demand byrelease-vm-kernel.yml
On Debian-family Linux amd64 and arm64 systems, install.sh installs the
Debian package from the selected OPENSHELL_VERSION release tag. That package
includes openshell-gateway and openshell-driver-vm, but leaves
OPENSHELL_COMPUTE_DRIVER unset so the gateway uses its normal runtime
auto-detection. Set OPENSHELL_COMPUTE_DRIVER=vm to force the VM driver.
On RPM-family Linux x86_64 and aarch64 systems, install.sh installs the
openshell and openshell-gateway RPM packages from the selected release tag.
The RPM gateway package is configured for the Podman driver.
On Apple Silicon macOS, install.sh stages the generated openshell.rb
formula from the selected release in the nvidia/openshell Homebrew tap.
Homebrew installs openshell, openshell-gateway, and the self-contained
openshell-driver-vm with its embedded native supervisor. It ad-hoc signs the
driver with the Hypervisor entitlement in post_install and owns the brew services gateway lifecycle. The service also leaves OPENSHELL_DRIVERS unset
so driver choice remains automatic unless the user explicitly overrides it.
TODOs
- The gateway still configures the driver via CLI args; this will move to a gRPC bootstrap call so the driver interface is uniform across backends. See the
TODO(driver-abstraction)note incrates/openshell-gateway/src/vm.rs. - macOS local builds are codesigned by
tasks/scripts/gateway-vm.sh; the generated Homebrew formula signs the release tarball driver for local installs.