Kubernetes v1.36:细粒度 Kubelet API 授权晋升为 GA

原文链接:https://kubernetes.io/blog/2026/04/24/kubernetes-v1-36-fine-grained-kubelet-authorization-ga/

代表 Kubernetes SIG Auth 和 SIG Node,我们很高兴地宣布:细粒度的 kubelet API 授权在 Kubernetes v1.36 中正式毕业为通用可用性(GA)!

KubeletFineGrainedAuthz 特性门控最初在 Kubernetes v1.32 作为可选的 Alpha 特性引入,随后在 v1.33 升级为 Beta(默认启用)。现在,该特性已正式可用,特性门控被锁定为启用状态。该特性实现了对 kubelet HTTPS API 更精确、最小权限的访问控制,取代了为常见监控和可观测性场景授予过于宽泛的 nodes/proxy 权限的需求。

动机:nodes/proxy 问题

kubelet 暴露了一个 HTTPS 端点,其中包含多个 API,可访问不同敏感程度的数据,包括 Pod 列表、节点指标、容器日志,以及关键的在运行容器中执行命令的能力。

在此特性之前,kubelet 授权采用粗粒度模型。当启用 Webhook 授权时,几乎所有 kubelet API 路径都被映射到单一的 nodes/proxy 子资源。这意味着任何需要从 kubelet 读取指标或健康状态的工作负载都必须拥有 nodes/proxy 权限,而同样的权限也允许在节点上运行的任何容器中执行任意命令。

这有什么问题?

nodes/proxy 授予监控代理、日志收集器或健康检查工具违反了最小权限原则。如果这些工作负载中的任何一个被攻破,攻击者将能够在节点上的每个容器中执行命令。nodes/proxy 权限实际上是一种节点级超级用户能力,广泛授予它会极大地扩大安全事件的爆炸半径。

社区多年来一直清楚理解这个问题(参见 kubernetes/kubernetes#83465),这也是此增强功能 KEP-2862 背后的主要驱动力。

nodes/proxy GET WebSocket RCE 风险

实际情况比表面看起来更严重。安全研究人员在 2026 年初 证明,仅凭 nodes/proxy GET(通常授予监控工具的最小只读权限)就可以被滥用来在可达节点上的任何 Pod 中执行命令。

根本原因是 WebSocket 连接的工作方式与 kubelet 将 HTTP 方法映射到 RBAC 动词的方式之间存在不匹配。WebSocket 协议 (RFC 6455) 要求初始连接握手使用 HTTP GET 请求。kubelet 将此 GET 映射到 RBAC get 动词并授权该请求,而没有进行二次检查以确认后续写操作也具备 CREATE 权限。使用像 websocat 这样的 WebSocket 客户端,攻击者可以直接访问 kubelet 在端口 10250 上的 /exec 端点并执行任意命令。

websocat --insecure \
  --header "Authorization: Bearer $TOKEN" \
  --protocol v4.channel.k8s.io \
  "wss://$NODE_IP:10250/exec/default/nginx/nginx?output=1&error=1&command=id"

```bash
uid=0(root) gid=0(root) groups=0(root)

细粒度 kubelet 授权:工作原理

启用 KubeletFineGrainedAuthz 后,kubelet 现在会在回退到 nodes/proxy 子资源之前,执行一次额外的、更具体的授权检查。几个常用的 kubelet API 路径被映射到它们各自的专用子资源:

kubelet API资源(Resource)子资源(Subresource)
/stats/*nodesstats
/metrics/*nodesmetrics
/logs/*nodeslog
/podsnodespods, proxy
/runningPods/nodespods, proxy
/healthznodeshealthz, proxy
/configznodesconfigz, proxy
/spec/*nodesspec
/checkpoint/*nodescheckpoint
所有其他路径nodesproxy

对于现在拥有细粒度子资源的端点(/pods/runningPods//healthz/configz),kubelet 首先针对特定子资源发送一个 SubjectAccessReview。如果该检查成功,则请求被授权。如果失败,kubelet 会使用粗粒度的 nodes/proxy 子资源重试,以实现向后兼容。

这种双重检查方法确保了平滑的迁移路径。拥有 nodes/proxy 权限的现有工作负载可以继续工作,而新部署可以从一开始就采用最小权限访问。

实际意义

考虑一个需要从 kubelet 抓取 /metrics 的 Prometheus 节点导出器(node exporter)或监控 DaemonSet。以前,你需要一个类似这样的 RBAC ClusterRole

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-node-exporter
rules:
- apiGroups: [""]
  resources: ["nodes/proxy"]
  verbs: ["get"]
# Old approach: overly broad
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-agent
rules:
- apiGroups: [""]
  resources: ["nodes/proxy"]
  verbs: ["get"]

这赋予了监控代理(monitoring agent)远超其所需的访问权限。通过细粒度授权(fine-grained authorization),现在可以精确地限定权限范围:

# New approach: least privilege
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-agent
rules:
- apiGroups: [""]
  resources: ["nodes/metrics", "nodes/stats"]
  verbs: ["get"]

监控代理现在可以从 kubelet 读取指标(metrics)和统计信息(stats),而无需具备在容器中执行命令的能力。

更新后的 system:kubelet-api-admin ClusterRole

当启用 RBAC 授权时,内置的 system:kubelet-api-adminClusterRole 会自动更新,包含所有新的细粒度子资源(fine-grained subresources)的权限。这确保了已经使用此角色的集群管理员(包括 API 服务器的 kubelet 客户端)无需任何手动配置更改即可继续拥有完全访问权限。

该角色现在包含以下权限:

  • nodes/proxy
  • nodes/stats
  • nodes/metrics
  • nodes/log
  • nodes/spec
  • nodes/checkpoint
  • nodes/configz
  • nodes/healthz
  • nodes/pods

升级注意事项

由于 kubelet 执行双重授权检查(先检查细粒度权限,然后回退到 nodes/proxy),升级到 v1.36 对大多数集群来说应该是无缝的:

  • 现有工作负载 拥有 nodes/proxy 权限的无需更改即可继续工作。回退到 nodes/proxy 确保了向后兼容性。
  • API 服务器 始终通过 system:kubelet-api-admin 拥有 nodes/proxy 权限,因此无论特性门控(feature gate)状态如何,kube-apiserverkubelet 的通信都不受影响。
  • 混合版本集群 能够优雅处理。如果 kubelet 支持细粒度授权但 API 服务器不支持(反之亦然),nodes/proxy 权限将作为回退。

验证特性已启用

你可以通过检查 kubelet 指标端点(metrics endpoint)来确认该特性在给定节点上是否已激活。由于端口 10250 上的指标端点需要授权,你首先需要为发起请求的 Pod 或 ServiceAccount 创建适当的 RBAC 绑定。

步骤 1:创建 ServiceAccount 和 ClusterRole

apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubelet-metrics-checker
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kubelet-metrics-reader
rules:
- apiGroups: [""]
  resources: ["nodes/metrics"]
  verbs: ["get"]

步骤 2:将 ClusterRole(集群角色)绑定到 ServiceAccount(服务账户)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubelet-metrics-checker
subjects:
- kind: ServiceAccount
  name: kubelet-metrics-checker
  namespace: default
roleRef:
  kind: ClusterRole
  name: kubelet-metrics-reader
  apiGroup: rbac.authorization.k8s.io

应用两个清单(manifests):

kubectl apply -f serviceaccount.yaml
kubectl apply -f clusterrole.yaml
kubectl apply -f clusterrolebinding.yaml

步骤 3:使用 ServiceAccount(服务账户)运行一个 Pod(容器组)并检查功能标志

kubectl run kubelet-check \
  --image=curlimages/curl \
  --serviceaccount=kubelet-metrics-checker \
  --restart=Never \
  --rm -it \
  -- sh

然后,在 pod(容器组)内部,获取节点 IP(节点 IP 地址)并查询 metrics 端点(指标端点):

# Get the token
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

# 查询 kubelet 指标并过滤特性门控
curl -sk \
  --header "Authorization: Bearer $TOKEN" \
  https://$NODE_IP:10250/metrics \
  | grep kubernetes_feature_enabled \
  | grep KubeletFineGrainedAuthz

如果该特性已启用,你应该会看到类似如下的输出:

kubernetes_feature_enabled{name="KubeletFineGrainedAuthz",stage="GA"} 1

注意:$NODE_IP 替换为你想要检查的节点 IP 地址。你可以通过 kubectl get nodes -o wide 获取节点 IP。

从 Alpha 到 GA 的历程

发布版本阶段详情
v1.32Alpha引入特性门控 KubeletFineGrainedAuthz,默认禁用
v1.33Beta默认启用;对 /pods/runningPods//healthz/configz 进行细粒度检查
v1.36GA特性门控锁定为启用;细粒度 kubelet 授权始终生效

下一步计划?

随着细粒度 kubelet 授权进入 GA 阶段,Kubernetes 社区可以开始推荐并最终强制要求使用特定子资源(subresource)替代 nodes/proxy 来执行监控和可观测性工作负载。这一迁移的紧迫性源于研究表明 nodes/proxy GET 可能通过 WebSocket 协议被滥用,导致未记录日志的远程代码执行。该风险存在于数十个广泛部署的 Helm Chart 的默认 RBAC 配置中。随着时间的推移,我们预计:

  • 生态系统采用: Prometheus、Datadog 代理等监控工具以及其他 DaemonSet 可以更新其默认 RBAC 配置,使用 nodes/metricsnodes/statsnodes/pods 替代 nodes/proxy。这将直接消除这些工作负载的 WebSocket RCE 攻击面。
  • 策略执行: 准入控制器(Admission Controller)和策略引擎(Policy Engine)可以在存在细粒度替代方案时标记或拒绝授予 nodes/proxy 的 RBAC 绑定,帮助组织大规模采用最小权限访问。
  • 弃用路径: 随着采用率的增长,nodes/proxy 最终可能会在监控场景中被弃用,从而进一步减少 Kubernetes 集群的攻击面。

参与贡献

这一增强功能由 SIG Auth 和 SIG Node 推动。如果你有兴趣为 Kubernetes 的安全和授权功能做出贡献,请加入我们:

我们期待听到你对这一功能的反馈和使用体验!