Skip to content

All posts

Kubernetes

How to sandbox AI agents on Kubernetes

Ritesh Patel

Kubernetes: How to sandbox AI agents on Kubernetes

To sandbox AI agents on Kubernetes, run each agent in its own Pod with a hardened security context, deny its egress with a NetworkPolicy, and give it a RuntimeClass that adds a stronger isolation boundary than a standard container. Agent Sandbox provides a Sandbox resource that manages that Pod’s lifecycle.

Checked against the Agent Sandbox README and threat model, and the Kubernetes docs for Pod security, Pod Security admission, NetworkPolicy and RuntimeClass, as fetched on 2026-11-05. Pin the Agent Sandbox release in the install step below to the one you have tested.

What a sandbox has to stop

An agent sandbox runs code nobody has reviewed, often code the model wrote a moment earlier. The Agent Sandbox threat model names the risks that matter for Sandbox Pods: a container escape to the node, a compromised Pod reaching other tenants over the network, a service account token used against the Kubernetes API, and a Pod that uses up the node’s CPU, memory or storage. Each risk needs a control at a different layer. This guide is part of our AI agent governance work.

Risk Control Where you set it
Container escape to the node A secure runtime such as gVisor or Kata Containers runtimeClassName on the Pod, from a RuntimeClass
Privilege escalation inside the container Non-root user, no privilege escalation, all capabilities dropped securityContext
Cross-tenant network attack Default-deny egress NetworkPolicy
Kubernetes API abuse No service account token mounted automountServiceAccountToken: false
Resource exhaustion CPU and memory requests and limits resources on each container
Unauthorized sandbox creation RBAC on the Sandbox resources Role and RoleBinding

For a per-request policy layer on top of Agent Sandbox, read our OpenShell on Kubernetes guide.

Create the sandbox with Agent Sandbox

Agent Sandbox is a SIG Apps project. It adds a Sandbox resource for a single stateful Pod with a stable identity and persistent storage. It does not provide the isolation itself, so the rest of this guide sets that up.

  1. Check the cluster version. Agent Sandbox needs Kubernetes 1.25 or later. The README recommends 1.29 or later, because CRD CEL validation is stable there.
  2. Install a pinned release. The README pins v1.0.2 in its production example, and recommends pinning for GitOps.
  3. Confirm the CRD and the controller are present.
  4. Create a namespace for agents, so the policies below apply only to them.
export VERSION="v1.0.2"
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${VERSION}/sandbox-with-extensions.yaml
kubectl get crd sandboxes.agents.x-k8s.io
kubectl get deploy agent-sandbox-controller -n agent-sandbox-system
kubectl create namespace agents

Harden the Pod security context

A Sandbox takes a full podTemplate, so the Pod settings go under spec.podTemplate.spec. Set the fields the Pod Security Standards restricted profile asks for. Restricted requires runAsNonRoot, allowPrivilegeEscalation set to false, a RuntimeDefault seccomp profile, and capabilities that drop ALL, with NET_BIND_SERVICE as the only permitted add-back.

Kubernetes defaults allowPrivilegeEscalation to true, so set it yourself. Setting it to false cannot be combined with a privileged container or with CAP_SYS_ADMIN, so those settings will conflict with this one.

apiVersion: agents.x-k8s.io/v1beta1
kind: Sandbox
metadata:
  name: agent-hardened
  namespace: agents
spec:
  podTemplate:
    spec:
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: agent
        image: registry.k8s.io/e2e-test-images/agnhost:2.45
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
        resources:
          requests:
            cpu: "250m"
            memory: "256Mi"
          limits:
            cpu: "1"
            memory: "1Gi"

Replace the test image with your agent image. The resource values are examples to size for your workload. Apply the namespace label and the NetworkPolicy from the next two sections before you create this Sandbox, so the first Pod starts under both controls. The namespace field above puts the Pod in agents even when your kubectl context points elsewhere.

Pod Security admission works as a backstop. Its labels apply at the namespace level when Pods are created, so the restricted level covers the Pods the controller makes, even when a manifest leaves a field out.

apiVersion: v1
kind: Namespace
metadata:
  name: agents
  labels:
    pod-security.kubernetes.io/enforce: restricted

Deny egress by default

A Pod is non-isolated for egress until a NetworkPolicy selects it and lists Egress in policyTypes. Policies are additive, so once a Pod is isolated, only the connections that some policy allows get through. The docs say new Pods are isolated before they start, but a Pod created before the network plugin has handled a new policy may start unprotected. Create the policy before the first sandbox.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: agents
spec:
  podSelector: {}
  policyTypes:
  - Egress

This policy also blocks DNS. Add a second NetworkPolicy that allows egress to your cluster’s DNS service, then add one allow rule for each destination the agent needs. The rule types the docs list are podSelector, namespaceSelector and ipBlock, so write each destination as a Pod, a namespace or a CIDR range. The policy also works only on a cluster whose networking plugin enforces NetworkPolicy. For managed sandboxes, the threat model describes a NetworkPolicy mode in SandboxTemplate that limits egress to the public internet.

Choose a RuntimeClass for untrusted code

A RuntimeClass names a runtime configuration that the CRI on each node provides. The handler must match a configuration in containerd or CRI-O on those nodes. Create one RuntimeClass per handler, then reference it from the Pod.

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: agent-isolated
handler: myconfiguration

Then set the runtime on the Sandbox’s Pod spec:

spec:
  podTemplate:
    spec:
      runtimeClassName: agent-isolated

If the RuntimeClass does not exist, or the CRI cannot run its handler, the Pod enters the Failed phase. Scheduling fields keep the Pod on nodes that support the runtime: the RuntimeClass nodeSelector and tolerations are merged with the Pod’s own. The threat model says administrators can require it by setting runtimeClassName in a SandboxTemplate.

Option Isolation added Trade-off Use it for
Hardened container Pod settings, NetworkPolicy and limits only No runtime overhead Agents whose code you have reviewed
gVisor or Kata Containers through a RuntimeClass Kernel and network isolation between the sandbox and the host Node runtime setup, plus the overhead the RuntimeClass overhead field accounts for Untrusted or LLM-generated code

Limit who can create sandboxes

The threat model says only authorized users should create Sandbox, SandboxClaim and SandboxTemplate resources, so restrict them with RBAC. The CRDs are sandboxes.agents.x-k8s.io, plus sandboxclaims, sandboxwarmpools and sandboxtemplates under extensions.agents.x-k8s.io.

Before you uninstall, check for live resources. The README warns that deleting the CRDs cascade-deletes all custom resources of those types across all namespaces.

kubectl get sandboxes -A
kubectl get crd sandboxclaims.extensions.agents.x-k8s.io >/dev/null 2>&1 && kubectl get sandboxclaims -A

A SandboxTemplate defaults automountServiceAccountToken to false when you omit it. A bare Sandbox gets no such default, so the threat model suggests a ValidatingAdmissionPolicy to require the field.

Enforcing this with Kyverno

Admission control is the right place to check the settings above for every sandbox, whoever creates it. The Kyverno policy library has a ClusterPolicy that requires every container to drop ALL capabilities. It matches Pods on create and update, and its sample runs in Audit mode, so it reports violations without blocking them. Test it on a development cluster first.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: drop-all-capabilities
  annotations:
    policies.kyverno.io/title: Drop All Capabilities in CEL expressions
    policies.kyverno.io/category: Best Practices in CEL
    policies.kyverno.io/severity: medium
    kyverno.io/kubernetes-version: "1.26-1.27"
    policies.kyverno.io/minversion: "1.11.0"
    policies.kyverno.io/subject: Pod
spec:
  validationFailureAction: Audit
  background: true
  rules:
    - name: require-drop-all
      match:
        any:
          - resources:
              kinds:
                - Pod
              operations:
                - CREATE
                - UPDATE
      validate:
        cel:
          variables:
            - name: allContainers
              expression: object.spec.containers + object.spec.?initContainers.orValue([]) + object.spec.?ephemeralContainers.orValue([])
          expressions:
            - expression: variables.allContainers.all(container, container.?securityContext.?capabilities.?drop.orValue([]).exists(capability, capability.upperAscii() == 'ALL'))
              message: Containers must drop `ALL` capabilities.

Admission runs when a Pod is created or updated, and it cannot see what the agent does at runtime, so plan a runtime control for that layer too. See Runtime OSS for the product.

Sources

Frequently asked questions

Is a hardened container enough to sandbox an AI agent on Kubernetes?

It is a baseline, not a full answer. A hardened container gets the Pod settings you give it and nothing more. The Agent Sandbox threat model recommends a secure runtime such as gVisor or Kata Containers, selected with a RuntimeClass, for untrusted code. Pair that with a default-deny NetworkPolicy and resource limits, and treat the security context as the minimum for any agent you have not reviewed.

Does Agent Sandbox isolate the agent by itself?

No. The Agent Sandbox threat model says the project does not implement isolation. It manages the Sandbox and its Pods, and it supports configuring secure runtimes through RuntimeClass. The isolation comes from the runtime, the Pod security context and the NetworkPolicy you apply to the namespace.

Why does a sandbox Pod fail after I add runtimeClassName?

A Pod that names a RuntimeClass that does not exist, or whose handler the CRI cannot run, enters the Failed phase, and an event carries the error. Check that the handler name matches a runtime configured in containerd or CRI-O on the nodes. If only some nodes support the runtime, add scheduling settings so the Pod lands on them.

Will a default-deny egress policy break DNS?

Yes, unless you add a rule for it. The Kubernetes docs warn that a default deny-all egress policy also blocks DNS traffic. Add a separate NetworkPolicy that allows egress to your cluster's DNS service, then allow only the destinations the agent needs. NetworkPolicy rules select Pods, namespaces or IP blocks.

Should I use RBAC or admission control to protect agent sandboxes?

Use both. RBAC decides who can create Sandbox, SandboxClaim and SandboxTemplate resources. Admission control checks what the object contains. A SandboxTemplate defaults automountServiceAccountToken to false, but a bare Sandbox does not, so the threat model suggests a ValidatingAdmissionPolicy for that field.

Ritesh Patel, Founder & VP Product, Nirmata

Ritesh Patel is a founder of Nirmata and leads its products. He writes about governing AI coding agents, MCP security and Kubernetes policy as code.

LinkedIn

Govern AI agents with AIControlsControl what AI agents do, and prove it.
ShareXLinkedIn

Stay up-to-date with the latest in AI, governance, and infrastructure

Subscribe to our free monthly newsletter to get industry news, DevOps tips, and articles right to your inbox on Kyverno, containerization, Kubernetes deployment & management and more.