Kubernetes 三个「不修」的 CVE 记录即将更正:你的扫描器可能突然报警

2026-05-27 27 预计阅读时间:1 分钟
来源:kubernetes.io AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:12 分钟

Kubernetes 安全响应委员会(SRC)发现,几个已公开多年的 CVE 记录存在一个关键错误——它们标注了"已修复版本",但实际漏洞从未被修补。2026 年 6 月 1 日,这些记录将被更正为"所有版本受影响"。这意味着你的漏洞扫描器可能在原本"安全"的集群上突然报出新的告警。本文拆解三个未修复 CVE 的技术机理,并给出可立即执行的缓解配置。

为什么现在才改记录?

起因是 Kubernetes 近期在生成官方 OSV(Open Source Vulnerabilities)文件时,交叉比对发现 CVE 数据库里的版本信息与实际代码状态不一致。几个 CVE 的记录暗示"升级到某版本就安全了",但事实是:这些问题的根源在于架构设计取舍,无法在不破坏核心功能的前提下通过代码修复。

更正记录的意义不只是"数据准确":

  • 自动化保真度:扫描器依赖精确的版本范围判断。错误的"已修复"标记导致假阴性——你以为安全,其实不然。
  • 风险文档化:正式标记为"未修复",迫使平台运维者正视持续存在的风险,主动采用配置层面的缓解手段。

三个未修复漏洞的技术拆解

CVE-2020-8561:kube-apiserver Webhook 重定向(中危,4.1)

kube-apiserver 在与 Admission Webhook 通信时遵循 HTTP 重定向。能配置 AdmissionWebhookConfiguration 的攻击者,可以把 API Server 的请求重定向到集群内部私有网络地址,实现信息泄露。

为什么不修:限制重定向行为意味着打破标准 HTTP 客户端语义,大量合法集成依赖这一行为。

缓解:降低日志详细度、关闭动态 profiling,防止攻击者通过日志获取响应体内容或擅自提升日志级别。

CVE-2020-8562:API Server 代理 DNS TOCTOU 绕过(低危,3.1)

API Server 代理在验证用户请求的目标 IP 时先做一次 DNS 解析(检查),建立连接时再做一次(使用)。两次解析之间的时间窗口构成 TOCTOU 竞态条件——攻击者可以操纵第二次解析结果,绕过 IP 限制。

为什么不修:要消除竞态,需要把第一次解析的 IP"钉住"用于连接,但这会破坏 split-horizon DNS 和动态 IP 环境下的正常行为。

缓解:在控制面节点部署本地 DNS 缓存,强制两次解析返回一致结果。

CVE-2021-25740:跨 Namespace 转发 via Endpoints(低危,3.1)

Endpoints 和 EndpointSlice API 允许用户手动指定 IP 地址。拥有 Endpoints 写权限的用户可以把 LoadBalancer 或 Ingress 的后端指向其他 Namespace 中的服务 IP,实现跨 Namespace 流量转发。

为什么不修:手动指定 IP 是 Endpoints API 的基础设计,大量网络工具和 Operator 依赖此能力。

缓解:收紧 Endpoints/EndpointSlice 的写权限。Kubernetes 1.22 起,默认 editadmin ClusterRole 已不再包含这些权限,但从旧版本升级的集群需要手动审计。

另外,CVE-2020-8554 也是未修复 CVE,其记录本身已正确标注"所有版本受影响",此次仅更新版本号格式以符合标准化要求。

立即可执行的缓解配置

以下命令和配置可以直接在非生产环境验证后部署。

1. 锁定 API Server 日志级别和 profiling(CVE-2020-8561)

检查当前 kube-apiserver 启动参数:

# 查看当前 apiserver 的 --v 和 --profiling 设置
ps aux | grep kube-apiserver | grep -oE '\-\-v=[0-9]+|\-\-profiling=[a-z]+'

如果 --v 大于等于 10 或 --profiling 为 true,需要修改。编辑 apiserver 的静态 Pod 配置(常见于 kubeadm 部署):

# 备份后编辑
cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak

# 用 sed 修改 --v 和 --profiling
sed -i 's/--v=10/--v=9/' /etc/kubernetes/manifests/kube-apiserver.yaml
# 如果没有 --profiling 参数,追加;如果已有且为 true,改为 false
grep -q '\-\-profiling' /etc/kubernetes/manifests/kube-apiserver.yaml && \
  sed -i 's/--profiling=true/--profiling=false/' /etc/kubernetes/manifests/kube-apiserver.yaml || \
  sed -i '/- kube-apiserver/a\    - --profiling=false' /etc/kubernetes/manifests/kube-apiserver.yaml

# kubelet 会自动检测变更并重启 apiserver,等待其就绪
kubectl get componentstatuses
# 或在新版本中:
kubectl get --raw='/healthz?verbose=true' | grep kube-apiserver

注意--v=9 仍然保留较详细的日志,只是不再记录响应体。如果你的审计要求更低级别,可以设为 --v=4 或更低,但会牺牲大量调试信息。

2. 控制面节点部署 dnsmasq 缓存(CVE-2020-8562)

在控制面节点上用 dnsmasq 做 DNS 缓存,缩小 TOCTOU 窗口:

# 在控制面节点安装 dnsmasq(Ubuntu/Debian 示例)
apt-get update && apt-get install -y dnsmasq

# 写入配置,强制最小缓存 TTL 为 60 秒
cat > /etc/dnsmasq.conf << 'EOF'
# 监听本地回环,仅服务本机
listen-address=127.0.0.1
bind-interfaces

# 最小缓存 TTL:DNS 响应即使 TTL 更短也至少缓存 60 秒
# 这确保"检查"和"使用"两次解析拿到相同结果
min-cache-ttl=60

# 上游 DNS 服务器(替换为你的实际上游)
server=8.8.8.8
server=8.8.4.4

# 不转发本地解析的 kubernetes 内部域名到上游
# 这些由集群 CoreDNS 处理
local=/cluster.local/
server=/cluster.local/10.96.0.10  # CoreDNS Service ClusterIP
EOF

systemctl enable dnsmasq && systemctl restart dnsmasq

# 修改控制面节点的 /etc/resolv.conf,把 127.0.0.1 放在最前
# 如果使用 systemd-resolved,需要额外配置;以下为传统 resolv.conf 方式
sed -i '1i\nameserver 127.0.0.1' /etc/resolv.conf

# 验证缓存生效
dig +short kubernetes.default.svc.cluster.local @127.0.0.1
# 第二次查询应命中缓存,响应时间显著缩短
dig +short kubernetes.default.svc.cluster.local @127.0.0.1

注意:如果你的控制面节点使用 systemd-resolved(Ubuntu 18.04+ 默认),需要让 dnsmasq 和 systemd-resolved 协作,或直接配置 systemd-resolved 的最小缓存 TTL。生产环境中建议先在测试节点验证 DNS 解析行为无异常。

3. 审计并收紧 Endpoints 写权限(CVE-2021-25740)

检查你的集群是否存在过宽的 Endpoints/EndpointSlice 写权限:

# 查找所有授予 endpoints 或 endpointslices 写权限的 ClusterRole
kubectl get clusterroles -o json | jq -r '.items[] | select(.rules[]? | select(.resources[]? | test("endpoints|endpointslices")) and select(.verbs[]? | test("create|update|patch|delete"))) | .metadata.name'

# 重点检查从旧版本升级的集群中 system:aggregate-to-edit ClusterRole
kubectl get clusterrole system:aggregate-to-edit -o yaml
# 如果输出中包含 endpoints 或 endpointslices 的写权限,需要移除

kubectl auth reconcile 清理过宽权限:

# 创建一个修正后的 ClusterRole 定义,移除 endpoints/endpointslices 写权限
cat > /tmp/aggregate-to-edit-fix.yaml << 'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: system:aggregate-to-edit
  labels:
    rbac.authorization.k8s.io/aggregate-to-edit: "true"
    rbac.authorization.k8s.io/aggregate-to-admin: "true"
rules:
- apiGroups: [""]
  resources: ["endpoints", "endpointslices"]
  verbs: ["get", "list", "watch"]  # 只保留读权限,移除写权限
EOF

# 应用修正(reconcile 会删除旧规则中不在新定义里的权限)
kubectl auth reconcile -f /tmp/aggregate-to-edit-fix.yaml --remove-extra-permissions

# 验证:以一个拥有 edit 角色的用户身份,尝试创建 endpoints
kubectl auth can-i create endpoints --as=system:authenticated --namespace=default
# 期望输出: no

注意:此操作仅适用于使用 RBAC 授权模式的集群(Kubernetes 默认)。移除 Endpoints 写权限前,确认你的网络 Operator 或自定义控制器不依赖该权限——检查它们使用的 ServiceAccount 对应的 RoleBinding。

2026 年 6 月 1 日之后会发生什么?

更正生效后,CVE-2020-8561、CVE-2020-8562、CVE-2021-25740 的记录将标注"所有版本受影响,无修复版本"。你的扫描器(Trivy、Grype、Snyk 等)会开始在所有 Kubernetes 版本上报告这三个漏洞,包括此前因为错误"已修复"标记而被跳过的版本。

这不是新的漏洞——它们一直存在,只是记录终于诚实了。你应该:

  1. 提前告知安全团队:扫描器告警数量会上升,提前标注为"已知未修复架构风险"避免误判为新入侵。
  2. 在非生产环境逐项验证缓解措施:每项缓解都有功能代价,评估你的威胁模型是否值得承受这些代价。
  3. 持续关注 GitHub Issue:这三个漏洞的 Issue 页面是最新技术讨论的来源,未来如果出现新的缓解思路或架构变更方案,会在这里更新。

诚实记录比虚假安全感更重要

把"未修复"标注为"已修复",比漏洞本身更危险——它让运维者在不知情的情况下放弃了配置层面的防御。这次更正不是 Kubernetes 安全的退步,而是安全生态成熟的标志:承认架构债务的存在,用透明数据替代虚假的安心。

三个漏洞的缓解检查清单:

检查项 命令/配置 风险等级
apiserver --v < 10 且 --profiling=false ps aux | grep kube-apiserver 中危
控制面 DNS 缓存 min-cache-ttl ≥ 60s dig +short <domain> @127.0.0.1 两次对比延迟 低危
Endpoints/EndpointSlice 写权限已从宽泛角色移除 kubectl auth can-i create endpoints 低危

先在测试集群跑一遍,再逐步推到生产。


相关推荐