LanternDocs

Isolation Classes

Every headless agent declares an isolation class in its agent.yaml. The class is the security boundary the workload runs behind. On Kubernetes it maps to a runtimeClassName — isolation is a tier on the pod, not a separate backend (ADR 0009).

In plain termsAn isolation class answers one question: how strong should the walls around this agent be? Code you wrote yourself gets normal walls. Code that pulls packages from the internet or was written by an LLM gets a sandbox that fakes the operating system. Truly hostile input gets a full virtual machine — its own kernel, its own everything. You declare the level once in the agent's config; if the cluster can't provide walls that strong, Lantern refuses to run the workload rather than quietly using weaker ones.
Backends climb from shared kernel to microVM, and each class has a floor A ladder of five isolation backends under a fail-closed gate. From weakest to strongest: runc with a shared namespaced kernel, serving trusted; gVisor with a user-space kernel, serving standard and untrusted; Kata with its own kernel and hypervisor per pod, serving hostile and below; Firecracker, a microVM with the Lantern harness as PID 1, session VMs and an in-guest tool runner, serving every class. Wasmtime, a capability sandbox for wasm workloads, sits apart and refuses untrusted and hostile outright. The gate at the top, choose_backend and then build_job, refuses a node whose backend cannot satisfy the class. When the hardened class is missing the workload does not run. Backends climb from shared kernel to microVM, and each class has a floor The runtime honors the trust class you declare or refuses it. Strength rises left to right; the gate never skips a rung. Fail-closed gate choose_backend() refuses a node whose backend cannot satisfy the class; build_job() re-checks before any pod is emitted. runc shared kernel gVisor user-space kernel between code and host RuntimeClass gvisor Kata own kernel + hypervisor a VM per pod RuntimeClass kata Firecracker microVM, harness PID 1 session VMs, tool runner Wasmtime capability sandbox for wasm workloads more isolation Trusted first-party code you wrote Standard the default class Untrusted user or generated code Hostile assumed to attack the host Any class every trust class fits Refuses untrusted and hostile Classes served at each rung Standard runs on gVisor; runc only if LANTERN_ALLOW_RUNC_STANDARD=1 is set. Untrusted needs a separate kernel (gVisor). When the hardened class is missing from the cluster the workload does not run. That refusal is the feature. Trust class or shared kernel Isolation backend Gate (trusted host) Refused
You declare how much you trust the code — the runtime either honors it or refuses. There is no third option.

The decision tree

Pick the least-privileged class the workload can tolerate. Walk it top to bottom and stop at the first match:

Is the code first-party and signed?                 ── yes ─▶  TRUSTED   (runc)
   │ no
Does it load packages from the internet,
or drive a browser, or run user/LLM-generated code? ── yes ─▶  UNTRUSTED (gVisor + egress-deny)
   │ no
Is the *input* adversarial / hostile?               ── yes ─▶  HOSTILE   (Kata microVM)
   │ no
                                                    ────────▶  STANDARD  (gVisor, default)

The classes

ClassRuntimeClassUse when
trustedruncSigned first-party code only. Runs on shared nodes. No untrusted package loading, no LLM-generated code path.
standardgvisorDefault. Your own code on shared, gVisor-isolated nodes. Used when the class is left unset.
untrustedgvisor + egress-denyLoads internet packages (PyPI/npm), drives a browser, or runs LLM-generated code. Adds an egress allowlist (a NetworkPolicy fence); pods run with the RuntimeDefault seccomp profile.
hostilekata-qemu (or kata-fc)Adversarial workloads. Full-kernel microVM via Kubernetes on a dedicated node pool with no co-tenancy.
wasmcrun+wasmWebAssembly workloads (or in-process Wasmtime on trusted hosts).
devcontainergvisorLong-lived workspace: a persistent pod + PVC that survives across calls.

Defaults & forced classes

  • An unset class resolves to standard.
  • Per ADR 0002, marketplace and LLM-generated bundles are to be forced to untrusted, and trusted is to require the signing key. This is policy, not yet enforced at schedule time: a request for trusted is honoured as sent.

The fail-closed gate

This is the load-bearing invariant. Untrusted and hostile code never runs in a bare pod:

  • A node may satisfy untrusted only if it advertises the gvisor RuntimeClass.
  • A node may satisfy hostile only if it advertises kata-qemu / kata-fc.
  • A node that lacks the required hardened RuntimeClass fails closed — the run is refused. It is never downgraded to runc.

The requirement is enforced in two places: the manager, which refuses the spawn when the RuntimeClass is not configured, and a pod nodeSelector (lantern.dev/runtimeclass) that only matches nodes labelled as having the handler.

Important: If your cluster has not provisioned the gvisor / kata RuntimeClasses, untrusted and hostile workloads are refused — correct, but operationally visible. The data-plane installer provisions them and a preflight check surfaces the gap before traffic.
Note: gvisor intercepts syscalls in user space — a minority of workloads hit an unimplemented syscall. Declare hostile (full kernel via Kata) for those, or get a runc-on-trusted exception via the admin override.

In a spec

Demo 02 (web-scraper) declares untrustedbecause it pulls third-party packages, and pairs it with an egress allowlist:

spec:
  isolation: untrusted
  network: allowlist_domain
  egress_rules:
    - pattern: "*.wikipedia.org"
      http_methods: ["GET"]
      rate_bps: 1048576      # 1 MiB/s

Egress enforcement and secret vending for untrusted workloads are covered in Identity & secrets.

Firecracker backend and broker mode

Where the runtime-manager uses the Firecracker backend, the workload runs in its own microVM. By default the VM has a NIC and the harness enforces the egress allowlist inside the guest. Set LANTERN_EGRESS_MODE=broker on the manager (opt-in, Firecracker only) and the VM gets no network device at all: egress leaves over vsock to a host-side broker that enforces the allowlist and injects credentials. Kata and Kubernetes backends do not support broker mode. See Egress and credentials.