Preventing Service Account Impersonation Abuse with Fine-Grained RBAC in Kubernetes
Service account impersonation is a serious security vulnerability in Kubernetes. By default, all service accounts can impersonate any pod within the same namespace. This allows a compromised service account to gain access to resources it shouldn’t, leading to significant security breaches. This tutorial demonstrates how to mitigate this risk using fine-grained Role-Based Access Control (RBAC).
The Problem: Default Service Account Impersonation
Without RBAC restrictions, any pod running with a service account can impersonate any other pod in the same namespace. This is problematic because a compromised pod could then impersonate a privileged pod, access sensitive data, or perform unauthorized actions. The default behavior exposes a significant attack surface.
# Example: Vulnerable Namespace Configuration (DO NOT USE)
apiVersion: v1
kind: Namespace
metadata:
name: vulnerable-namespace
labels:
app: example
Example 1: Basic RBAC Role & RoleBinding
Let’s create a minimal RBAC configuration to restrict service accounts from impersonating pods. We’ll define a Role that only allows reading pods and a RoleBinding that applies that Role to a specific service account.
# role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: vulnerable-namespace
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
# rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: vulnerable-namespace
subjects:
- kind: ServiceAccount
name: default
namespace: vulnerable-namespace
roleRef:
kind: Role
name: pod-reader
namespace: vulnerable-namespace
Steps to apply:
- Create `role.yaml`
- Create `rolebinding.yaml`
- `kubectl apply -f role.yaml`
- `kubectl apply -f rolebinding.yaml`
Verification:
kubectl get role pod-reader -n vulnerable-namespace
kubectl describe role pod-reader -n vulnerable-namespace
kubectl get rolebinding pod-reader-binding -n vulnerable-namespace
kubectl describe rolebinding pod-reader-binding -n vulnerable-namespace
The output should show the Role and RoleBinding resources created. A pod running with service account `default` in `vulnerable-namespace` should now only be able to list, get, and watch pods. Any attempt to perform actions not defined in the Role will be denied.
Example 2: Refining the Role – Specifying Pod Selectors
Now, let’s make the Role more specific. We’ll add a pod selector to limit the Role to only pods with a specific label. This significantly reduces the attack surface by targeting only specific applications. This step addresses a common misconfiguration where roles are defined for the entire namespace.
# role.yaml (Revised)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: vulnerable-namespace
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
resourceNames:
- my-app-pod # Added Pod Selector
Important: You MUST create a pod with the label `my-app-pod` in the `vulnerable-namespace` for this RoleBinding to take effect. Otherwise, the Role will not apply to any pods.
# pod.yaml (Example pod definition)
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
namespace: vulnerable-namespace
labels:
app: my-app
spec:
containers:
- name: my-app-container
image: nginx
Steps to apply:
- Create `role.yaml` (with the revised rules)
- Create `pod.yaml`
- `kubectl apply -f role.yaml`
- `kubectl apply -f pod.yaml`
Verification:
kubectl get role pod-reader -n vulnerable-namespace
kubectl describe role pod-reader -n vulnerable-namespace
kubectl get pods -n vulnerable-namespace
kubectl describe pod my-app-pod -n vulnerable-namespace
kubectl get rolebinding pod-reader-binding -n vulnerable-namespace
kubectl describe rolebinding pod-reader-binding -n vulnerable-namespace
The RoleBinding now only applies to pods labeled `app: my-app`. Attempting to list pods without this label will result in a permission denied error. This demonstrates how resource selectors refine RBAC.
Example 3: Addressing a Misconfiguration – Unintended Service Account Impersonation
Let’s deliberately introduce a misconfiguration. Assume that the `default` service account’s permissions are not correctly restricted. If it can impersonate all pods in the namespace, it represents a significant vulnerability. Let’s modify `rolebinding.yaml` to allow impersonation by mistake.
# rolebinding.yaml (Incorrect Configuration)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: vulnerable-namespace
subjects:
- kind: ServiceAccount
name: default
namespace: vulnerable-namespace
roleRef:
kind: Role
name: pod-reader
namespace: vulnerable-namespace
Steps to apply:
- Replace the `rolebinding.yaml` file with the incorrect configuration.
- `kubectl apply -f rolebinding.yaml`
Verification:
kubectl get rolepod-reader -n vulnerable-namespace
kubectl describe rolepod-reader -n vulnerable-namespace
kubectl get pods -n vulnerable-namespace
kubectl describe pod my-app-pod -n vulnerable-namespace
kubectl get rolebinding pod-reader-binding -n vulnerable-namespace
kubectl describe rolebinding pod-reader-binding -n vulnerable-namespace
The `kubectl describe rolebinding` output will now show that the `default` service account has permissions to perform `get`, `watch`, and `list` operations on all pods within the `vulnerable-namespace`. This highlights the importance of carefully reviewing and validating RBAC configurations.
Correction:
# rolebinding.yaml (Corrected Configuration)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: vulnerable-namespace
subjects:
- kind: ServiceAccount
name: default
namespace: vulnerable-namespace
roleRef:
kind: Role
name: pod-reader
namespace: vulnerable-namespace
Steps to apply the corrected configuration
- Replace the `rolebinding.yaml` file with the corrected configuration.
- `kubectl apply -f rolebinding.yaml`
Verification:
kubectl get rolepod-reader -n vulnerable-namespace
kubectl describe rolepod-reader -n vulnerable-namespace
kubectl get pods -n vulnerable-namespace
kubectl describe pod my-app-pod -n vulnerable-namespace
kubectl get rolebinding pod-reader-binding -n vulnerable-namespace
kubectl describe rolebinding pod-reader-binding -n vulnerable-namespace
The `kubectl describe rolebinding` output will now correctly reflect the restrictive RBAC configuration. This emphasizes the need for thorough testing and validation of RBAC rules.



Leave a Reply