July 17, 2023
Kubernetes RBAC: Paths for Privilege Escalation
Describing privilege escalation paths within Kubernetes' RBAC authorization scheme.
This is the first post of our Kubernetes security series. In this series we explain and showcase common weak points of enterprise Kubernetes clusters. Many of the described vulnerabilities we encounter when performing Cloud Security Assessments for our customers.
This series consists of four parts. We will update the links as soon as the following parts are published:
- Part I: Kubernetes RBAC: Paths for Privilege Escalation
- Part II: Kubernetes RBAC: Hands on Privilege Escalation
- Part III: Protecting Kubernetes: Common Admission Controller (Mis)Configurations
- Part IV: Extending RBAC: Making Use of Admission Controllers to Automate Permission Management
Kubernetes is a widely used open-source container orchestration system that helps to reduce workloads when dealing with container management in distributed systems. If you are interested in learning more about Kubernetes, the official documentation (1) is a good place to start. Its built-in authorization module (2) - which is based on role-based access control principles - is enabled by default and provides authorization mechanisms that prevent unauthorized access to resources. However, certain permissions enable their subject - here referred to as entity (users, groups, service accounts) - to escalate their privileges to a potentially Cluster compromising extent. In this post, we present various ways to escalate privileges within a Kubernetes Cluster and provide explanations as to how an exploit might work.
Privilege Escalation Threats
In total, this post contains 7 different known privilege-escalation threat-vectors, which are enabled by the following permissions:
- create Pods
- read Secrets
- bind Roles
- escalate existing Roles
- impersonate entities in the Cluster
Let’s have a high-level look at what the threats are and why they are caused by these permissions.
Pod Creation
Pods are the basic work unit of every Kubernetes Cluster. Each Pod consists of at least one container, which, in turn, runs an application. In short: If you are using Kubernetes, you are using Pods.
One might be wondering: Why does a basic permission that is essentially the most widely-used feature of Kubernetes pose a privilege escalation threat? It’s because of (overprivileged) containers! While the RBAC system does enforce that only authorized users can create Pods, it does not enforce what these users can put into their Pod definitions. Without proper admission control (3) , users who are authorized to create Pods can use arbitrary images to create containers packed with arbitrary privileges and configurations. The following subsections outline the corresponding exploitation scenarios.
Mounting a Service Account Token
Pod definitions can specify the option to automatically mount (4) the authorization token for a service account within the same namespace. With this in mind, creating Pods can simply be used as a mechanism to gain the authorization token of some high-privileged target service account and then proceed to perform API actions with that token. To achieve this, an attacker might create a Pod that is based on a backdoor-containing image and simply steal the token.
Obtaining Access to a Cluster node
If an entity is allowed to create arbitrarily privileged containers (e.g. a lack of comprehensive admission control), it is possible to spawn vulnerable Pods that allow an attacker to gain easy access to the corresponding container and more importantly, potentially access to the underlying node within the Cluster. Various examples (5) exist that illustrate a simple way of doing this. Essentially this method consists of 2 steps: Gaining access to the container and then escaping the container by means of traditional container escape techniques.
Obviously, having access to any node within a Cluster is a major breach in and of itself. However, in terms of privilege escalation within Kubernetes, this can have even larger consequences. By gaining access to the node, an attacker could either:
- use the underlying container engine to access mounted Serviceaccount tokens of any Pod that is running on the same node
- search for application information and configuration files on the node that potentially expose further parts of the Cluster
- discover hosts and services on the network that are not related to Kubernetes (e.g. DNS Servers)
By exploiting this vulnerability the attacker gains access to the Kubernetes node, which increases the attack surface significantly.
Secret Reading
It goes without saying that the permission to read Secrets - in any system - should be given with caution. This is also true in the context of Kubernetes RBAC. In Kubernetes, Secrets can be used to store application-critical configuration data in the Cluster in a relatively secure manner. Being able to read these Secrets is a very valuable position to be in. More importantly, authorization tokens of existing Serviceaccounts are also stored as a Secret in the Serviceaccounts' corresponding namespace. In consequence, anyone who is able to read Secrets within a namespace can steal these authorization tokens and essentially owns the respective Serviceaccounts' permissions.
Brute-Forcing Secrets
In terms of permission verbs (6) , Kubernetes makes a distinction between the verbs get, and list. While list allows an entity to retrieve a collection of the respective resource, get only allows the retrieval of single resource objects. This means that if an entity possesses the get permission on Secrets, it needs to know the exact name of that Secret in order to get its information.
(Un)Fortunately, Kubernetes adheres to a certain pattern with which it automatically creates Secrets that belong to service accounts. The pattern goes <service-account-name>-token-<5-digit-alphanumeric>
. Consequently, finding the correct 5-digit alphanumeric combination for a given service account can be done in a matter of hours.
Impersonation
In Kubernetes, impersonation (7) is a mechanism that allows an entity to act as another entity while performing API requests. This can be useful for administrators of the Cluster to check whether implemented configurations (e.g. newly created Roles) work as intended. However, attackers can use this mechanism to act as higher-privileged entities.
Impersonation is done by adding the impersonation header: Impersonate-User: <user>
to the API request that is being sent to Kubernetes. Kubernetes first checks whether impersonation on the target is allowed and then proceeds as if the impersonated entity has made the request.
Impersonating service accounts works similarly, but requires a little bit more specification within the username field. The respective header looks like this: Impersonate-User: system:serviceaccount:<namespace>:<service-account-name>
Impersonating a group is done in the same way, with the difference of having to provide the Impersonate-Group
header instead of the Impersonate-User
header.
Bind
Theoretically, possessing the permission to create Rolebindings in Kubernetes is powerful as one could assign Roles or Clusterroles to oneself in order to obtain those permissions. However, Kubernetes does not allow binding Roles that possess more privileges than already held, if not explicitly allowed with the bind verb.
Binding Roles
If an entity holds both, the permission to create Rolebindings and the permission to bind Roles, it can assign arbitrary Roles to itself and elevate its privileges depending on the Roles available in the namespace in which these permissions are available on.
Binding Clusterroles within a namespace
If an entity holds the permissions to create Rolebindings and bind Clusterroles, it is permitted to bind the permissions of a Clusterrole to the respective namespace. This is a generally greater privilege escalation than the first variant.
Binding Clusterroles cluster-wide
Finally, if an entity holds the permissions to create Clusterrolebindings and bind Clusterroles, it is permitted to gain the highest possible permissions within the Cluster by binding the permissions of the most privileged entities within the kube-system
namespace to itself.
Escalate
Let’s say an entity possesses the permissions to create Roles or update existing Roles. Attackers could abuse this to update Roles that are already assigned to them to contain the highest of privileges. However, this is not permitted by Kubernetes as it disallows creating Roles with permissions that are not already held. This is where escalate chimes in. Escalate is a verb that specifically exists to allow entities to create or edit Roles and Clusterroles that grant permissions that they themselves currently do not possess. If an entity has the permission to create/update Roles or Clusterroles and additionally possesses the permission to escalate, it can assign arbitrary permissions to itself.
Next Post
While this post has focused on explaining the theory of existing privilege escalation techniques within the Kubernetes' RBAC module, the next post will showcase hands-on examples of exploitation performed on a locally running kind
(8)
Cluster.
If you liked this post, dont forget to follow us on Twitter
, LinkedIn
, Xing
to stay up-to-date with our latest content!