Fine-grained Kubelet API Authorization
Required knowledge for the CKS certification.
The kubelet exposes an HTTPS API on port 10250 covering endpoints for stats, metrics, logs, pod listings, health checks, configuration, and container command execution. Before Kubernetes v1.36, any client that needed access to an endpoint such as /pods or /healthz was forced to be granted nodes/proxy, which covers all kubelet APIs including container command execution.
Kubernetes v1.36 graduates the KubeletFineGrainedAuthz feature to stable, enabling roles to be scoped to specific endpoint groups without granting the overly broad nodes/proxy permission. The official Kubernetes documentation states: "FEATURE STATE: Kubernetes v1.36 [stable] (enabled by default). Kubelet performs a fine-grained check before falling back to the proxy subresource for the /pods, /runningPods, /configz and /healthz endpoints."
1. Why nodes/proxy Was the Only Option
Before: The kubelet mapped every endpoint that did not already have a dedicated subresource (stats, metrics, log, spec, checkpoint) to the proxy subresource. Clients needing /pods, /healthz, or /configz had to be granted nodes/proxy — the same permission that authorizes /exec, /attach, and /run.
After: With KubeletFineGrainedAuthz enabled (the default since v1.36), the kubelet performs a dedicated authorization check for /pods, /runningPods, /configz, and /healthz against new fine-grained subresources before falling back to proxy. Monitoring and observability workloads can be scoped to only those subresources without any access to command execution.
Pre-v1.36 subresource mapping
| Kubelet endpoint | Required subresource |
|---|---|
/stats/* | stats |
/metrics/* | metrics |
/logs/* | log |
/spec/* | spec |
/checkpoint/* | checkpoint |
| all other endpoints | proxy |
Under this mapping, any role needing /pods, /runningPods, /healthz, or /configz had to request nodes/proxy.
2. KubeletFineGrainedAuthz Feature Progression
| Kubernetes version | Status |
|---|---|
| v1.32 | Alpha |
| v1.33 | Beta |
| v1.36 | Stable (enabled by default) |
Version Skew and Managed Clusters
On clusters older than v1.32 the KubeletFineGrainedAuthz feature gate does not exist — the fine-grained subresources (pods, healthz, configz) are unknown to the kubelet, and requests to the affected endpoints are authorized against proxy. On v1.32 and v1.33 the feature is opt-in: the gate must be set to true for the RBAC check against the new subresources to take effect. Managed offerings such as EKS, GKE, and AKS typically lag upstream by several minor releases, so cluster operators should confirm their control plane version before relying on the fine-grained subresources.
3. Kubelet API Subresource Mappings (v1.36)
With KubeletFineGrainedAuthz enabled, the kubelet resolves endpoints as follows:
| Kubelet endpoint | Resource | Accepted subresources |
|---|---|---|
/stats/* | nodes | stats |
/metrics/* | nodes | metrics |
/logs/* | nodes | log |
/spec/* | nodes | spec |
/checkpoint/* | nodes | checkpoint |
/pods | nodes | pods, proxy |
/runningPods/ | nodes | pods, proxy |
/healthz | nodes | healthz, proxy |
/configz | nodes | configz, proxy |
| all other endpoints | nodes | proxy |
For endpoints that list both a fine-grained subresource and proxy, granting the fine-grained subresource alone is sufficient — proxy is not required.
/pods vs /runningPods/
Both endpoints map to the pods subresource, but they return different data:
/podsreturns the kubelet's desired state — the pods the kubelet has been told to run./runningPods/returns the container runtime's view — pods the CRI reports as actually running on the node.
They are not interchangeable. Choose the endpoint that matches what the consumer actually needs.
Endpoints That Still Require nodes/proxy
Endpoints that fall into the "all others" bucket continue to require nodes/proxy. The set includes (non-exhaustively):
/exec/*/attach/*/portForward/*/run/*/cri/*/debug/*
Any workload that legitimately calls one of these — a cluster diagnostic tool, an ephemeral debugging controller — will still need nodes/proxy after migration.
4. Least-privilege RBAC for Monitoring and Observability
Issue: Monitoring systems that only need metrics, pod listings, and health checks previously required nodes/proxy, which also grants container command execution access.
Fix: Scope monitoring and observability ClusterRoles to specific subresources.
Authentication prerequisite
RBAC decides what a caller may do; it does not authenticate the caller to the kubelet in the first place. ServiceAccount token-based clients such as Prometheus also require the kubelet to be configured with --authentication-token-webhook=true, otherwise token-authenticated requests return 401 Unauthorized regardless of the role. See the Kubelet Security Overview for the authentication flags.
Metrics-only role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubelet-metrics-reader
rules:
- apiGroups: [""]
resources: ["nodes/metrics", "nodes/stats", "nodes/log"]
verbs: ["get"]
Pod listing without proxy access
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubelet-pod-reader
rules:
- apiGroups: [""]
resources: ["nodes/pods"]
verbs: ["get"]
Full observability role (no container execution)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubelet-observability
rules:
- apiGroups: [""]
resources:
- "nodes/metrics"
- "nodes/stats"
- "nodes/log"
- "nodes/pods"
- "nodes/healthz"
- "nodes/configz"
verbs: ["get"]
This role grants access to metrics, stats, logs, pod information, health status, and kubelet configuration without any access to container command execution.
Bind the role to a monitoring service account
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus-kubelet-metrics
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring
roleRef:
kind: ClusterRole
name: kubelet-metrics-reader
apiGroup: rbac.authorization.k8s.io
5. The system:kubelet-api-admin ClusterRole
The built-in system:kubelet-api-admin ClusterRole is automatically updated to include permissions for all subresources (proxy, stats, log, metrics, configz, healthz, pods) when KubeletFineGrainedAuthz is enabled. No manual changes are required for the API server's own access to the kubelet.
6. Audit and Verify
Find ClusterRoles that grant nodes/proxy
kubectl get clusterroles -o json \
| jq -r '.items[]
| select(.rules[]?.resources[]? == "nodes/proxy")
| .metadata.name'
Find ClusterRoleBindings that reference those ClusterRoles
kubectl get clusterrolebindings -o json \
| jq -r --argjson names "$(kubectl get clusterroles -o json \
| jq '[.items[] | select(.rules[]?.resources[]? == "nodes/proxy") | .metadata.name]')" '
.items[]
| select(.roleRef.kind == "ClusterRole" and (.roleRef.name | IN($names[])))
| "\(.metadata.name) -> \(.roleRef.name)"'
Review each binding: keep nodes/proxy only where the subject genuinely needs /exec, /attach, /portForward, /run, /cri, or /debug/*.
Verify a new role grants the expected access
Use kubectl auth can-i against the target ServiceAccount to confirm the fine-grained grants and the absence of proxy:
kubectl auth can-i get nodes/metrics \
--as=system:serviceaccount:monitoring:prometheus
# yes
kubectl auth can-i get nodes/pods \
--as=system:serviceaccount:monitoring:prometheus
# yes
kubectl auth can-i get nodes/proxy \
--as=system:serviceaccount:monitoring:prometheus
# no
A no on nodes/proxy combined with yes on the fine-grained subresources confirms the old broad grant has been fully replaced.
Security Checklist
- Control plane is on Kubernetes v1.36+ (KubeletFineGrainedAuthz is enabled by default). On v1.32 or v1.33, enable the feature gate explicitly.
- Audited ClusterRoles and ClusterRoleBindings that reference
nodes/proxy. - Replaced broad
nodes/proxygrants with specific subresources for monitoring and observability tools. - Verified the replacement role with
kubectl auth can-i— fine-grained subresources returnyes,nodes/proxyreturnsno. - Confirmed the kubelet is configured for the caller's authentication method (for ServiceAccount tokens,
--authentication-token-webhook=true). - Reviewed membership of any ClusterRoleBindings that reference
system:kubelet-api-admin.
References
This article is based on information from the following official sources:
- Kubelet Authentication and Authorization - Kubernetes Documentation
- Kubernetes v1.36 Sneak Peek - Kubernetes Blog
- Kubernetes v1.36 Release - Kubernetes Blog