导读:本期聚焦于小团团创作的《如何设计容器镜像准入控制策略才能有效拦截高风险镜像?》,敬请观看详情。把镜像扫描放在 CI 阶段就认为安全,其实只挡住了一半风险。真正关键的控制点在 Kubernetes 准入链路上,镜像只有通过策略校验才会被允许创建 Pod。本文围绕 ValidatingWebhook 配置、镜像签名校验、OPA Rego 策略和漏洞扫描结果接入,说明如何建立分层的镜像准入机制。重点包括禁止 latest 标签、限制受信仓库、强制 Sigstore 签名验证,以及高危漏洞阻断。读完可以设计一套既能快速失败又能持续审计的镜像治理方案,避免把不可信镜像放进生产集群。

容器运行时一旦拉取不可信镜像,后续网络策略、RBAC、运行时防护都只能做补救。镜像准入控制是把安全校验前置到 Kubernetes API 请求落库之前的关键手段。它的目标并不是替代 CI 扫描,而是在生产边界上设卡。设置这个卡点后,即使开发者绕过 CI 流程直接提交 Pod,也会被 API Server 拒绝。本文展开的策略包括镜像仓库白名单、禁止 latest、强制签名、漏洞级别阻断等,并给出对应的 Webhook 与 OPA 配置。

如何设计容器镜像准入控制策略才能有效拦截高风险镜像?

一、准入控制链路的触发时机与失败策略

在 Kubernetes 中创建 Pod 时,请求会先经过认证、鉴权,然后进入准入控制器。镜像策略通常放在 ValidatingWebhook 或自定义准入插件中,因为此时不需要修改对象,只需要给出一致性判断。Webhook 接收 AdmissionReview 请求,返回 allowed true 或 false。如果返回 false,API Server 会直接拒绝该 Pod 创建请求。

失败策略需要单独设计。failurePolicy 设置为 Fail 时,只要 webhook 服务不可用,所有 Pod 创建都会被阻断。这虽然严格,但可能让整个集群不可用。因此生产环境常把失败策略设为 Fail,同时用多副本和 PDB 保证 webhook 可用;如果策略属于审计性质,可以先设 Ignore 观察一段时间。另一个容易忽略的是 timeoutSeconds,它决定了 webhook 响应超时时间。镜像扫描如果耗时长,不能直接在 webhook 内同步扫描,否则请求容易超时。

真正推荐的方式是将镜像扫描结果预先生成到镜像元数据或外部缓存中,webhook 只查缓存或签名验证结果。签名验证使用短时网络请求即可完成,适合放在同步 webhook 中。漏洞扫描则需要异步执行,在 CI 或仓库侧完成。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: image-policy-validation
webhooks:
  - name: check-images.ipipp.com
    clientConfig:
      service:
        name: image-policy-webhook
        namespace: security
        path: /validate-image
    rules:
      - operations: ["CREATE", "UPDATE"]
        apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
    failurePolicy: Fail
    sideEffects: None
    admissionReviewVersions: ["v1"]
    timeoutSeconds: 5

二、镜像仓库白名单与标签策略

不少生产事故的起点并不是镜像里有恶意代码,而是开发者不小心用了公共仓库中的同名镜像,或者把测试环境里 latest 标签的镜像带到了生产。latest 是一个可移动标签,今天指向的版本和明天可能完全不同。即使镜像内容本身没有问题,这种不确定性也会破坏可重复部署。因此第一条准入策略通常是禁止 latest 标签,同时只允许来自指定仓库前缀的镜像。

仓库白名单的核心是解析镜像字段,而不是做字符串包含判断。比如 image 字段可能写成 registry.ipipp.com/team/app:1.2.3,也可能带 digest,还可能来自默认 docker.io。如果只检查是否包含某个域名,攻击者可以使用 registry.ipipp.com.evil.com 绕过。严格的做法是解析完整镜像引用,确认 host 部分精确匹配白名单。

下面这段 Rego 策略通过 startswith 判断仓库前缀,并显式拒绝 latest。它放在 Gatekeeper 的 ConstraintTemplate 中,可以约束所有 Pod 和 Deployment 等上层资源,因为上层资源最终都会生成 Pod。

package k8sallowedimages

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  image := container.image
  not startswith(image, "registry.ipipp.com/")
  msg := sprintf("镜像 %s 不在仓库白名单中", [image])
}

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  image := container.image
  endswith(image, ":latest")
  msg := sprintf("禁止使用 latest 标签: %s", [image])
}

三、强制镜像签名与内容信任

仓库白名单只能保证镜像来自某个受控位置,不能保证这个位置上的镜像没有被篡改。仓库账号泄露、CI 流水线被入侵、镜像推送过程中的中间人攻击都可能导致镜像内容变化。镜像签名解决的是内容完整性和来源认证问题。Sigstore 提供的 cosign 工具可以对镜像摘要进行签名,验证时只要镜像摘要与签名匹配,就说明内容没有被改动。

在准入阶段验证签名,需要 webhook 解析 Pod 中的镜像引用,调用 cosign verify 或通过签名存储服务检查。如果镜像没有签名,或者签名密钥不匹配,直接拒绝。这样即使攻击者拿到了仓库写权限,只要没有签名私钥,仍无法把恶意镜像带进集群。签名策略还需要考虑镜像 tag 与 digest 的区别,建议强制使用 digest 而不是 tag,因为 tag 可移动,签名也容易错位。

以下命令展示在 CI 或 webhook 中执行签名验证的方式。生产环境中通常会把公钥挂载到 webhook 容器内,验证过程不依赖外部服务。

cosign verify \
  --key /keys/cosign.pub \
  registry.ipipp.com/team/app@sha256:9f6c...
if [ $? -ne 0 ]; then
  echo "镜像签名验证失败"
  exit 1
fi

四、漏洞扫描结果的准入判断

签名再严格,也不能保证镜像里的依赖没有已知漏洞。基础镜像中的 OpenSSL、glibc、Java 运行时都可能存在高危 CVE。漏洞扫描通常由 Trivy、Grype 或云厂商扫描服务完成,输出 JSON 报告。准入控制需要消费这些报告,而不是在请求链路上重新扫描。常见架构是 CI 推送镜像后执行扫描,把结果写入数据库或 OCI 注解,Webhook 查询结果并判断是否超过阈值。

漏洞等级是策略核心。一般将 CRITICAL 和 HIGH 定义为阻断级,MEDIUM 可以告警,LOW 忽略。这个阈值不能一刀切,例如基础镜像中的某个低危漏洞无法修复且不影响业务,仍然可以放行;但互联网暴露服务如果包含 CRITICAL RCE 漏洞,必须阻断。策略中不仅要看等级,还要看 CVSS 评分、可利用性和是否存在固定版本。

下面是一个在 CI 中使用 Trivy 的示例,扫描失败时阻断镜像推送。推送失败后,Pod 自然无法引用该镜像,这是第一层控制。准入 webhook 再做第二层兜底,防止有人绕过 CI 直接推送未扫描镜像。

trivy image \
  --severity HIGH,CRITICAL \
  --exit-code 1 \
  --ignore-unfixed \
  registry.ipipp.com/team/app:1.2.3
if [ $? -ne 0 ]; then
  echo "发现高危漏洞,禁止推送"
  exit 1
fi

五、策略分层与审计落地

镜像准入控制不是单一规则,而是多层策略的组合。仓库白名单负责限定来源,标签策略负责消除漂移,签名验证负责确认完整性,漏洞阈值负责控制风险。每一层可以独立演进,但需要在同一条 webhook 链路上统一执行。策略过多可能出现规则冲突,例如开发环境允许某公共镜像,生产环境不允许,这要求策略引擎支持按命名空间、标签和资源类型做作用域隔离。

OPA/Gatekeeper 通过 Constraint 和 ConstraintTemplate 解耦策略与执行,适合团队规模较大的场景。Kyverno 则以 Kubernetes 原生策略形式呈现,学习成本更低。无论选择哪种工具,都建议把拒绝原因写清楚,方便开发者快速修正镜像引用。下面是一个 Kyverno 策略片段,它拒绝未带摘要的镜像,并在返回信息中提示需要执行 cosign resolve。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-image-digest
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: check-digest
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "镜像必须使用 digest 而不是 tag"
        pattern:
          spec:
            containers:
              - image: "*@sha256:*"

策略上线后不能一劳永逸。至少要定期检查被拒绝请求的类型,判断是策略过严还是团队确实存在风险行为。同时要演练 webhook 服务故障时的表现,确认 failurePolicy 设置合理。镜像治理的最终目标不是给开发者添堵,而是把安全基线变成默认行为。当受信仓库、签名、扫描和 digest 都成为唯一入口时,不可信镜像自然就没有落地空间。

容器镜像准入控制镜像签名修改时间:2026-09-20 02:46:05

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0920/59472.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。