Shared Surface · API Server

API Server

There is one API server, and every tenant talks to it. Worse, a lot of what lives behind it is cluster-scoped and shared by everyone.

In every cluster there is only one logical API server and it’s shared by all the tenants in the cluster, which introduces some security constraints and possible concerns.

Cluster-wide objects

Within a Kubernetes cluster there are a number of things which are cluster-wide, and so can’t be handed over to a namespace-level admin.

  • Custom Resource Definitions (CRDs). Within a given cluster there can only be one version of a CRD in place. This means that when upgrading a CRD, all tenants must be able to upgrade at the same time, and two tenants can’t run different versions of the same operator.
  • Admission webhook configurations. ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects apply across the cluster, so every tenant shares the same admission webhooks (and is affected if one of them breaks).
  • Storage. StorageClasses and PersistentVolumes are cluster-scoped, even though the PersistentVolumeClaims that use them are namespaced.
  • ClusterRoles and ClusterRoleBindings, which can grant access across every namespace.

Even the namespace object itself is a bit of an odd case, which I’ve covered on the RBAC page.

Information leakage

Any tenant with API access is going to learn something about the other tenants. RBAC doesn’t have a way of saying “you can list namespaces, but only see your own”, so in practice tenants either see all the namespace names in the cluster or none of them. Things like the list of installed CRDs also give away what software is running in the cluster.

That might not be a big deal for a couple of internal teams sharing a cluster, but it can be a real concern where tenants are external customers who shouldn’t know about each other.

Shared controllers

The API server isn’t just a database, it’s also the hub for all the controllers that act on the objects tenants create. Those controllers run with their own (often quite powerful) credentials, so a tenant who can create an object a controller acts on is, in effect, asking that controller to do something on their behalf.

This is mostly a problem with third-party operators, which have their own page, but it’s not limited to them. CVE-2026-2270 was a bug in the core StatefulSet controller in kube-controller-manager, which let a tenant with write access to statefulsets and controllerrevisions in their own namespace get a pod created in someone else’s namespace.

Denial of Service

Where tenants have access to create objects in a cluster, there is always a risk of Denial of Service, as they can effectively just keep creating objects till the etcd database runs out of space. Other variations include filling etcd with very large Secret objects, or generating lots of churn through things like pod status updates.

Importantly, the Kubernetes project does not regard this kind of attack as a risk they seek to mitigate, as noted in the severity ratings page. The general view is that anyone who can create objects can DoS the cluster.

There are some things that can help:

  • Resource Quotas can limit the number of objects in a namespace, not just CPU and memory. The multi-tenancy benchmarks recommend setting both, and making sure tenants can’t edit their own quotas.
  • API Priority and Fairness can stop one noisy client from starving everyone else of API server capacity, although it reduces the risk rather than removing it.

Can you avoid sharing it?

The main way of not sharing the API server is to give each tenant their own, either with separate clusters or with virtual clusters, where each tenant gets their own API server running on top of a shared host cluster. That solves the CRD and cluster-scoped resource problems, although with virtual clusters the tenants are still sharing the underlying nodes.

References & further reading

← All shared surfaces