Multi-tenancy is an old problem with a well-worn playbook: keep tenants from seeing each other's data, keep one tenant from starving the others, keep a compromised tenant contained. deploymill has all of that. But it also has a tenant the classic playbook never accounted for: an autonomous agent, possibly driven by an untrusted prompt, that deploys and runs code on purpose. The tenant isn't just data sitting in a row. The tenant is actively executing.
That changes the threat model. Here's how.
The code itself is the adversary
In a normal SaaS, tenant isolation is mostly about access control: tenant A's request must never read tenant B's row. We have that. Every resource carries ownership, and a request for a resource you don't own is refused, not silently empty.
But here, tenant A also gets to run arbitrary code on our hardware. So container isolation alone, the kind where a kernel exploit means game over, isn't enough comfort. Tenant workloads run with hardened, VM-grade isolation, each app effectively in its own little machine rather than sharing a kernel with its neighbors. The blast radius of "the code a tenant deployed does something hostile" has to stop at that tenant's boundary, because the hostile code is a feature of the product, not a breach of it.
The network is a wall, not a fence
The most direct thing hostile tenant code tries is the network: reach another tenant, reach the cluster's control API, reach the cloud metadata endpoint that hands out credentials, or just reach the open internet to exfiltrate or phone home. So the network is default-deny and opened by exception. Cross-tenant traffic: blocked. The internal API server: blocked. The metadata endpoint: blocked. Free-tier internet egress: blocked at the network layer, not by policy that asks nicely.
Getting that right was humbling. I've written here before about the day applying these very rules took every app offline, and about the way a deny rule can be quietly bypassed when the network rewrites a destination before the policy is evaluated. The lesson that stuck: a network control is only real once it's verified against the actual cluster, with a hard automated check for every property, including the ones that fail in non-obvious directions.
The platform is the adversary's other target
The agent doesn't only run code. It talks to the control plane. So the control plane's own surface has to assume hostile input. A couple of the defenses I care about:
Fail closed, never open. When the system can't determine which organization a request belongs to, the answer is deny, not "pick something reasonable." Ambiguity resolving to access is how cross-tenant leaks happen. Every one of those decision points is built to refuse when it isn't sure.
Validate the way an attacker probes, not the way a user types. When a tenant hands us a URL (say, to import a repo or call out), we have to stop it from being aimed at our own internals. That's a server-side request forgery guard, and the uncomfortable truth is that the naive version is always bypassable: an address can be encoded a dozen ways that look different but resolve to the same forbidden internal target. We've closed those one bypass at a time, including obscure encodings, and the posture is that any new place we accept a URL is guilty until proven safe.
The audit trail is the thing that makes it accountable
The last piece is the one that turns all of this from "trust us" into "check us." Every meaningful action, including denials, including authorization failures, is appended to a log that's attributable after the fact. When an agent does something at 3am, or tries something it wasn't allowed to, there's a record of exactly what and when. Autonomy without an audit trail is just hoping nothing went wrong. With one, isolation isn't only enforced, it's observable, which is what lets you actually run this and sleep.
None of these are exotic. VM-grade isolation, default-deny networking, fail-closed authorization, SSRF guards, an audit log. What's different is who you're defending against: not a careless tenant, but a capable, automated one you've deliberately invited to run code and drive production. Build for that adversary and the careless tenant is covered for free.
- Ryan