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 起,默认 edit 和 admin 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 版本上报告这三个漏洞,包括此前因为错误"已修复"标记而被跳过的版本。
这不是新的漏洞——它们一直存在,只是记录终于诚实了。你应该:
- 提前告知安全团队:扫描器告警数量会上升,提前标注为"已知未修复架构风险"避免误判为新入侵。
- 在非生产环境逐项验证缓解措施:每项缓解都有功能代价,评估你的威胁模型是否值得承受这些代价。
- 持续关注 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 |
低危 |
先在测试集群跑一遍,再逐步推到生产。