Kubernetes authorization is a vital but complex part of cluster security, where mistakes can have serious consequences in allowing attackers to establish and expand their access to critical resources. With that in mind we decided to examine how role-based access control (RBAC) is configured in real-world clusters. Specifically, we looked at bindings that can grant some of the built-in principals wide-ranging access to cluster resources.
We examined over 65,000 clusters from almost 10,000 organizations to understand what the real-world usage of these principals looked like.
Background: How do Kubernetes built-in principals work?
Kubernetes provides a number of built-in users and groups that can have permissions assigned to them.
Unauthenticated users who make requests to the Kubernetes API server are assigned a username of system:anonymous and a group of system:unauthenticated. As such, any permissions granted to those subjects are given to any caller who can reach the API server at a network level. In most clusters, these permissions allow access to endpoints such as /healthz, which is used for cluster monitoring.
However, there are some configuration options that change how the API server handles requests without credentials. If the API server has --anonymous-auth=false set, then requests without credentials will always be rejected. Additionally, Kubernetes v1.34 introduced a feature that allows cluster administrators to restrict anonymous access to a specific list of paths, regardless of what RBAC settings are in place.
The third principal that we're looking at in this blog post, system:authenticated, is a group that includes every user with valid credentials for the cluster. Administrators can use this group to grant permissions that every authenticated user in the cluster requires.
Distribution defaults
Of course, most clusters do not run on upstream Kubernetes but instead use one of the available Kubernetes distributions. In our dataset, most of the clusters ran on Amazon Elastic Kubernetes Service (Amazon EKS), Google Kubernetes Engine (GKE), or Microsoft's Azure Kubernetes Service (AKS), so it's worth mentioning the relevant access-control defaults for each before getting into the data:
- AKS is one of the few distributions that uses the
--anonymous-auth=falsesetting. So, any permissions granted to the anonymous principals have no effect, and an AKS API server will reject any request without valid credentials. - EKS allows anonymous access. However, since v1.32 (before the upstream feature was generally available), EKS has restricted the endpoints that can be exposed without credentials. As a result, bindings to the anonymous principals don't have any effect.
- GKE allows anonymous access and, like EKS, limits the endpoints that can be accessed without credentials (but from v1.35 in this case). GKE also has an unusual way of handling access to
system:authenticated, as by default it allows any user with a valid Google account to have that access to any GKE cluster. (More details are available in Orca's research post on the topic.) It is now possible to block access from arbitrary Google accounts at cluster creation, but the default still stands.
Data analysis
With the background information covered, what did we see in our data? Across the clusters in the dataset, there were over 320,000 bindings to one of the three principals we're focusing on. Of those, we eliminated 265,000 because they were the default bindings that ship with base Kubernetes (system:basic-user, system:discovery, and system:public-info-viewer). That left us about 55,000 bindings to analyze.
The next group that we excluded was interesting: 11,000 bindings related to podsecuritypolicy objects. Kubernetes Pod Security Policies were removed as a feature in Kubernetes v1.25, which was released in August 2022, and are no longer supported on any major Kubernetes distribution. While having these objects in clusters doesn’t have any negative impact on cluster behavior, their presence suggests that the RBAC configurations in those clusters are not being regularly maintained.
After removing those 11,000 bindings from our dataset, we had 44,000 bindings to our three built-in principals. This number is notable because it points to substantial use of these principals, which can leave clusters dangerously exposed when the principals have broad permissions. From a purely security perspective, except when information is intended to be public, use of these principals is unlikely to meet the definition of least privilege. So, the fact that these principals appear in bindings at all tells us that many clusters could have their security improved with tightened authorization.
The next question, of course, is how many of the bindings grant dangerous permissions. This question is very difficult to answer definitively because factors such as cluster posture, usage, and other controls might reduce the impact of a permissive RBAC binding.
We looked at permissions that are dangerous at the RBAC level. To that end, we used the following definition of dangerous:
Although these aren't the only permissions that can be dangerous in Kubernetes, it seems reasonable to state that they shouldn't be granted to principals such as system:authenticated, system:anonymous, or system:unauthenticated.
We found over 3,500 bindings that granted at least one of the permissions in that dangerous list. As a percentage of our starting 320,000 bindings, that's a relatively low fraction. However, it does still show a level of risk and exposure across Kubernetes clusters for a set of permissions that you'd hope would rarely, if ever, be granted. Although there might be some cases where this kind of access makes sense, these findings also suggest that many clusters have excessive permissions and could benefit from review and tightening of their RBAC rules.
Another point worth noting here is that the bindings were not just at the cluster level; there were also namespace-scoped bindings. In cases where multi-tenant clusters are providing "namespace as a service," a namespace-level admin can expose the overall cluster to risks by creating bindings to principals such as system:unauthenticated.
Conclusion
In general, there seems to be fairly limited use of these principals in the dataset that we examined. However, there were quite a few cases where excessive permissions had been applied. Another theme was the number of redundant RBAC bindings, which makes cluster security administration and auditing more cumbersome, showing a need for more regular maintenance of Kubernetes RBAC.
While it's good to see major distributions making changes to defaults to improve security, it's important to note that these changes aren’t going to be universal across distributions. So, care is needed in ensuring that your clusters are not exposed to attack by RBAC misconfigurations.