Skip to content

Secure the Kubernetes API server

Severity: criticalApplies to: Kubernetes 1.29+ (self-managed)Applies to: Kubernetes 1.34
The fix/etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --anonymous-auth=false
- --authorization-mode=Node,RBAC
- --profiling=false
- --audit-log-path=/var/log/kubernetes/audit.log

On a managed cluster (EKS/GKE/AKS) this is the provider’s job — you can’t set these flags, and shouldn’t need to. This page is for self-managed control planes.

The API server is the single front door to everything: workloads, secrets, RBAC, nodes. Every kubectl command, every controller, every pod’s service account talks to it. Compromise it and you have the cluster; expose it carelessly and you invite the attempt.

Three flags carry most of the risk.

--anonymous-auth=true lets requests that present no credentials through to the authorization stage as the user system:anonymous. On its own that’s not fatal — RBAC still has to grant anonymous something — but it’s a foot-gun: a single over-broad ClusterRoleBinding to system:unauthenticated (which people create by accident, or copy from a bad tutorial) turns anonymous into real access.

--anonymous-auth=false removes the category. There’s rarely a reason for anonymous API access; the health endpoints that legitimately need it (/livez, /readyz) can be allowed explicitly.

--authorization-mode=Node,RBAC is what you want. The danger values:

  • AlwaysAllow — every authenticated request is permitted. RBAC is not consulted. This is catastrophic and occasionally appears in dev clusters that escaped to production.
  • Missing RBAC — if RBAC isn’t in the authorizer chain, none of your carefully scoped roles are enforced.

Node restricts what kubelets can read to what their own pods need; RBAC enforces everything else. Both, in that order.

Don’t expose it, and mind the unauthenticated endpoints

Section titled “Don’t expose it, and mind the unauthenticated endpoints”

The API server should be reachable by your operators and nodes, not the internet. On a self-managed cluster that means binding it appropriately and firewalling 6443. Even authenticated, an internet-facing API server is a continuous brute-force and CVE target.

And a few endpoints answer before authentication:

  • /healthz, /livez, /readyz — fine, but they confirm a cluster is there.
  • /metrics — should require auth; unauthenticated metrics leak cluster internals.
  • --profiling=true exposes /debug/pprof, which can leak memory contents. Turn it off in production.