Remember the taste of that bitter coffee you had to drink when you realized the intern you gave cluster-admin access to 'accidentally' deleted the entire production environment with a single kubectl command? If you haven't tasted that coffee yet, you're either very lucky or you've fallen into the false sense of security created by 'default' settings in the Kubernetes (K8s) world.
Hey everyone, I'm Sedat. Today, we're diving into the dark alleys of the orchestration world—K8s security. On the Red Team side, our job isn't just to break in; it's to explain exactly why those doors were left wide open. When it comes to K8s, the common mentality is often 'It’s up and running, let’s move on.' But that 'working' system might actually be providing a massive playground for an attacker. Let’s look at how we can tame this beast based on our simulations at testCompany and our experience in the field.
RBAC: The End of the 'Everyone is Admin' Mentality
The first mistake usually made after a K8s installation is handing out the cluster-admin role like candy. Why? Because no one wants to deal with 'Forbidden' errors while trying to do their job. But here's what we forget: RBAC (Role-Based Access Control) isn't just for humans; it applies to ServiceAccounts too. Imagine an attacker breaches a pod. If the ServiceAccount used by that pod has unnecessarily broad permissions, the attacker doesn't just move laterally; they move vertically straight to the top.
Check this out—this YAML file is basically a 'recipe for disaster':
# THIS IS A BAD EXAMPLE - Do not let this near production!
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: default-sa-admin-binding
subjects:
- kind: ServiceAccount
name: default
namespace: dev-team
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
What’s happening here? We’ve given 'God-mode' permissions to the 'default' service account in the dev-team namespace across the entire cluster. If an attacker hacks a simple web app running in this namespace, they now hold the keys to the kingdom.
The Fix? The Principle of Least Privilege. A pod should only have access to the specific APIs it needs. Better yet, if a pod doesn't need to talk to the API server at all, set automountServiceAccountToken: false. If it's not needed, why leave it there?
Container Escapes and Privileged Pods
Let’s look at something a bit more technical: privileged: true. This setting allows a container to have almost all the same capabilities as the host machine. In Red Team operations, if we see a pod with this setting enabled, we usually get to go home early because escaping to the host machine takes mere seconds.
Here’s a look at a 'dangerous' pod configuration:
apiVersion: v1
kind: Pod
metadata:
name: dangerous-pod
spec:
containers:
- name: exploit-container
image: example.com/security-tool:latest
securityContext:
privileged: true # This is where things go south.
When you run a pod like this, you're essentially breaking the isolation barrier that containerization is supposed to provide. An attacker inside this pod can access the host’s devices, mount the host’s file system, and eventually take over the entire node.
Always audit your security contexts and use tools like Kyverno or OPA (Open Policy Agent) to block these kinds of configurations from ever reaching your cluster.
