Skip to content

All posts

KubernetesAI

RBAC for AI agents in Kubernetes

Ritesh Patel

Kubernetes: RBAC for AI agents in Kubernetes

Give each AI agent its own Kubernetes service account, bind that account to a Role that lists only the resources and verbs the agent needs, and set spec.serviceAccountName on its pod. RBAC only adds permissions and has no deny rules, so the grants you bind are the whole limit.

This post covers the RBAC side only: the bindings, the pod settings and the tokens an agent uses.

Checked against the Kubernetes RBAC, service account and Pod Security Standards pages as fetched on 2026-11-05.

Give each agent its own service account

Kubernetes creates a default service account in every namespace. The docs say it gets no permissions beyond API discovery, and a pod that does not name a service account uses it. The docs also say that permissions given to default are available to every pod in the namespace that does not set serviceAccountName.

So a grant made to default for one workload reaches every other pod that falls back to it. Create a named service account for each agent, and never bind a role to default for an agent’s sake. The account names below (triage-agent) are examples.

Write a Role for the job

RBAC rules have three parts: the API group, the resource and the verbs. The RBAC docs give this example of a namespaced Role that reads pods:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Keep the verbs list as short as the agent’s job allows. The docs’ examples also use create, update, patch and delete on Deployments and Jobs, so a write-capable agent needs those verbs listed explicitly. The docs also say that deletecollection and top-level create cannot be restricted by resource name, so if an agent needs either verb, the grant covers every object of that type in its scope.

Bind the account in one namespace

The RBAC docs show a RoleBinding that refers to a ClusterRole and grants it only inside one namespace. That shape lets one ClusterRole serve agents in several namespaces, with a separate binding in each. The sample below uses a ClusterRole with the same rules as the Role above, bound in the agents namespace.

  1. Create the ClusterRole. It has no namespace, because ClusterRole is a non-namespaced resource.
  2. Create a RoleBinding in the agent’s namespace. Its subjects entry names the service account, including its namespace.
  3. Check that no ClusterRoleBinding also grants the agent’s account the same rules.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: triage-agent-pod-reader
  namespace: agents
subjects:
- kind: ServiceAccount
  name: triage-agent
  namespace: agents
roleRef:
  kind: ClusterRole
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Lock down the agent’s pod and its account

The pod names its service account in the Pod specification, and Kubernetes then provides that account’s credentials to the pod. The docs also describe automountServiceAccountToken, which controls whether credentials are injected. Set it to false for an agent that never calls the Kubernetes API. An agent that does call the API keeps the default or sets it explicitly. It gets the grants bound to its own account, plus any grants bound to groups it belongs to, such as system:serviceaccounts, system:serviceaccounts:agents or system:authenticated. A broad group grant reaches the agent even when its direct binding is narrow, so audit the group bindings too.

spec:
  serviceAccountName: triage-agent
  automountServiceAccountToken: false

RBAC controls what the pod can do with the API. It does not control what a process inside the container can do on the node, and the same pod spec has to cover that. The Pod Security Standards Restricted profile sets those limits. Its container fields apply to containers, initContainers and ephemeralContainers, and a single failing container fails the whole pod.

Control Field to set Allowed value
Privilege escalation securityContext.allowPrivilegeEscalation false
Non-root user securityContext.runAsNonRoot true
Root UID securityContext.runAsUser Any non-zero value, or unset
Seccomp securityContext.seccompProfile.type RuntimeDefault or Localhost
Capabilities securityContext.capabilities.drop Must include ALL
Added capabilities securityContext.capabilities.add Unset, or NET_BIND_SERVICE only
Volume types spec.volumes[*] configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected or secret

Keep tokens short-lived

Since v1.22, Kubernetes gives a pod a short-lived token from the TokenRequest API. It mounts the token as a projected volume and rotates it automatically. That is the token an agent pod should use.

Older behaviour is different. The docs say that before v1.24 a permanent token was created automatically for each service account, and that these tokens do not expire or rotate. The docs advise against them, especially at scale. Application code that calls the API can request a short-lived token itself through the TokenRequest API, so avoid mounting a static Secret token into an agent pod.

Compare the three ways to grant an agent access

Permissions reach an agent through the bindings that name its account and through the groups it belongs to, and the three setups below differ mainly in how far those bindings reach. The Kubernetes docs define each mechanism, and the fallback case is the one most often left in place by accident. A pod on default with no bindings has nothing to lose, but an agent that is later bound to default inherits that grant everywhere.

The table compares the three setups. The “Use it for” column is our recommendation.

Setup What the agent gets Use it for
Pod on default, no bindings API discovery only Nothing; do not run agents this way
Named service account, RoleBinding to a ClusterRole The ClusterRole’s rules, in one namespace Most agents
ClusterRoleBinding The ClusterRole’s rules in every namespace Only agents that need cluster-wide reach

Enforcing this with Kyverno

The settings in this post can also be enforced at admission. Kyverno’s policy library has rules for some of them, such as disallowing privilege escalation and requiring drop ALL capabilities, so a manifest that skips review can still be checked before it runs. Start the rule in audit mode, read the results, and only then switch it to deny, so that workloads already in production are not blocked by surprise.

The Kyverno project page covers installation and the project’s documentation. For the wider governance picture, see governing AI agents.

Sources

Frequently asked questions

Can an AI agent run under the namespace default service account?

It can, but you should not let it. Kubernetes gives the default account no permissions beyond API discovery outside kube-system. Any grant you later bind to default applies to every pod in the namespace that does not name a service account. An agent on default inherits whatever another workload was given, so create a named account for each agent.

Does a RoleBinding limit a ClusterRole to one namespace?

Yes. The RBAC docs say a RoleBinding grants permissions within its own namespace even when it refers to a ClusterRole. The docs' example binds the ClusterRole secret-reader in the development namespace, and says that only grants permissions within that namespace. Use this pattern when one ClusterRole serves several agents in different namespaces.

Can an RBAC rule stop an agent from deleting objects?

Only by leaving out the delete verb. RBAC permissions are purely additive, with no deny rules, so a rule cannot subtract access that another binding grants. Check every binding that reaches the agent's service account, because one forgotten grant is enough for a delete to succeed.

Should an agent pod mount a service account token if it never calls the API?

No. Set automountServiceAccountToken to false in the Pod specification, which stops Kubernetes injecting credentials for that account. Leave it on only for agents that call the Kubernetes API, and give those agents the narrowest Role they need.

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.