Kubernetes: Prevent Service Account Impersonation Abuse with Fine-Grained RBAC

Preventing Service Account Impersonation Abuse with Fine-Grained RBAC in Kubernetes

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:

  1. Create `role.yaml`
  2. Create `rolebinding.yaml`
  3. `kubectl apply -f role.yaml`
  4. `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:

  1. Create `role.yaml` (with the revised rules)
  2. Create `pod.yaml`
  3. `kubectl apply -f role.yaml`
  4. `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:

  1. Replace the `rolebinding.yaml` file with the incorrect configuration.
  2. `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

  1. Replace the `rolebinding.yaml` file with the corrected configuration.
  2. `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

Your email address will not be published. Required fields are marked *

We use cookies and similar technologies to enhance your experience on wobizdu.com, analyze site traffic, personalize content, and deliver relevant ads. Some cookies are essential for the site to function, while others help us improve performance and user experience. You may accept all cookies, decline optional ones, or customize your settings. Review our Privacy Policy to learn more.