Why multi tenant AI agent isolation is hard
Multi tenant AI agent isolation is the problem of running agents for many customers on shared infrastructure without ever letting one customer's agent see, reach, or affect another's. It sounds like a solved problem, because we have run multi-tenant SaaS for years. Agents make it harder. An agent is not a passive request handler. It holds credentials, executes code, makes outbound network calls, and follows instructions that can come from untrusted input. A single container per tenant feels like enough. It is not, and betting your customers' data on that assumption is how tenancy breaches happen.
The reason agents raise the stakes: a normal web request cannot be talked into attacking your infrastructure. An agent can. Feed it a poisoned web page or a malicious document and it might try to scan the internal network or read a neighbor's files. That risk is covered broadly in AI agent security risks; this piece zooms into the tenancy boundary specifically. If "agent" is still fuzzy, the plain-English definition is the place to start.
Why a container per tenant is not enough
The instinct is reasonable: give each tenant a container and you are done. Here is why that single layer leaks.
Containers share a kernel. A container is process isolation, not a security boundary against a determined attacker. A kernel vulnerability or a container escape crosses it. It was never designed as a hard wall between hostile tenants.
The network is usually wide open. By default, containers on the same host or cluster can often reach each other over the network. Tenant A's agent can send packets to tenant B's agent unless you explicitly forbid it.
Shared backends leak quietly. If all tenants hit one database, isolation depends entirely on every query carrying the right tenant filter. One forgotten
WHERE tenant_id = ?and the wall is gone, with no crash to warn you.Credentials sprawl. If a single service account can touch every tenant's resources, a compromise anywhere is a compromise everywhere.
None of these are exotic. They are the default state of a naive setup, which is exactly why "just use containers" fails in practice.
Isolation is layered, not a single wall
Real multi tenant AI agent isolation is defense in depth. No single mechanism is trusted to hold alone; each one assumes the others might fail. Think in layers.
Compute isolation. Each tenant's agent runs in its own namespace, with resource limits so one tenant cannot starve others, and ideally a stronger sandbox than a shared-kernel container for untrusted code.
Network isolation. Deny all cross-tenant traffic by default. An agent can reach the specific services it needs and nothing else, least of all another tenant's pods.
Credential isolation. Per-tenant, per-agent secrets. A leaked token is useless outside its own tenant because it was never granted anything else.
Data isolation. The tenant boundary lives in the data layer itself, through separate schemas, row-level security, or per-tenant encryption keys, not only in application code that a single bug can bypass.
Miss any one layer and the others have to cover for it. Get all four and a failure in one is contained by the rest.
Network policy: the layer teams skip
The most commonly missing layer is network. On Kubernetes, the fix is a default-deny NetworkPolicy per tenant namespace, then explicit allows for the traffic you actually want.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-cross-tenant
namespace: tenant-acme
spec:
podSelector: {}
policyTypes: ["Ingress", "Egress"]
ingress: [] # deny all inbound by default
egress:
- to: # allow only egress to approved services
- namespaceSelector:
matchLabels: { role: shared-services }apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-cross-tenant
namespace: tenant-acme
spec:
podSelector: {}
policyTypes: ["Ingress", "Egress"]
ingress: [] # deny all inbound by default
egress:
- to: # allow only egress to approved services
- namespaceSelector:
matchLabels: { role: shared-services }Start from deny-all and open only what is needed. This flips the default from "everything can talk to everything" to "nothing can talk to anything unless allowed," which is the only safe starting point for hostile tenants. The Kubernetes multi-tenancy guide goes deeper on the patterns here.
Do not forget the human side of tenancy
Isolating agents from each other is half the job. The other half is making sure the right humans can reach the right agents and no others. An operator in tenant A must never be able to open a shell into tenant B's agent, read its logs, or rotate its secrets. That is access control, and it has to enforce the same tenant boundary the network does.
This is where agent isolation meets role-based access control. The two must agree on the boundary, or a gap opens between them. We cover the human side in RBAC and team management. The principle is the same on both sides: least privilege, and a boundary enforced in more than one place so a single mistake does not open the door.
A checklist for multi-tenant agents
Before you run agents for more than one customer, confirm every layer:
Each tenant's agents run in a dedicated namespace with resource limits.
A default-deny network policy blocks all cross-tenant traffic; allows are explicit and minimal.
Secrets are scoped per tenant and per agent, so a leaked token is useless elsewhere.
The tenant boundary is enforced in the data layer, not only in application code.
Human access control enforces the same boundary as the infrastructure.
Untrusted input cannot turn an agent into a tool for probing your network.
Each item is a separate wall. The security of the whole system is not the strongest wall, it is whether any wall is missing.
The data layer: the leak that hides in plain sight
Of all the isolation layers, the data layer causes the quietest breaches, because a data leak does not crash anything. If every tenant shares one database and isolation depends on each query carrying the right tenant filter, then isolation is only as strong as your most tired developer on their worst day. One query that forgets the filter, or one ORM default that scopes too broadly, and tenant A sees tenant B's rows with no error to warn anyone.
Stronger options move the boundary out of application logic:
Row-level security. The database itself enforces that a connection scoped to tenant A can only ever see tenant A's rows, even if the query forgets to say so.
Schema per tenant. Each tenant's data lives in its own schema, so a cross-tenant read has to be explicit and obvious, not an accidental missing clause.
Per-tenant encryption keys. Even if data is somehow read across the boundary, it stays unreadable without the other tenant's key.
The principle throughout: do not trust application code to be the only thing standing between tenants. Put the boundary somewhere a single forgotten line cannot bypass it.
Isolating what the agent can reach outward
Most isolation thinking is about keeping tenants from reaching each other. Agents add a direction people forget: outbound. An agent that can be steered by untrusted input might try to reach your internal metadata service, a neighbor's internal endpoint, or the wider internet to exfiltrate what it read. Ingress rules alone do not stop this. You need egress control too.
Lock down where an agent can send traffic, not just where it can receive it. Deny egress by default, allow only the specific external services the agent legitimately needs, and block access to internal endpoints like cloud metadata services that an attacker would love an agent to hit on their behalf. This is the layer that turns a successful prompt injection from a breach into a blocked request. An agent that reads a malicious instruction to phone home simply cannot, because the network will not carry the packet.
Testing your isolation before a customer does
Isolation you have not tested is isolation you are only hoping for. Verify each boundary deliberately:
Try to cross the network. From one tenant's agent, attempt to reach another tenant's pod. It should fail. If it succeeds, your network policy is not doing its job.
Try a stolen token elsewhere. Take a tenant's credential and use it against another tenant's resources. It should be rejected everywhere but its own scope.
Try a forgotten filter. Run a query without the tenant clause and confirm the data layer still refuses to return another tenant's rows.
Try to phone home. Have a test agent attempt to reach an unapproved external host. Egress control should block it.
Run these as an automated suite that fails your build if any boundary opens. A breach found by your own test on a Tuesday is a fixed bug. The same breach found by a customer is an incident and a disclosure.
Where this leaves you
Building all of this yourself is real work: namespaces, network policies, a secrets backend, per-tenant data boundaries, and the access control to match. It is doable, and it is also exactly the undifferentiated infrastructure most teams would rather not hand-roll for every agent. Sokko builds multi tenant AI agent isolation in by default: every customer's agents are fully sealed off from every other customer's, in compute, network, secrets, and storage. Each agent's files and memory stay private to that agent alone, and you pick where it runs: US or EU regions, with EU hosting available for GDPR needs. The layered model above is the goal. The point is you get it as a default, not assembled by hand while hoping you did not miss a layer.
The takeaway
Multi tenant AI agent isolation is not one wall, it is four: compute, network, credentials, and data, plus human access control that agrees with all of them. A container per tenant covers roughly one of those and shares a kernel while doing it. Because agents hold credentials and can be steered by untrusted input, the cost of a missing layer is a real tenancy breach, not a theoretical one. Build every layer, default to deny, and treat a single container as the start of isolation, never the end of it.