A role that grants permission to create or modify
(Cluster)RoleBindings can allow an attacker to escalate privileges on a compromised user.
|PermissionSet||PermissionSet||Valid Accounts, T1078|
An attacker with sufficient permission can create a
RoleBinding with the default existing admin
ClusterRole and bind it to a compromised user. By creating this
RoleBinding, the compromised user becomes highly privileged, and can execute privileged operations in the cluster (reading secrets, creating pods, etc.).
To exploit the attack we need to:
- Be able to
- Be able to
To fully understand the attacks we need to know the basic around RBAC in kubernetes:
- Roles and role bindings must exist in the same namespace.
- Role bindings can exist in separate namespaces to service accounts.
- Role bindings can link cluster roles, but they only grant access to the namespace of the role binding.
- Cluster role bindings link accounts to cluster roles and grant access across all resources.
- Cluster role bindings can not reference roles.
In KubeHound we added an abstraction called PermissionSet which is an object that link the RoleBinding and the Role directly (in one object). When creating every PermissionSet all the above rules are enforced to make sure the scope is valid.
In the bind attack there is 2 levels to checks:
- The PermissionSet itself (rolebinding/role) which will grant the role to designated subject
- The actual verbs allowed by the PermissionSet. We are looking for the verbs
To test all usecases, we created unit tests for each:
- CRB_CR: regroup all the PermissionSets with ClusterRoleBinding / ClusterRole.
- RB_CR-SA: regroup all the PermissionSets with RoleBinding/ClusterRole for a Service Account.
- RB_R-SA: regroup all the PermissionSets with RoleBinding/Role for a ServiceAccount.
- RB_R-UG: regroup all the PermissionSets with RoleBinding/Role for Users/Groups.
But, the PermissionSet object is created only if a role is linked by a rolebinding, this imply:
- If a role is not linked by a role binding, no PermissionSet will be created in the graph. Therefore this role can not be used in any attack paths (there is no direct role abstraction)
- All the PermissionSet are created from at the ingestion time. Currently no attacks create new assets in the graph. It means only the "existing" PermissionSet can be used in the attack path generation.
So some of the usecases are not fully covered:
|Usecase #||Coverage||Limitation description|
|2||Limited||All the PermissionSet that are not namespaced are linked to a single specific namespace. Yet, this attack allow to bind a role to any namespace. Therefore, we would need to create additional PermissionSet for every namespace if we want to fully cover the attack|
|4||None||To cover this usecase, we need duplicate a non-namespaced PermissionSet to a namespace one.|
Limitation of the can-i Kubernetes API
The PermissionSet (linked by RoleBinding/Role) allows access to namespaced objects only. So even if the verb allows you to
ClusterRole, it will not work because those objects are not namespaced. With this PermissionSet (RB/R), the scope is only namespaced objects.
K8s API will let you create invalid configs, it is considered as "a feature of Kubernetes RBAC". For instance you can create RBAC that will give you rights to allow the educate right on dolphin objects. So Kubernetes won't warn you if you get something wrong, because it doesn’t have a list of what “right” looks like. So when asking the
can-i API from Kubernetes, it will tell you that you can
ClusterRole because it will only process a "regex check".
Asking the API if I can create/bind:
root@rolebind-pod-rb-r-crb-cr-fail:/# ./kubectl auth can-i create clusterrolebindin Warning: resource 'clusterrolebindings' is not namespace scoped in group 'rbac.authorization.k8s.io' yes root@rolebind-pod-rb-r-crb-cr-fail:/# ./kubectl auth can-i bind clusterrole Warning: resource 'clusterroles' is not namespace scoped in group 'rbac.authorization.k8s.io' yes
Exploiting the attack fails (as expected):
root@rolebind-pod-rb-r-crb-cr-fail:/# ./kubectl create clusterrolebinding rolebindadmin --clusterrole=cluster-admin --serviceaccount=default:rolebind-sa-rb-r-crb-cr-fail error: failed to create clusterrolebinding: clusterrolebindings.rbac.authorization.k8s.io is forbidden: User "system:serviceaccount:default:rolebind-sa-rb-r-crb-cr-fail" cannot create resource "clusterrolebindings" in API group "rbac.authorization.k8s.io" at the cluster scope root@rolebind-pod-rb-r-crb-cr-fail:/# ./kubectl create clusterrolebinding rolebindadmin --clusterrole=cluster-admin --serviceaccount=default:rolebind-sa-rb-r-crb-cr-fail -n default error: failed to create clusterrolebinding: clusterrolebindings.rbac.authorization.k8s.io is forbidden: User "system:serviceaccount:default:rolebind-sa-rb-r-crb-cr-fail" cannot create resource "clusterrolebindings" in API group "rbac.authorization.k8s.io" at the cluster scope
Tests User/Group RBAC in kind cluster
Users and groups have been created in the Kind Cluster. Each user have it is own kubeconfig file. They are located in the
- KUBECONFIG=test/setup/test-cluster/RBAC/user-rb-r-crb-cr-fail/kubeconfig kubectl auth can-i bind clusterrole
Ability to interact with the K8s API with a role allowing modify or create access to
(Cluster)RoleBindings. Pods config for all the use cases:
- ROLE_BIND_CRB_CR: ClusterRoleBinding / ClusterRole
- ROLE_BIND_RB_CR-SA: RoleBinding / ClusterRole for ServiceAccounts
- ROLE_BIND_RB_R-SA: RoleBinding / Role for ServiceAccounts
- ROLE_BIND_RB_R-UG: RoleBinding / Role for Users/Groups
The following file regroups some assets needed to exploit/test the attacks ROLE_BIND_ALL:
AdminRole not bind to any account in the default namespace. This can be bind using
./kubectl create rolebinding rbr-admin --role=admin --serviceaccount=$SAS -n defaultfor instance.
- Instance (in vault namespace) into reach from the role bind exploitation:
./kubectl get pods -n vault
Installing required binary (jq / curl / kubectl)
Simply ask kubectl:
Note: in one edge case (describe earlier), using
can-i Kubernetes API is not enough.
(Cluster)RoleBinding definition as below:
Create the binding via kubectl:
Retrieving service account information (needed to bind the role):
Exploiting the attack using only the kubectl command:
admin is not a standard role, it has been added manually in the kind cluster.
- Monitor anomalous access to the K8s authorization API including creating privileged
(Cluster)RoleBindingfrom with a pod, unusual
User-Agentheaders and other outliers.
Implement least privilege access
(Cluster)RoleBinding is a very powerful privilege and should not be required by the majority of users. Use an automated tool such a KubeHound to search for any risky permissions and users in the cluster and look to eliminate them.
- RoleBind - UseCase 1
- RoleBind - UseCase 2
- RoleBind - UseCase 3
- RoleBind - UseCase 4 - not implemented yet
- Official Kubernetes Documentation:Using RBAC Authorization
- Securing Kubernetes Clusters by Eliminating Risky Permissions
- Getting into a bind with Kubernetes
- Official Kubernetes Documentation: Bind verb
- Official Kubernetes Documentation: RBAC rules
- Mixing Kubernetes Roles, RoleBindings, ClusterRoles, and ClusterBindings
- RBAC Virtual Verbs: Teaching Kubernetes to Educate Dolphins