# Kubernetes RBAC Permissions You Might Not Know About, but Should


**K8s RBAC offers three permissions with hidden powers that can be used maliciously. Discover how to control their use.**

![Featued image for: Kubernetes RBAC Permissions You Might Not Know About, but Should](https://cdn.thenewstack.io/media/2024/05/b1762463-kubernetes-rbac-permissions-featured-image-1024x683.jpg align="center")

Role-based access control ([RBAC](https://thenewstack.io/3-frameworks-for-role-based-access-control/)) is the default access control approach in [Kubernetes (K8s)](https://thenewstack.io/kubernetes/). This model categorizes permissions using specific verbs to define allowed interactions with resources. Within this system, three lesser-known permissions — `escalate`, `bind` and `impersonate` — can override existing role limitations, grant unauthorized access to restricted areas, expose confidential data or even allow complete control over a cluster. This article explains these potent permissions, offering insights into their functions and guidance on mitigating their associated risks.

## **About RBAC Role and Verbs**

If you are not already familiar with the [key concepts of Kubernetes](https://roadmap.sh/kubernetes) RBAC, please refer to the [Kubernetes’ documentation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/).

However, I do need to briefly describe one important concept directly related to this article: role. This describes access rights to K8s resources within a specific namespace and the available operations. Roles consist of a list of rules. Rules include verbs — available operations for defined resources.

Here is an example of a role from the K8s documentation that grants read access to pods:

```go
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" points to the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
```

[**view raw**](https://gist.github.com/lovemycodesnippets/50534302efbfd2099840979b214bfb6c/raw/eeb80040223665d21556a0610b88ac7a3b0223fb/read-access.yaml)[**read-access.yaml**](https://gist.github.com/lovemycodesnippets/50534302efbfd2099840979b214bfb6c#file-read-access-yaml) **hosted with ❤ by** [**GitHub**](https://github.com/)

![](https://cdn.thenewstack.io/media/2023/07/9f76522e-gcore_logo.svg align="left")

**Gcore is the global edge AI, cloud, network, and security solutions provider. Headquartered in Luxembourg, with a staff of 600+ operating from ten offices worldwide, Gcore provides its solutions to global leaders in numerous industries.**

**Learn More**

**The latest from Gcore**

[**Training in the Sovereign Cloud, Deploying at the Edge: Part 2  
11 September 2024**](https://gcore.com/blog/sovereign-cloud-3-part-2/?utm_source=the+new+stack&utm_medium=referral&utm_campaign=tns+platform&utm_content=sponsor+module)[**Training in the Sovereign Cloud, Deploying at the Edge: Part 1  
11 September 2024**](https://gcore.com/blog/sovereign-cloud-3-part-1/?utm_source=the+new+stack&utm_medium=referral&utm_campaign=tns+platform&utm_content=sponsor+module)[**6 Trends and Predictions for AI in Video Streaming  
5 September 2024**](https://gcore.com/blog/6-trends-predictions-ai-video/?utm_source=the+new+stack&utm_medium=referral&utm_campaign=tns+platform&utm_content=sponsor+module)

Verbs like `get`, `watch` and `list` are commonly used. However, more intriguing ones also exist.

## **Three Lesser-Known Kubernetes RBAC Permissions**

For more granular and complex permissions management, the K8s RBAC has the following verbs:

* `escalate`: Allows users to create and edit roles even if they don’t have initial permissions to do so.
    
* `bind`: Allows users to create and edit role bindings and cluster role bindings with permissions they haven’t been assigned.
    
* `impersonate`: Allows users to impersonate other users and gain their privileges in the cluster or in a different group. Critical data can be accessed using this verb.
    

Below, you’ll learn about these verbs in more detail. But first, create a test namespace and name it `rbac`:

**TRENDING STORIES**

1. [**Build Kubernetes Security on Intents, Not Rules**](https://thenewstack.io/build-kubernetes-security-on-intents-not-rules/)
    
2. [**How To Run Databases in Kubernetes**](https://thenewstack.io/how-to-run-databases-in-kubernetes/)
    
3. [**Kubernetes RBAC Permissions You Might Not Know About, but Should**](https://thenewstack.io/kubernetes-rbac-permissions-you-might-not-know-about-but-should/)
    
4. [**Kubernetes 1.31 Arrives with New Support for AI/ML, Networking**](https://thenewstack.io/kubernetes-1-31-arrives-with-new-support-for-ai-ml-networking/)
    
5. [**How the U.S. Air Force Deployed Kubernetes and Istio on an F-16 in 45 days**](https://thenewstack.io/how-the-u-s-air-force-deployed-kubernetes-and-istio-on-an-f-16-in-45-days/)
    

```go
kubectl create ns rbac
```

Then, create a test service account (SA) resource named `privsec` in the `rbac` namespace you just created:

```go
kubectl -n rbac create sa privesc
```

You’ll use these throughout the rest of this tutorial.

### **Escalate**

By default, the Kubernetes RBAC API doesn’t allow users to escalate privileges by simply editing a role or role binding. This restriction works at the API level even if the RBAC authorizer is disabled. The only exception is if the role has the `escalate` verb.

In the image below, the SA with only `update` and `patch` permissions can’t add a new verb to the role. But if you add a new role with the `escalate` verb, it becomes possible.

![How adding the escalate verb to the role allows the user to change the role permissions and add a new verb](https://cdn.thenewstack.io/media/2024/05/4c6c8e84-kubernetes-rbac-permissions-2-1024x356.png align="left")

[**Zoom**](https://cdn.thenewstack.io/media/2024/05/4c6c8e84-kubernetes-rbac-permissions-2-1024x356.png)

***Adding the*** `escalate` verb to the role allows the user to change the role permissions and add a new verb.

Create a role that allows read-only access to pods and roles in this namespace:

```go
kubectl -n rbac create role view --verb=list,watch,get --resource=role,pod
```

Bind this role to the SA `privesc`:

```go
kubectl -n rbac create rolebinding view --role=view --serviceaccount=rbac:privesc
```

Check if the role can be updated:

```go
kubectl auth can-i update role -n rbac --as=system:serviceaccount:rbac:privesc 
 
no
```

The SA can read roles but can’t edit them.

Create a new role that allows role editing in the `rbac` namespace:

```go
kubectl -n rbac create role edit --verb=update,patch --resource=role                              
```

Bind this new role to the SA `privesc`:

```go
kubectl -n rbac create rolebinding edit --role=edit --serviceaccount=rbac:privesc
```

Check if the role can be updated:

```go
kubectl auth can-i update role -n rbac --as=system:serviceaccount:rbac:privesc   
 
yes
```

Check if the role can be deleted:

```go
kubectl auth can-i delete role -n rbac --as=system:serviceaccount:rbac:privesc
 
no
```

The SA can now edit roles but can’t delete them.

For the sake of experimental accuracy, check the SA capabilities by using a JSON Web Token (JWT):

```go
TOKEN=$(kubectl -n rbac create token privesc --duration=8h)
```

Remove the old authentication parameters from the config, as [Kubernetes will check the user’s certificate first](https://stackoverflow.com/questions/60083889/kubectl-token-token-doesnt-run-with-the-permissions-of-the-token) and won’t check the token if it already knows about the certificate.

```go
cp ~/.kube/config ~/.kube/rbac.conf
export KUBECONFIG=~/.kube/rbac.conf
kubectl config delete-user kubernetes-admin
kubectl config set-credentials privesc --token=$TOKEN
kubectl config set-context --current --user=privesc
```

[**view raw**](https://gist.github.com/lovemycodesnippets/83a6ca9fa070df9d6470a04ed09d464c/raw/1e79d6f829276422826115a579ebe89a238a83d4/remove-auth.sh)[**remove-auth.sh**](https://gist.github.com/lovemycodesnippets/83a6ca9fa070df9d6470a04ed09d464c#file-remove-auth-sh) **hosted with ❤ by** [**GitHub**](https://github.com/)

This role shows you can edit other roles:

```go
kubectl -n rbac get role edit -oyaml

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: edit
  namespace: rbac
rules:
- apiGroups:
  - rbac.authorization.k8s.io
  resources:
  - roles
  verbs:
  - update
  - patch
```

[**view raw**](https://gist.github.com/lovemycodesnippets/4c0c05d250d3dfd0bf7edf888be1e5c9/raw/8534f2456f1efdb0a3f38d1f53a25fe94a1b367b/get-role-edit.yaml)[**get-role-edit.yaml**](https://gist.github.com/lovemycodesnippets/4c0c05d250d3dfd0bf7edf888be1e5c9#file-get-role-edit-yaml) **hosted with ❤ by** [**GitHub**](https://github.com/)

Try to add a new verb, `list`, which you already used in the read-only view role:

```go
kubectl -n rbac edit  role edit 

OK

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: edit
  namespace: rbac
rules:
- apiGroups:
  - rbac.authorization.k8s.io
  resources:
  - roles
  verbs:
  - update
  - patch
  - list   # the new verb we added
```

[**view raw**](https://gist.github.com/lovemycodesnippets/7af5ae3d77978e6188cb4111039fa57c/raw/9982fc340cf98d0cc0fd06fb7557d6fe27742565/role-edit.yaml)[**role-edit.yaml**](https://gist.github.com/lovemycodesnippets/7af5ae3d77978e6188cb4111039fa57c#file-role-edit-yaml) **hosted with ❤ by** [**GitHub**](https://github.com/)

Success.

Now, try to add a new verb, `delete`, which you haven’t used in other roles:

```go
kubectl -n rbac edit  role edit

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: edit
  namespace: rbac
rules:
- apiGroups:
  - rbac.authorization.k8s.io
  resources:
  - roles
  verbs:
  - update
  - patch
  - delete   # trying to add a new verb

error: roles.rbac.authorization.k8s.io "edit" could not be patched: roles.rbac.authorization.k8s.io "edit" is forbidden: user "system:serviceaccount:rbac:privesc" (groups=["system:serviceaccounts" "system:serviceaccounts:rbac" "system:authenticated"]) is attempting to grant RBAC permissions not currently held:
```

[**view raw**](https://gist.github.com/lovemycodesnippets/e488f5b41211a0ceb58d06f97c92a567/raw/ccb94eab2714dd8e30483c197471c83fd5d16b4a/delete.yaml)[**delete.yaml**](https://gist.github.com/lovemycodesnippets/e488f5b41211a0ceb58d06f97c92a567#file-delete-yaml) **hosted with ❤ by** [**GitHub**](https://github.com/)

This confirms that Kubernetes doesn’t allow users or service accounts to add new permissions if they don’t already have them — only if users or service accounts are bound to roles with such permissions.

So extend the `privesc` SA permissions. Do this by using the admin config and adding a new role with the `escalate` verb:

```go
KUBECONFIG=~/.kube/config kubectl -n rbac create role escalate --verb=escalate --resource=role
```

Now, bind the `privesc` SA to the new role:

```go
KUBECONFIG=~/.kube/config kubectl -n rbac create rolebinding escalate --role=escalate --serviceaccount=rbac:privesc
```

Check if you can add a new verb to the role now:

```go
kubectl -n rbac edit  role edit

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: edit
  namespace: rbac
rules:
- apiGroups:
  - rbac.authorization.k8s.io
  resources:
  - roles
  verbs:
  - update
  - patch
  - delete   # the new verb we added

role.rbac.authorization.k8s.io/edit edited
```

[**view raw**](https://gist.github.com/lovemycodesnippets/0bef85ca4d4ef7ee7efdc5ebfa9519f0/raw/5d7e1004bc3817c48b163097e0e5a24d20af9eb6/add-verb.yaml)[**add-verb.yaml**](https://gist.github.com/lovemycodesnippets/0bef85ca4d4ef7ee7efdc5ebfa9519f0#file-add-verb-yaml) **hosted with ❤ by** [**GitHub**](https://github.com/)

Now it works. The user can escalate the SA privileges by editing the existing role. This means that the `escalate` verb gives the appropriate admin privileges, including those of the namespace admin or even cluster admin.

### **Bind**

The `bind` verb allows the user to edit the `RoleBinding` or `ClusterRoleBinding` objects for privilege escalation, similar to `escalate`, which allows the user to edit `Role` or `ClusterRole`.

In the image below, the SA with the role binding that has the `update`, `patch` and `create` verbs can’t add `delete` until you create a new role with the `bind` verb.

![How adding the bind verb to the role allows the user to change the role permissions and add a new verb](https://cdn.thenewstack.io/media/2024/05/261d0c3a-kubernetes-rbac-permissions-3-1024x356.png align="left")

***Adding the new role with the*** `bind` *verb allows the user to extend the role’s binding permissions.*

Take a closer look at how this works.

Change the `kubeconfig` file to admin:

```go
export KUBECONFIG=~/.kube/config
```

Remove old roles and bindings:

```go
kubectl -n rbac delete rolebinding view edit escalate
kubectl -n rbac delete role view edit escalate
```

Allow the SA to view and edit the role binding and pod resources in the namespace:

```go
kubectl -n rbac create role view --verb=list,watch,get --resource=role,rolebinding,pod
 
kubectl -n rbac create rolebinding view --role=view --serviceaccount=rbac:privesc
 
kubectl -n rbac create role edit --verb=update,patch,create --resource=rolebinding,pod
 
kubectl -n rbac create rolebinding edit --role=edit --serviceaccount=rbac:privesc
```

Create separate roles to work with pods, but still don’t bind the role:

```go
kubectl -n rbac create role pod-view-edit --verb=get,list,watch,update,patch --resource=pod
 
kubectl -n rbac create role delete-pod --verb=delete --resource=pod
```

Change the `kubeconfig` to the SA `privesc` and try to edit the role binding:

```go
export KUBECONFIG=~/.kube/rbac.conf
 
kubectl -n rbac create rolebinding pod-view-edit --role=pod-view-edit --serviceaccount=rbac:privesc
 
rolebinding.rbac.authorization.k8s.io/pod-view-edit created
```

The new role has been successfully bound to the SA. Note that the `pod-view-edit` role contains verbs and resources that were already bound to the SA by the role that binds `view` and `edit`.

Now, try to bind a role with a new verb, `delete`, which is missing among the roles that are bound to the SA:

```go
kubectl -n rbac create rolebinding delete-pod --role=delete-pod --serviceaccount=rbac:privesc
 
error: failed to create rolebinding: rolebindings.rbac.authorization.k8s.io "delete-pod" is forbidden: user "system:serviceaccount:rbac:privesc" (groups=["system:serviceaccounts" "system:serviceaccounts:rbac" "system:authenticated"]) is attempting to grant RBAC permissions not currently held:
{APIGroups:[""], Resources:["pods"], Verbs:["delete"]}
```

Kubernetes doesn’t allow this, even though you have permission to edit and create role bindings. But you can fix that with the `bind` verb. Do so using the admin config:

```go
KUBECONFIG=~/.kube/config kubectl -n rbac create role bind --verb=bind --resource=role
 
role.rbac.authorization.k8s.io/bind created
 
KUBECONFIG=~/.kube/config kubectl -n rbac create rolebinding bind --role=bind --serviceaccount=rbac:privesc
 
rolebinding.rbac.authorization.k8s.io/bind created
```

Try once more to create a role binding with the new `delete` verb:

```go
kubectl -n rbac create rolebinding delete-pod --role=delete-pod --serviceaccount=rbac:privesc
 
rolebinding.rbac.authorization.k8s.io/delete-pod created
```

Now it works. So, using the `bind` verb, the SA can bind any role to itself or any user.

### **Impersonate**

The `impersonate` verb in K8s is like `sudo` in Linux. If users have `impersonate` access, they can authenticate as other users and run commands on their behalf. The kubectl tool has the `--as, --as-group` and `--as-uid` options, which allow commands to be run as a different user, group or universally unique identifier (UUID), respectively. If a user was given impersonation permissions, they would become the namespace admin, or — if there is a `cluster-admin` service account in the namespace — even the cluster admin.

The `impersonate` verb is helpful to check the RBAC permissions delegated to a user. An admin should perform a command according to the template `kubectl auth can-i --as=$USERNAME -n $NAMESPACE $VERB $RESOURCE` and check if the authorization works as designed.

In this example, the SA wouldn’t get info about pods in the `rbac` namespace by just performing `kubectl -n rbac get pod`. But it becomes possible if there is a role with the `impersonate` verb:

```go
kubectl auth can-i get pod -n rbac --as=system:serviceaccount:rbac:privesc
 
yes
```

```go
KUBECONFIG=~/.kube/config kubectl -n rbac create sa impersonator
 
serviceaccount/impersonator created
```

Now, create a role with the `impersonate` verb and a role binding:

```go
KUBECONFIG=~/.kube/config kubectl -n rbac create role impersonate --resource=serviceaccounts --verb=impersonate --resource-name=privesc
```

(Look at the `--resource-name` parameter in the above command: It only allows impersonation as the `privesc` SA.)

```go
role.rbac.authorization.k8s.io/impersonate created
 
KUBECONFIG=~/.kube/config kubectl -n rbac create rolebinding impersonator --role=impersonate --serviceaccount=rbac:impersonator
 
rolebinding.rbac.authorization.k8s.io/impersonator created
```

![The role with the impersonate verb helps the user to get info about pods](https://cdn.thenewstack.io/media/2024/05/045d18b5-kubernetes-rbac-permissions-4-1024x335.png align="left")

[**Zoom**](https://cdn.thenewstack.io/media/2024/05/045d18b5-kubernetes-rbac-permissions-4-1024x335.png)

***Getting info about pods with a role that has the*** `impersonate` verb.

Create a new context:

```go
TOKEN=$(KUBECONFIG=~/.kube/config kubectl -n rbac create token impersonator --duration=8h)
 
kubectl config set-credentials impersonate --token=$TOKEN   
 
User "impersonate" set.
 
kubectl config set-context impersonate@kubernetes  --user=impersonate --cluster=kubernetes       
 
Context "impersonate@kubernetes" created.
 
kubectl config use-context impersonate@kubernetes                                      
 
Switched to context "impersonate@kubernetes".
```

Check the permissions:

```go
kubectl auth can-i --list -n rbac
 
Resources                                       Non-Resource URLs                     Resource Names   Verbs
selfsubjectaccessreviews.authorization.k8s.io   []                                    []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                    []               [create]
 
...
 
serviceaccounts                                 []                                    [privesc]        [impersonate]
```

No additional permissions exist besides `impersonate`, as specified in the role. But if you impersonate the `impersonator` SA as the `privesc` SA, you get the same permissions that the `privesc` SA has:

```go
kubectl auth can-i --list -n rbac --as=system:serviceaccount:rbac:privesc
 
Resources                                       Non-Resource URLs                     Resource Names   Verbs
roles.rbac.authorization.k8s.io                 []                                    [edit]           [bind escalate]
selfsubjectaccessreviews.authorization.k8s.io   []                                    []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                    []               [create]
pods                                            []                                    []               [get list watch update patch delete create]
 
...
 
rolebindings.rbac.authorization.k8s.io          []                                    []               [list watch get update patch create bind escalate]
roles.rbac.authorization.k8s.io                 []                                    []               [list watch get update patch create bind escalate]
configmaps                                      []                                    []               [update patch create delete]
secrets                                         []                                    []               [update patch create delete]
```

Thus, the `impersonate` SA has all of its own privileges as well as all the privileges of the SA it is impersonating, including those that a namespace admin has.

## **How To Mitigate Potential Threats**

The `escalate`, `bind` and `impersonate` verbs can be used to create flexible permissions, resulting in granular management of access to K8s infrastructure. But these verbs also open the door to malicious use, since, in some cases, they enable a user to access crucial infrastructure components with admin privileges.

Three practices can help you mitigate the potential dangers of misuse or malicious use of these verbs:

1. **Regularly check RBAC manifests.**
    
2. **Use the** `resourceNames` field in the `Role` and `ClusterRole` manifests.
    
3. **Use external tools to monitor roles.**
    

Take a look at each in turn.

### **Regularly Check RBAC Manifests**

To prevent unauthorized access and RBAC misconfiguration, periodically check your cluster RBAC manifests:

```go
kubectl get clusterrole -A -oyaml | yq '.items[] | select (.rules[].verbs[] | contains("esalate" | "bind" | "impersonate"))  | .metadata.name'
 
kubectl get role -A -oyaml | yq '.items[] | select (.rules[].verbs[] | contains("esalate" | "bind" | "impersonate"))  | .metadata.name'
```

### **Use the resourceNames Field**

To restrict the use of `escalate`, `bind`, `impersonate` or any other verbs, configure the `resourceNames` field in the `Role` and `ClusterRole` manifests. There, you can — and should — enter the names of resources that can be used.

Here is an example of a `ClusterRole` that allows creation of a `ClusterRoleBinding` with `roleRef` named `edit` and `view`:

```go
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: role-grantor
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["clusterroles"]
  verbs: ["bind"]
  resourceNames: ["edit","view"]
```

[**view raw**](https://gist.github.com/lovemycodesnippets/72e218bfd0f0b5e76e9f05b7fcfeb015/raw/92cb21681d8ddb18332dd9d62ea34cc11ba31062/cluster-role.yaml)[**cluster-role.yaml**](https://gist.github.com/lovemycodesnippets/72e218bfd0f0b5e76e9f05b7fcfeb015#file-cluster-role-yaml) **hosted with ❤ by** [**GitHub**](https://github.com/)

You can do the same with `escalate` and `impersonate`.

Note that in the case of `bind`, an admin sets permissions for a role, and users can bind that role to themselves only if allowed to do so in `resourceNames`. With `escalate`, users can write any parameters within a role and become admins of a namespace or cluster. So, `bind` restricts users, while `escalate` gives them more options. Keep this in mind if you need to grant these permissions.

### **Use External Tools To Monitor Roles**

Consider using automated systems that monitor creating or editing roles with suspicious content, such as [Falco](https://thenewstack.io/falco-is-a-cncf-graduate-now-what/) or [Tetragon](https://thenewstack.io/tetragon-1-0-promises-a-new-era-of-kubernetes-security-and-observability/).

You can also redirect Kubernetes audit logs to a log management system like [Gcore Managed Logging](https://gcore.com/cloud/managed-logging), which is useful for analyzing and parsing K8s logs. To prevent accidental resource deletion, create a separate service account with the `delete` verb and allow users to impersonate only that service account. This is the principle of least privilege. To simplify this process, you can use the kubectl plug-in [kubectl-sudo](https://github.com/postfinance/kubectl-sudo).

At Gcore, we use these methods to make our [Managed Kubernetes service](https://gcore.com/cloud/managed-kubernetes) more secure; we recommend that all our customers do the same. Using managed services doesn’t guarantee that your services are completely secured by default, but at Gcore, we do everything possible to ensure our customers’ protection, including encouraging RBAC best practices.

## **Conclusion**

The `escalate`, `bind` and `impersonate` verbs allow admins to manage access to K8s infrastructure flexibly and let users escalate their privileges. These are powerful tools that, if abused, can cause significant damage to a K8s cluster. Carefully review any use of these verbs and ensure that the least privileged rule is followed. Users must have the minimum privileges necessary to operate, no more.
