Skip to content

Commit 09bd8a9

Browse files
authored
fix(vm): preserve guest TLS hostname (#1416)
1 parent f819f7d commit 09bd8a9

4 files changed

Lines changed: 54 additions & 28 deletions

File tree

crates/openshell-driver-vm/scripts/openshell-vm-sandbox-init.sh

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ BOOT_START=$(date +%s%3N 2>/dev/null || date +%s)
1717
# gvproxy's TCP/UDP/ICMP forwarder. Use this address
1818
# (or any of the host.* hostnames below) to reach a
1919
# service the host is listening on.
20-
# The host.containers.internal / host.docker.internal DNS records served
21-
# by gvproxy's embedded resolver point at 192.168.127.254. We mirror that
22-
# in /etc/hosts so the supervisor can reach the gateway even when
23-
# gvproxy's DNS is not in resolv.conf (e.g. DHCP failed and we fell
24-
# back to 8.8.8.8).
20+
# The host.openshell.internal / host.containers.internal /
21+
# host.docker.internal DNS records served by gvproxy's embedded resolver
22+
# point at 192.168.127.254. We mirror that in /etc/hosts so the supervisor
23+
# can reach the gateway even when gvproxy's DNS is not in resolv.conf
24+
# (e.g. DHCP failed and we fell back to 8.8.8.8).
2525
GVPROXY_GATEWAY_IP="192.168.127.1"
2626
GVPROXY_HOST_LOOPBACK_IP="192.168.127.254"
2727
GATEWAY_IP="$GVPROXY_GATEWAY_IP"
@@ -419,7 +419,12 @@ rewrite_openshell_endpoint_if_needed() {
419419
if [ "${GATEWAY_IP}" != "${GVPROXY_GATEWAY_IP}" ]; then
420420
fallback_ip="$GATEWAY_IP"
421421
fi
422-
for candidate in host.openshell.internal host.containers.internal host.docker.internal "$fallback_ip"; do
422+
local candidates="host.openshell.internal host.containers.internal host.docker.internal"
423+
if [ "$scheme" != "https" ]; then
424+
candidates="${candidates} ${fallback_ip}"
425+
fi
426+
427+
for candidate in $candidates; do
423428
if [ "$candidate" = "$host" ]; then
424429
continue
425430
fi
@@ -435,6 +440,11 @@ rewrite_openshell_endpoint_if_needed() {
435440
fi
436441
done
437442

443+
if [ "$scheme" = "https" ]; then
444+
ts "WARNING: could not preflight HTTPS OpenShell endpoint ${host}:${port}; preserving hostname for TLS verification"
445+
return 0
446+
fi
447+
438448
ts "WARNING: could not reach OpenShell endpoint ${host}:${port}"
439449
}
440450

crates/openshell-driver-vm/src/driver.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,11 @@ const OPENSHELL_HOST_GATEWAY_ALIAS: &str = "host.openshell.internal";
9191
/// resolves even when gvproxy's DNS is not in resolv.conf;
9292
/// * keeping a recognisable hostname makes log messages clearer than a bare
9393
/// 192.168.127.254 reference;
94-
/// * `host.docker.internal` works the same way for Docker-flavoured tooling.
94+
/// * package-managed gateway certificates include this SAN for guest mTLS.
9595
///
9696
/// Both names ultimately route through the gvproxy NAT path on
9797
/// `GVPROXY_HOST_LOOPBACK_IP` — they do **not** go through the gateway IP.
98-
const GVPROXY_HOST_LOOPBACK_ALIAS: &str = "host.containers.internal";
98+
const GVPROXY_HOST_LOOPBACK_ALIAS: &str = OPENSHELL_HOST_GATEWAY_ALIAS;
9999
const GUEST_SSH_SOCKET_PATH: &str = "/run/openshell/ssh.sock";
100100
const GUEST_TLS_CA_PATH: &str = "/opt/openshell/tls/ca.crt";
101101
const GUEST_TLS_CERT_PATH: &str = "/opt/openshell/tls/tls.crt";
@@ -3392,7 +3392,7 @@ fn merged_environment(sandbox: &Sandbox) -> HashMap<String, String> {
33923392
/// not the host's. Inside the guest we need a name that gvproxy will translate
33933393
/// into the host's loopback address.
33943394
///
3395-
/// We rewrite to `host.containers.internal`, which gvproxy's embedded DNS resolves
3395+
/// We rewrite to `host.openshell.internal`, which gvproxy's embedded DNS resolves
33963396
/// to the host-loopback IP `192.168.127.254`. gvproxy installs a default NAT entry
33973397
/// rewriting that destination to the host's `127.0.0.1` and dialing out from the
33983398
/// host process, so any port the host is listening on becomes reachable. The

crates/openshell-driver-vm/src/rootfs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ fn prepare_sandbox_rootfs(rootfs: &Path) -> Result<(), String> {
379379
.map_err(|e| format!("write sandbox rootfs marker: {e}"))?;
380380
ensure_sandbox_guest_user(rootfs)?;
381381
create_sandbox_mountpoint(&rootfs.join("sandbox"))?;
382+
create_sandbox_mountpoint(&rootfs.join("image-cache"))?;
382383
create_sandbox_mountpoint(&rootfs.join("lower"))?;
383384
create_sandbox_mountpoint(&rootfs.join("overlay"))?;
384385
create_sandbox_mountpoint(&rootfs.join("newroot"))?;
@@ -941,6 +942,7 @@ mod tests {
941942
assert!(rootfs.join("srv/openshell-vm-sandbox-init.sh").is_file());
942943
assert!(rootfs.join("opt/openshell/bin/umoci").is_file());
943944
assert!(rootfs.join("sandbox").is_dir());
945+
assert!(rootfs.join("image-cache").is_dir());
944946
assert!(rootfs.join("lower").is_dir());
945947
assert!(rootfs.join("overlay").is_dir());
946948
assert!(rootfs.join("newroot").is_dir());

e2e/rust/e2e-vm.sh

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@
2828
# `openshell` CLI with the embedded runtime.
2929
# 3. On macOS, codesigns the VM driver (libkrun needs the
3030
# `com.apple.security.hypervisor` entitlement).
31-
# 4. Starts the gateway with `--drivers vm --disable-tls
32-
# --disable-gateway-auth --db-url sqlite:<run-state>/gateway.db` on a random
33-
# free port, waits for `Server listening`, then runs the selected
34-
# Rust e2e test (`smoke` by default).
31+
# 4. Writes a per-run gateway config with `[openshell.drivers.vm]`
32+
# settings, starts the gateway with `--config <run-state>/gateway.toml`
33+
# on a random free port, waits for `Server listening`, then runs the
34+
# selected Rust e2e test (`smoke` by default).
3535
# 5. Tears the gateway down and (on failure) preserves the gateway
3636
# log and every VM serial console log for post-mortem.
3737
#
@@ -50,7 +50,7 @@ DRIVER_BIN="${ROOT}/target/debug/openshell-driver-vm"
5050
E2E_TEST="${OPENSHELL_E2E_VM_TEST:-smoke}"
5151
E2E_FEATURES="${OPENSHELL_E2E_VM_FEATURES:-e2e-vm}"
5252

53-
# The VM driver places `compute-driver.sock` under --vm-driver-state-dir.
53+
# The VM driver places `compute-driver.sock` under `[openshell.drivers.vm].state_dir`.
5454
# AF_UNIX SUN_LEN is 104 bytes on macOS (108 on Linux), so paths anchored
5555
# in the workspace's `target/` blow the limit on typical developer
5656
# machines — e.g. a ~100-char `~/.superset/worktrees/.../target/...`
@@ -68,6 +68,11 @@ SANDBOX_PROVISION_TIMEOUT=180
6868

6969
# ── Build prerequisites ──────────────────────────────────────────────
7070

71+
if [ -n "${RUSTC_WRAPPER:-}" ] && [ "${OPENSHELL_E2E_VM_ALLOW_RUSTC_WRAPPER:-0}" != "1" ]; then
72+
echo "==> Building without RUSTC_WRAPPER=${RUSTC_WRAPPER} (set OPENSHELL_E2E_VM_ALLOW_RUSTC_WRAPPER=1 to keep it)"
73+
unset RUSTC_WRAPPER
74+
fi
75+
7176
mkdir -p "${COMPRESSED_DIR}"
7277

7378
if ! find "${COMPRESSED_DIR}" -maxdepth 1 -name 'libkrun*.zst' | grep -q .; then
@@ -116,6 +121,7 @@ mkdir -p "${RUN_STATE_DIR}"
116121
GATEWAY_LOG="$(mktemp /tmp/openshell-gateway-e2e.XXXXXX)"
117122
GATEWAY_PID_FILE="${RUN_STATE_DIR}/gateway.pid"
118123
GATEWAY_ARGS_FILE="${RUN_STATE_DIR}/gateway.args"
124+
GATEWAY_CONFIG="${RUN_STATE_DIR}/gateway.toml"
119125
GATEWAY_DB="${RUN_STATE_DIR}/gateway.db"
120126

121127
# ── Cleanup (trap) ───────────────────────────────────────────────────
@@ -172,28 +178,36 @@ trap cleanup EXIT
172178

173179
echo "==> Starting openshell-gateway on 127.0.0.1:${HOST_PORT} (state: ${RUN_STATE_DIR})"
174180

175-
# Pin --driver-dir to the workspace `target/debug/` so we always pick up
181+
# Pin `driver_dir` to the workspace `target/debug/` so we always pick up
176182
# the driver we just cargo-built. Without this, the gateway's
177183
# `resolve_compute_driver_bin` fallback prefers
178184
# `~/.local/libexec/openshell/openshell-driver-vm` when present,
179185
# which silently shadows development builds — a subtle source of
180186
# stale-binary bugs in e2e runs.
181-
# --grpc-endpoint is the URL the VM driver passes into each guest as
187+
# `grpc_endpoint` is the URL the VM driver passes into each guest as
182188
# OPENSHELL_ENDPOINT. The supervisor inside the VM dials this address.
183-
# Use `host.containers.internal` rather than `127.0.0.1` so gvproxy's
184-
# host-loopback proxy carries the connection — gvproxy's bare gateway IP
185-
# (192.168.127.1) does NOT forward arbitrary host ports. The driver also
186-
# rewrites loopback URLs to this hostname as a safety net, so this matches
187-
# what the guest will actually see and aligns with `tasks/scripts/gateway-vm.sh`.
189+
# Use `host.openshell.internal` rather than `127.0.0.1` so gvproxy's
190+
# host-loopback proxy carries the connection while keeping the endpoint aligned
191+
# with package-managed gateway certificates. gvproxy's bare gateway IP
192+
# (192.168.127.1) does NOT forward arbitrary host ports.
193+
cat >"${GATEWAY_CONFIG}" <<EOF
194+
[openshell]
195+
version = 1
196+
197+
[openshell.gateway]
198+
bind_address = "127.0.0.1:${HOST_PORT}"
199+
compute_drivers = ["vm"]
200+
disable_tls = true
201+
202+
[openshell.drivers.vm]
203+
grpc_endpoint = "http://host.openshell.internal:${HOST_PORT}"
204+
driver_dir = "${ROOT}/target/debug"
205+
state_dir = "${RUN_STATE_DIR}"
206+
EOF
207+
188208
GATEWAY_ARGS=(
189-
--drivers vm
190-
--disable-tls
191-
--disable-gateway-auth
209+
--config "${GATEWAY_CONFIG}"
192210
--db-url "sqlite:${GATEWAY_DB}?mode=rwc"
193-
--port "${HOST_PORT}"
194-
--grpc-endpoint "http://host.containers.internal:${HOST_PORT}"
195-
--driver-dir "${ROOT}/target/debug"
196-
--vm-driver-state-dir "${RUN_STATE_DIR}"
197211
)
198212
e2e_write_gateway_args_file "${GATEWAY_ARGS_FILE}" "${GATEWAY_ARGS[@]}"
199213

0 commit comments

Comments
 (0)