Tools · Containers and Kubernetes security · 10 / 20
Checking Kubernetes exposure: public API servers, anonymous auth, and kubelet ports
Verify from outside and inside that your API server and kubelets do not accept anonymous requests, and restrict who can reach the control plane.
The network surfaces
The API server usually listens on 6443 (or 443 on managed services). Each kubelet listens on 10250 for its authenticated API and historically on 10255 for a read-only port. etcd listens on 2379 and should only be reachable by the API server. A dashboard or other admin UI exposed through a LoadBalancer service is another common mistake.
Settings that close them
On the API server, --anonymous-auth=false or tight RBAC for system:anonymous ensures unauthenticated requests get nothing useful. On kubelets, set authentication.anonymous.enabled: false, authorization.mode: Webhook, and readOnlyPort: 0. On managed clusters, enable private endpoints or authorized IP ranges for the API server.
Lab: test your own lab cluster
From a machine allowed to reach your lab cluster, send unauthenticated requests. A hardened API server returns 401 for anonymous requests to most paths, or 403 if anonymous is enabled but has no permissions. /version and /healthz may be readable by design. On the node, check the kubelet configuration and whether 10255 is listening. Only run these checks against clusters you own.
curl -sk https://<api-server>:6443/api/v1/namespaces -o /dev/null -w '%{http_code}\n'
curl -sk https://<api-server>:6443/version
curl -sk https://<node-ip>:10250/pods -o /dev/null -w '%{http_code}\n'
kubectl get clusterrolebindings -o json | jq -r '.items[] | select(.subjects[]?.name=="system:anonymous" or .subjects[]?.name=="system:unauthenticated") | .metadata.name'Interpreting results
A 200 with a namespace list from an unauthenticated request is a critical finding. Any ClusterRoleBinding to system:anonymous or system:unauthenticated beyond the defaults for discovery and health endpoints should be removed. Put the API server behind a private endpoint and use a VPN or bastion with SSO for administrators.
Diagram
Unauthenticated requests to a lab cluster
What good and bad look like.
Hardened API server
GET /api/v1/namespaces (no token)
401 Unauthorized
Misconfigured API server
GET /api/v1/namespaces (no token)
200 OK with namespace list
Hardened kubelet
GET https://node:10250/pods (no token)
401 Unauthorized
Check yourself
1. Which port does the kubelet’s authenticated API use?
2. Which kubelet setting disables the legacy read-only port?
3. An unauthenticated request returns a list of namespaces. What is the likely cause?