A console in the browser — seeing a provisioned VM's screen without leaving the portal
Context
Once the self-service catalog could create a virtual machine, there was still no way to actually see it — no screen, no console — without leaving the portal entirely and logging into the underlying virtualization platform directly, which defeats the point of a self-service experience.
The problem
Opening a remote screen from a browser, safely, through a portal that isn't the virtualization platform itself, means solving a few things together: knowing whose VM is whose (a link that, surprisingly, didn't exist anywhere yet — automation had always run under one shared service account, with no per-user trace); making sure a visitor can only ever open a console for a VM they actually own; and never handing the browser a direct, standing credential to the virtualization platform's own API.
The solution
The portal acts purely as a relay: the browser opens a normal web-socket connection to the portal, and only the portal — never the browser — holds the short-lived credential needed to open the actual remote-console session with the virtualization platform. A new, narrowly scoped access role was created specifically for this, limited to "view the screen" and "read basic state," on a virtual-machine pool dedicated to catalog items only — verified directly: a request against a VM in that pool succeeds, a request against any other machine in the homelab is refused outright.
The missing "whose VM is whose" link was added at the source: every VM created through the catalog is now tagged with its owner at creation time, read from the visitor's own authenticated session — never taken from anything the browser itself claims, which was tested explicitly by trying to forge it.
Limits were kept deliberately tight for this first version: one console session per person at a time, capped duration, a request-rate limit, and access restricted to a visitor's own machines (an administrator can reach any of them).
What went wrong along the way
The most instructive failures weren't in the protocol itself, but in timing. The remote-console protocol used here starts sending data the instant a connection opens — before a browser has necessarily finished getting ready to receive it. That exact class of bug (an event handler attached a beat too late) showed up twice, in two unrelated parts of the code, a good reminder that finding one instance of a timing bug is a good reason to go looking for the same shape of bug elsewhere, not just patching the one spot.
A second, quieter bug: a permission that lets you see an individual resource doesn't automatically let you see which group it belongs to in a combined listing — a distinction that cost a debugging session before a second, more specific permission closed the gap.
Alternatives considered
- A shared access credential reused from an existing integration, instead of a new dedicated one — rejected outright, consistent with a rule applied everywhere else in this homelab: one credential per consumer, scoped to only what that consumer needs.
- Extending console access to every machine in the homelab immediately — explicitly out of scope for this first version, to keep the blast radius of any bug limited to one dedicated pool of disposable machines while the mechanism was still new.