Skip to content

All posts

KyvernoAI

Kyverno policies for AI agents

Ritesh Patel

Navy panel with the title Kyverno policies for AI agents, beside a watercolour abstract

Kyverno policies for AI agents are admission rules that check the pod spec of each agent before the Kubernetes API server accepts it. Write them as ValidatingPolicy resources, enforce the Pod Security Standards Restricted controls on agent pods, and turn on background evaluation to find pods that already run. Kyverno’s ClusterPolicy type is deprecated from v1.19.

For the wider picture, see governing AI agents. This post covers the Kubernetes side only.

What Kyverno checks for an agent pod

An AI agent on Kubernetes is usually a pod that runs a model client, a tool runner and sometimes a shell. Kyverno can check that pod spec in three places. The Kyverno overview describes it as a policy engine that works as a Kubernetes admission controller, as a CLI-based scanner, and at runtime. It can validate, mutate, generate or clean up resources. This post uses validation, because an unsafe agent pod should be refused, not quietly changed.

Check point Setting that controls it What happens on a failure
Admission evaluation.admission.enabled in the policy, with validationActions set to Deny The create or update is rejected
Background scan evaluation.background.enabled: true The result goes to a PolicyReport. Nothing is rejected
Pipeline kyverno apply against manifest files, run in CI The command reports the result before the manifest reaches a cluster

The admission and background rows run inside the cluster. The pipeline row catches the problem earlier, before a commit is applied. Use the pipeline check and the admission check together, so an agent manifest that skips CI still hits the webhook.

The Restricted controls to enforce on agent pods

The Kubernetes Pod Security Standards define three profiles: Privileged, Baseline and Restricted. Restricted is aimed at current pod hardening best practices, and it is the right baseline for code you did not write line by line. An agent that runs tool calls is that kind of code. Treat each agent pod as lower trust.

The table lists the Restricted controls that matter most for agent pods, with the field each one checks and the value it allows.

Control Field Allowed value
Privilege escalation spec.containers[*].securityContext.allowPrivilegeEscalation false
Non-root user spec.securityContext.runAsNonRoot, or the same field on each container true
Seccomp spec.securityContext.seccompProfile.type, or the same field on each container RuntimeDefault or Localhost
Capabilities spec.containers[*].securityContext.capabilities.drop and .add drop includes ALL. add is undefined or NET_BIND_SERVICE only
HostPath volumes spec.volumes[*].hostPath Not set. This control comes from Baseline and Restricted inherits it

Restricted also limits volume types to configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected and secret. The sample policy below checks privilege escalation, non-root, capabilities and HostPath, on containers only. The standard applies the same rules to initContainers and ephemeralContainers, so add those lists before you depend on the policy.

Why ClusterPolicy is the wrong starting point

Many Kyverno examples still use ClusterPolicy. The Kyverno docs say ClusterPolicy and Policy are deprecated as of Kyverno v1.19 and will be removed in v1.20. They also say the CEL-based policy types provide full feature parity. New agent rules should start from ValidatingPolicy.

Point ClusterPolicy ValidatingPolicy
Status in the v1.19 docs Deprecated. Removed in v1.20 Stable
Relationship to Kubernetes Kyverno’s own policy resource A superset of the Kubernetes ValidatingAdmissionPolicy type
Namespaced variant Policy (deprecated) NamespacedValidatingPolicy, which a namespace owner can manage without cluster-admin rights
Results PolicyReports PolicyReports, with optional auditAnnotations

The ValidatingPolicy type is the one the docs describe for admission, background scans and reporting, so the rest of this post uses it.

Write the agent policy as a ValidatingPolicy

Follow these steps to write the sample policy. It applies only to pods that carry a label you choose, so ordinary workloads in the same cluster are not affected.

  1. Label every agent pod with one key and value. The sample uses component: ai-agent. Pick a label your platform team can enforce in the Deployment template.
  2. Set matchConstraints.resourceRules to pods in the core API group, for CREATE and UPDATE. Use matchConditions to narrow the match to the agent label. The docs show matchConditions as a list of name and expression pairs.
  3. Set validationActions to Deny after the Audit run is clean. Start with Audit on a live cluster (see the FAQ).
  4. Add one entry under validations for each control. Each entry has an expression and a message.
apiVersion: policies.kyverno.io/v1
kind: ValidatingPolicy
metadata:
  name: ai-agent-pod-restricted
spec:
  validationActions:
    - Deny  # Start with Audit on a live cluster; switch to Deny after the Audit run is clean
  matchConstraints:
    resourceRules:
      - apiGroups: ['']
        apiVersions: [v1]
        operations: [CREATE, UPDATE]
        resources: [pods]
  matchConditions:
    - name: is-ai-agent
      expression: "has(object.metadata.labels) && 'component' in object.metadata.labels && object.metadata.labels['component'] == 'ai-agent'"
  validations:
    - expression: "object.spec.containers.all(c, has(c.securityContext) && has(c.securityContext.allowPrivilegeEscalation) && c.securityContext.allowPrivilegeEscalation == false)"
      message: "Every container in an AI agent pod must set allowPrivilegeEscalation to false."
    - expression: "object.spec.containers.all(c, !has(c.securityContext) || !has(c.securityContext.runAsNonRoot) || c.securityContext.runAsNonRoot == true) && ((has(object.spec.securityContext) && has(object.spec.securityContext.runAsNonRoot) && object.spec.securityContext.runAsNonRoot == true) || object.spec.containers.all(c, has(c.securityContext) && has(c.securityContext.runAsNonRoot) && c.securityContext.runAsNonRoot == true))"
      message: "AI agent pods must run as a non-root user. No container may set runAsNonRoot to false, even when the pod sets it to true."
    - expression: "object.spec.containers.all(c, has(c.securityContext) && has(c.securityContext.capabilities) && has(c.securityContext.capabilities.drop) && c.securityContext.capabilities.drop.exists(x, x == 'ALL') && (!has(c.securityContext.capabilities.add) || c.securityContext.capabilities.add.all(x, x == 'NET_BIND_SERVICE')))"
      message: "Every container in an AI agent pod must drop ALL capabilities and may add back only NET_BIND_SERVICE."
    - expression: "!has(object.spec.volumes) || object.spec.volumes.all(v, !has(v.hostPath))"
      message: "AI agent pods must not mount hostPath volumes."

The non-root check accepts a pod-level or container-level setting, as the Restricted table allows, but fails any container that sets runAsNonRoot: false, even when the pod sets it to true. The capabilities check rejects any add entry other than NET_BIND_SERVICE. The sample does not check seccomp or runAsUser. Add those with the same pattern before you rely on the policy.

Test the policy with the Kyverno CLI

Test the policy against two manifests before it reaches a cluster: one that breaks a control and one that meets all four. Keep both files in the repository next to the policy, so CI can run them on every change.

  1. Save an agent pod manifest with the label component: ai-agent that sets allowPrivilegeEscalation: true. Call it agent-pod-bad.yaml.
  2. Save a compliant pod manifest with the same label and every control set. Call it agent-pod-good.yaml.
  3. Run kyverno apply on the policy and each manifest. Add --detailed-results to see each rule’s outcome.
  4. Confirm the bad manifest fails and the good one passes. Then add the same two commands to your pipeline.
kyverno apply ai-agent-pod-restricted.yaml --resource agent-pod-bad.yaml --detailed-results
kyverno apply ai-agent-pod-restricted.yaml --resource agent-pod-good.yaml --detailed-results

Check that the CLI result for the bad manifest matches what the admission webhook returns on a test cluster. Use the CLI for fast feedback in CI and the webhook for enforcement.

Enforcing this with Kyverno

Kyverno is open source, and the Kyverno project page covers installation and the project’s docs. The rollout order for this policy is the same as for any Kyverno rule. Start with Audit, which records results in PolicyReports instead of rejecting requests. Read the reports, fix the agent specs that break a control, and add exceptions only for workloads that need one. Then change validationActions to Deny.

Exceptions use a separate resource. The Kyverno docs say a PolicyException lets select resources bypass a policy without changing the policy itself. Keep exceptions narrow and name the workload, so the rule still applies to every other agent pod.

Two related posts cover the next layers. Governance beyond the admission webhook explains what admission rules cannot see. Policy-driven authorization for AI agents with Kyverno and AWS AgentCore shows the same policy idea applied to agent tool calls.

Checked against the Kyverno v1.19 docs and the Kubernetes Pod Security Standards, as of 2026-11-04.

Frequently asked questions

Can Kyverno stop an AI agent from starting an unsafe pod?

Yes, for the pod spec. Kyverno receives validating admission webhook calls from the Kubernetes API server, so a ValidatingPolicy with Deny rejects a create or update that breaks a rule. It does not reach into a process that is already running inside an allowed pod. Pair admission rules with limits on what the agent's service account can do, and with runtime controls for the actions a pod spec cannot describe.

Should new agent policies use ClusterPolicy?

No. The Kyverno docs mark ClusterPolicy and Policy as deprecated from v1.19 and removed in v1.20, and they say the CEL-based policy types have full feature parity. Write new rules as ValidatingPolicy. Use NamespacedValidatingPolicy when a namespace owner manages the rule. Convert any existing ClusterPolicy resources with the migration guide before you upgrade to v1.20.

What is the difference between Audit and Deny in a ValidatingPolicy?

Deny rejects the request, so the object is not created or updated. Audit records the result in PolicyReports instead of rejecting the request. Run a new agent policy with Audit on a live cluster, read the reports, fix the workloads or add exceptions, and then switch the rule to Deny. Switching early blocks deployments that were already working.

Does Kyverno check agent pods that are already running?

Yes, when background evaluation is on. The ValidatingPolicy docs describe background scans that run periodically or when a policy is created or changed, and they write the results to PolicyReports. A background result does not reject a pod. It shows you which running pods break the rule so you can fix them on their next rollout.

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.