Kubernetes RBAC Hardening: A Practitioner's Guide
Kubernetes RBAC (Role-Based Access Control) is the gatekeeper for everything in your cluster: who can read secrets, who can exec into pods, who can create new workloads. When it is misconfigured, attackers who compromise one pod can pivot to own your entire infrastructure. This guide covers how to design RBAC correctly from the start, how to audit existing permissions, and the specific misconfigurations that show up in nearly every real-world cluster compromise.
How Kubernetes RBAC Works
Kubernetes RBAC operates on four core resources:
- Role -- defines allowed verbs (get, list, create, delete, patch, watch, *) on specific API resources within a namespace
- ClusterRole -- same as Role but cluster-scoped (applies across all namespaces, or to non-namespaced resources)
- RoleBinding -- binds a Role or ClusterRole to a subject (user, group, or ServiceAccount) within a namespace
- ClusterRoleBinding -- binds a ClusterRole to a subject cluster-wide
The evaluation engine is additive: there are no deny rules. A principal has a permission if any binding grants it. This means the attack surface grows with every role and binding you create.
Subjects in RBAC:
| Subject Type | Typical Use | Risk Level |
|---|---|---|
| User | Human operators (via OIDC/cert) | Medium -- humans make mistakes |
| Group | Teams bound to IdP groups | Medium -- group sprawl is common |
| ServiceAccount | Workload identity for pods | High -- often over-privileged |
The RBAC API uses these verbs against these resource groups most commonly exploited:
verbs: ["get", "list", "watch"] # read-only -- relatively safe
verbs: ["create", "update", "patch"] # write -- dangerous on secrets/configmaps
verbs: ["delete"] # destructive -- high impact
verbs: ["*"] # wildcard -- almost never justified
resources: ["secrets"] # contains credentials, tokens
resources: ["pods/exec"] # RCE inside the cluster
resources: ["pods/portforward"] # lateral movement
resources: ["clusterrolebindings"] # privilege escalation
The authentication flow: Kubernetes authenticates requests via certificates, bearer tokens (ServiceAccount JWT or OIDC), or webhook authenticators. RBAC authorization then evaluates whether the authenticated identity holds a binding that permits the requested verb+resource combination.
Least-Privilege Role Design Principles
The default posture in most clusters is over-permissive. Here is how to design roles that actually enforce least privilege.
Principle 1: Namespace isolation as a blast radius limiter
Use namespaces to segment workloads by trust level. Bind roles with RoleBinding (namespace-scoped) rather than ClusterRoleBinding wherever possible. A compromised pod in the payments namespace with a RoleBinding cannot affect the infra namespace.
Principle 2: Avoid binding ClusterRoles cluster-wide
The view, edit, and admin ClusterRoles are convenient but dangerous when bound cluster-wide. A ClusterRoleBinding for view on a developer account means they can list secrets in every namespace -- including those containing cloud provider credentials. Use namespace-scoped RoleBindings even when referencing ClusterRoles.
Principle 3: Never use cluster-admin except for break-glass accounts
cluster-admin is equivalent to root on the entire cluster. Audit all ClusterRoleBindings referencing it:
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") | {name: .metadata.name, subjects: .subjects}'
Any result should be treated as a high finding unless it is an explicitly approved break-glass account with MFA enforcement on the underlying identity.
Principle 4: Grant specific verbs, not wildcards
Instead of:
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["*"]
Write:
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
Principle 5: Use resourceNames for surgical access
Restrict access to specific named resources where possible:
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get"]
This prevents a workload from reading all ConfigMaps in the namespace.
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
Service Account Hardening
Service accounts are the most common RBAC vulnerability in production clusters. By default, Kubernetes:
- Auto-creates a
defaultservice account in every namespace - Auto-mounts the service account token into every pod
- Grants the
defaultservice account no RBAC permissions -- but CI/CD pipelines and operators frequently add permissions to it without realizing the blast radius
Critical hardening steps:
Disable auto-mounting by default:
At the namespace level (patch the default service account):
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: your-namespace
automountServiceAccountToken: false
On individual pods:
spec:
automountServiceAccountToken: false
Create dedicated service accounts per workload:
apiVersion: v1
kind: ServiceAccount
metadata:
name: payment-processor
namespace: payments
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/payment-processor # IRSA on EKS
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
serviceAccountName: payment-processor
automountServiceAccountToken: true # only true because this SA needs API access
Use projected service account tokens (Kubernetes 1.20+):
Projected tokens are time-limited and audience-bound -- they cannot be replayed against other services:
volumes:
- name: token
projected:
sources:
- serviceAccountToken:
audience: "my-service"
expirationSeconds: 3600
path: token
Audit service account token usage with audit logs:
Look for ServiceAccount tokens being used from outside the cluster (sourceIPs not in your pod CIDR range) -- a sign of token theft.
Common RBAC Misconfigurations Attackers Exploit
Real-world cluster compromises follow predictable RBAC patterns.
Misconfiguration 1: pods/exec granted to broad subjects
pods/exec is effectively remote code execution. Any role with this permission can run arbitrary commands in any pod in scope. Check:
kubectl get roles,clusterroles -A -o json | \
jq '.items[] | select(.rules[]?.resources[]? == "pods/exec") | .metadata.name'
Misconfiguration 2: secrets list/get granted to workloads
Workloads almost never need to list or get Kubernetes Secrets -- they should receive secrets via environment variables or projected volumes. A workload with secrets get can read every credential in its namespace.
Misconfiguration 3: Privilege escalation via rolebindings create
A principal with permission to create RoleBindings in a namespace can grant themselves any permission that exists in that namespace -- even permissions they do not hold. This is a privilege escalation path analogous to PassRole in AWS IAM:
# Attacker with rolebindings create in namespace "app" can do:
kubectl create rolebinding attacker-admin --clusterrole=admin --serviceaccount=app:attacker-sa -n app
Misconfiguration 4: Helm RBAC (Tiller legacy)
Older Helm v2 installations ran Tiller with cluster-admin. While Helm v3 eliminated Tiller, many clusters still have tiller service accounts with broad ClusterRoleBindings from legacy installations.
Misconfiguration 5: Operator CRD over-permissioning
Kubernetes operators frequently request broad RBAC permissions during installation. Audit the RBAC manifests in every operator Helm chart before deployment. Common culprits include monitoring operators that request cluster-wide secrets access.
Detection query (audit log):
Watch for these audit log patterns in your SIEM:
| Event | Meaning |
|---|---|
| verb=create, resource=clusterrolebindings | Privilege escalation attempt |
| verb=get, resource=secrets, user=system:serviceaccount | SA reading secrets directly |
| verb=create, resource=pods, subresource=exec | Interactive shell in pod |
| verb=list, resource=pods, namespace=kube-system | Reconnaissance of control plane |
Auditing Existing RBAC with kubectl and Open Source Tools
Most clusters accumulate RBAC debt over time. These tools help you find it.
kubectl-who-can:
Shows which subjects can perform a specific action:
kubectl who-can get secrets -n production
kubectl who-can create clusterrolebindings
kubectl who-can exec pods
Install via Krew: kubectl krew install who-can
rbac-tool:
Generates a visual graph of all subjects, roles, and bindings:
kubectl rbac-tool lookup system:serviceaccount:kube-system:default
kubectl rbac-tool policy-rules -e '^system' # exclude system accounts
rakkess (access matrix):
Prints which verbs a service account can perform on all resources -- useful for quickly spotting over-permissioned accounts:
rakkess --sa kube-system:default
Automated audit checklist:
# 1. Find all cluster-admin bindings
kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name=="cluster-admin")'
# 2. Find service accounts with wildcard verbs
kubectl get roles,clusterroles -A -o json | jq '.items[] | select(.rules[]?.verbs[]? == "*")'
# 3. Find pods with automounted tokens that have API access
kubectl get pods -A -o json | jq '.items[] | select(.spec.automountServiceAccountToken != false)'
# 4. List all role bindings across all namespaces
kubectl get rolebindings -A -o wide
Run this audit quarterly and after every major operator or tooling installation.
Enabling and Using Kubernetes Audit Logs for RBAC Monitoring
Kubernetes audit logs record every API server request with full context: who, what, when, and the result. Without them, you have no visibility into RBAC abuse.
Audit policy configuration:
Create an audit policy at /etc/kubernetes/audit-policy.yaml on your control plane:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Log all requests to secrets at RequestResponse level
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
# Log exec, portforward at Metadata level
- level: Metadata
resources:
- group: ""
resources: ["pods/exec", "pods/portforward", "pods/attach"]
# Log RBAC changes at RequestResponse
- level: RequestResponse
resources:
- group: "rbac.authorization.k8s.io"
resources: ["clusterroles", "clusterrolebindings", "roles", "rolebindings"]
# Omit high-volume, low-value events
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: ""
resources: ["endpoints", "services", "services/status"]
# Default: Metadata for everything else
- level: Metadata
SIEM correlation rules for RBAC abuse:
Forward audit logs to your SIEM and build alerts for:
| Alert | Condition |
|---|---|
| Privilege escalation | verb=create AND resource=clusterrolebindings |
| Secret enumeration | verb=list AND resource=secrets AND user != system:serviceaccount:kube-system:* |
| Shell in pod | verb=create AND resource=pods AND subresource=exec |
| Role with wildcard | verb=create AND resource=clusterroles AND requestObject contains verbs=[*] |
| Anonymous access | user=system:anonymous |
The bottom line
Kubernetes RBAC is not a one-time setup -- it is an ongoing hygiene practice. Start with a least-privilege audit using kubectl-who-can and rakkess, disable auto-mounting on every service account that does not need API access, remove all wildcard verbs, and wire audit logs to your SIEM. The clusters that get compromised are not the ones that enabled RBAC; they are the ones that enabled it and then stopped paying attention.
Frequently asked questions
What is the difference between a Role and a ClusterRole in Kubernetes?
A Role is namespace-scoped: it only grants permissions within the namespace where it is created. A ClusterRole is cluster-scoped: it can grant permissions on non-namespaced resources (like nodes and persistent volumes) or be reused across namespaces via RoleBindings. The key operational rule is to prefer namespace-scoped RoleBindings even when referencing ClusterRoles -- this limits the blast radius of a compromised account to a single namespace.
How do I find overprivileged service accounts in my cluster?
Use three tools in combination: kubectl-who-can (shows who can do a specific action), rakkess (generates an access matrix for a service account), and a direct audit of ClusterRoleBindings referencing cluster-admin. Run: `kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name=="cluster-admin")'` to immediately see your highest-risk bindings. Also check for roles with wildcard verbs: `kubectl get roles,clusterroles -A -o json | jq '.items[] | select(.rules[]?.verbs[]? == "*")'`.
Is it safe to disable automountServiceAccountToken on all pods?
It is safe to disable on any pod that does not make direct Kubernetes API calls. The vast majority of application workloads (web servers, databases, message consumers) do not need to call the Kubernetes API, so their service account token mount is pure attack surface. Disable it by default at the ServiceAccount level and re-enable only for workloads that explicitly need API access (operators, monitoring agents, CI/CD runners). Set automountServiceAccountToken: false on the default service account in every namespace.
What are the most dangerous Kubernetes RBAC permissions to grant?
In order of severity: (1) cluster-admin ClusterRoleBinding -- full cluster control; (2) clusterrolebindings create/update -- allows self-escalation to any role; (3) pods/exec -- interactive shell in any pod; (4) secrets get/list -- credential access; (5) nodes/proxy -- can proxy traffic through the kubelet to access pod APIs without going through the API server. Treat these as critical findings in any RBAC audit.
How should I handle RBAC for CI/CD pipelines?
Create a dedicated service account for each pipeline with the minimum permissions needed for deployment. For a typical deployment pipeline, this means: `deployments update/patch` in specific namespaces, `configmaps get/list` if config is read at deploy time, and `secrets get` only for the specific secrets needed. Never grant pipelines cluster-admin or the ability to create ClusterRoleBindings. Use IRSA (EKS), Workload Identity (GKE), or Pod Identity (AKS) to bind the service account to a cloud IAM role for cloud resource access, avoiding long-lived static credentials.
Do Kubernetes network policies replace the need for RBAC hardening?
No -- they are complementary controls at different layers. Network policies control pod-to-pod and pod-to-service traffic (layer 3/4). RBAC controls who can interact with the Kubernetes API (create pods, read secrets, exec into containers). An attacker who compromises a pod can still call the Kubernetes API using the auto-mounted service account token even if network policies block direct pod-to-pod communication. Both controls are required: network policies for lateral movement containment, RBAC for privilege escalation prevention.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, weekly, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals weekly.
The Mythos Brief is free.
AI that finds 27-year-old zero-days. What it means for your security program.
