Skip to content

KASM Void

kasm-void is the production workspace image used by the kasm-vpn Deployment in apps/kube/kasm/. It extends kasmweb/discord with CloakBrowser so the KASM session exposes both Discord and a browser side-by-side. The browser is the canonical screen-share target inside Discord — the operator opens any URL in the bundled Chromium build and streams the window through Discord’s video feature.

  • The stock kasmweb/discord image ships only Discord; closing it leaves an empty desktop with no way to recover.
  • We need a known, reproducible browser binary inside the workspace so the Discord stream picks up consistent fonts/codecs across sessions.
  • Resource targets are higher than the stock image’s defaults — bundling lets us own the requests/limits against a single artifact instead of patching a vendor tag.

/dockerstartup/custom_startup.sh spawns three background supervisors:

LoopProcess matched (pgrep -f)Action
cloak_loopcloakbrowserRelaunches /opt/cloakbrowser/cloakbrowser $CLOAK_APP_ARGS $START_URL
discord_loop`discordelectron`
nav_shim_loopnav_shim.pyRelaunches python3 /dockerstartup/nav_shim.py

Each loop polls every 3–5 seconds. Closing the Discord window or the browser window from the desktop triggers a respawn — no manual KASM session restart needed.

The original kasmweb/discord startup script is preserved as /dockerstartup/discord_startup.sh so its arg-handling, profile setup, and maximize logic continue to work unchanged.

VariableDefaultNotes
START_URLhttps://kbve.comLaunch URL for the cloakbrowser instance
CLOAK_APP_ARGS(chromium defaults)Override the full cloakbrowser arg list
LAUNCH_DISCORD1Set to 0 to disable the Discord supervisor
LAUNCH_CLOAK1Set to 0 to disable the browser supervisor
LAUNCH_NAV_SHIM1Set to 0 to disable the URL launcher shim
NAV_SHIM_PORT9998Shim listens on this port (0.0.0.0)
CDP_PORT9222Cloakbrowser CDP port (bound to 127.0.0.1)
URL_LAUNCHER_TOKEN(k8s secret)Reuses kasm-vnc-pw value as bearer token
VNC_PW(k8s secret)Provided by the kasm Deployment
APP_ARGS(inherited)Discord-side Electron args, consumed upstream

Desktop shortcuts + helper scripts (v0.0.5)

Section titled “Desktop shortcuts + helper scripts (v0.0.5)”

The Desktop ships with launcher icons so the operator does not have to remember paths. Each .desktop entry is built into the image at /home/kasm-user/Desktop/ and the underlying scripts live in /home/kasm-user/scripts/.

IconAction
TerminalOpens xfce4-terminal (the package is now installed)
DiscordDirect launcher for /usr/share/discord/Discord (host-update skipped)
CloakBrowserDirect launcher for the bundled Chromium fork
Open URL in Browserzenity prompt → posts to the local nav_shim (falls back to a fresh cloakbrowser --new-window if the shim is down)
Reload CloakBrowserKills cloakbrowser, clears the Singleton* locks; the supervisor respawns it in ~3s
Reset DiscordStops Discord, clears Cache//Code Cache//GPUCache//Shared Dictionary/, re-seeds SKIP_HOST_UPDATE

scripts/seed-discord-config.sh writes SKIP_HOST_UPDATE: true to ~/.config/discord/settings.json before every Discord launch. The upstream Discord-on-Linux build otherwise attempts a self-update on each boot, which fails inside the gluetun-tunneled namespace and leaves the desktop without a Discord window.

cloak_loop now passes --user-data-dir=/home/kasm-user/.config/cloakbrowser --disable-software-rasterizer and clears stale SingletonLock/SingletonSocket files before each respawn. The loop also tracks an exponential backoff when the binary exits in under 2 seconds and tails the last few lines of /tmp/cloakbrowser.log so the failure is visible from kubectl logs.

The bundled browser opens whatever START_URL was at session start. To swap it without restarting the pod, the dashboard POSTs a JSON body to /dashboard/kasm/launch-url/{workspace} (axum-kbve). axum forwards to the in-pod nav_shim.py over an internal kasm-vpn-service:9998 route.

The shim is a thin HTTP front for CDP Page.navigate and only exposes that one method. Defense in depth:

LayerMitigation
Cloakbrowser CDPBound to 127.0.0.1 inside the workspace container only
Shim API surfaceOnly POST /open {url} and GET /healthz are routed; everything else 404s
Bearer authEvery request must carry the URL_LAUNCHER_TOKEN (= rotated kasm-vnc-pw)
Cilium NetworkPolicyPort 9998 is only reachable from the kbve namespace
URL policyScheme allowlist (http/https), no embedded creds, no loopback/private/link-local hosts, no .cluster.local/.svc
AuditEach launch request and shim response is captured via the existing Vector → ClickHouse project_logs pipeline

The workspace container in apps/kube/kasm/manifest/deployment.yaml is sized for Discord + a browser tab + a screenshare encoder running in parallel:

CPUMemory
requests24Gi
limits48Gi

The Gluetun sidecar keeps its own modest profile (100m/128Mi request, 500m/384Mi limit) — bumping it does not buy noticeable latency since the VPN tunnel is bandwidth-, not CPU-bound.

Terminal window
npx nx run kasm-void:container
npx nx run kasm-void:test

Published tags land at ghcr.io/kbve/kasm-void:<version>; the post-publish chore workflow syncs the Deployment image pin to match version.toml.