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).
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
| Class | RuntimeClass | Use when |
|---|---|---|
trusted | runc | Signed first-party code only. Runs on shared nodes. No untrusted package loading, no LLM-generated code path. |
standard | gvisor | Default. Your own code on shared, gVisor-isolated nodes. Used when the class is left unset. |
untrusted | gvisor + egress-deny | Loads 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. |
hostile | kata-qemu (or kata-fc) | Adversarial workloads. Full-kernel microVM via Kubernetes on a dedicated node pool with no co-tenancy. |
wasm | crun+wasm | WebAssembly workloads (or in-process Wasmtime on trusted hosts). |
devcontainer | gvisor | Long-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, andtrustedis to require the signing key. This is policy, not yet enforced at schedule time: a request fortrustedis 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
untrustedonly if it advertises thegvisorRuntimeClass. - A node may satisfy
hostileonly if it advertiseskata-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.
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.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/sEgress 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.