4. 第一个策略:编写一个简单的 Validate 策略——禁止使用 latest 镜像标签

在生产环境中,使用 latest 标签拉取容器镜像是一个高风险行为。它会导致 Pod 在不同节点或不同时间点拉取到不同版本的镜像,从而引发不可预期的行为、回滚困难以及安全审计缺失。本节将带领你编写第一个 Kyverno Validate 策略,从源头阻断 latest 标签的使用。

4.1 策略目标与核心逻辑

本策略的目标是:拦截所有 Pod 及工作负载资源(如 Deployment、StatefulSet、DaemonSet)中,镜像标签为 latest 或未显式指定标签(默认也为 latest)的创建与更新请求。

维度 说明
策略类型 Validate(验证)
触发动作 CREATE 和 UPDATE
匹配资源 Pod 以及包含 Pod 模板的工作负载(Deployment、StatefulSet、DaemonSet、Job、CronJob)
验证规则 检查 spec.containers[*].image 和 spec.initContainers[*].image 字段,不允许以 :latest 结尾或不包含 : 分隔符
违规行为 拒绝请求并返回明确错误信息
为什么是 Validate 而非 Mutate? 虽然 Mutate 策略可以自动将 latest 替换为具体版本,但这会掩盖配置中的原始意图,且无法强制要求开发者显式指定版本。Validate 策略直接拒绝,能更早地在 CI/CD 流程中暴露问题,培养良好的镜像管理习惯。

4.2 策略 YAML 详解

下面是一个完整的 Kyverno 策略 YAML 定义。它使用 pattern 方式定义验证规则,通过正则表达式匹配不合规的镜像标签。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-latest-tag
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: require-image-tag
      match:
        any:
          - resources:
              kinds:
                - Pod
                - Deployment
                - StatefulSet
                - DaemonSet
                - Job
                - CronJob
      validate:
        message: "使用 'latest' 标签或未指定标签的镜像是不允许的。请使用明确的版本标签,例如 'v1.2.3' 或 'sha256:...'。"
        pattern:
          spec:
            containers:
              - image: "!*:latest & !*"
            initContainers:
              - image: "!*:latest & !*"
关键字段解析:
  • validationFailureAction: Enforce:设置为 Enforce 表示直接拒绝违规请求;若设为 Audit 则仅生成报告,不拦截。
  • background: true:开启后台扫描,对集群中已有的资源进行审计,发现违规项并生成 PolicyReport。
  • pattern 中的 !*:latest & !*:这是一个 Kyverno 特有的反模式语法。!*:latest 表示“不能匹配任何以 :latest 结尾的字符串”;!* 表示“不能匹配任何不包含 : 的字符串”。两者用 & 连接,表示同时满足两个否定条件,即镜像必须包含 : 且不能以 latest 结尾。

4.3 策略执行流程(SVG)

下图展示了从用户提交 Pod 到 Kyverno 策略引擎做出准入决策的完整流程:

Validate 策略执行流程:禁止 latest 标签 用户/CI 提交 Pod Kubernetes API Server Kyverno Webhook 匹配资源类型 验证 image 模式 通过:允许创建 拒绝:返回错误 策略核心逻辑 检查 containers 和 initContainers 中的 image 字段

4.4 部署与测试策略

将上述 YAML 保存为 disallow-latest-tag.yaml,然后执行以下命令部署到集群:

kubectl apply -f disallow-latest-tag.yaml

部署后,可以通过创建测试 Pod 来验证策略是否生效:

# 测试1:使用 latest 标签(应被拒绝)
kubectl run nginx-latest --image=nginx:latest

# 测试2:未指定标签(应被拒绝)
kubectl run nginx-notag --image=nginx

# 测试3:使用明确版本标签(应被允许)
kubectl run nginx-ok --image=nginx:1.25.3
预期结果: 前两个命令会返回类似 Error from server: admission webhook "validate.kyverno.svc" denied the request: ... 的错误信息,其中包含策略中定义的 message 字段内容。第三个命令应成功创建 Pod。

4.5 策略优化与扩展建议

基础策略已经能够满足大部分场景,但在实际生产环境中,你可能需要根据业务需求进行以下优化:

优化方向 实现方式 适用场景
排除特定命名空间 在 match 块中添加 namespaceSelector 或使用 exclude 块 允许 kube-system 或 istio-system 等系统命名空间使用 latest 进行调试
允许特定镜像仓库 在 pattern 中使用 imageRegistry 条件或结合 anyPattern 允许私有仓库中的 latest 标签用于内部开发环境
仅拦截 latest 但允许空标签 将 pattern 改为 "!*:latest" 并移除 & !* 某些基础镜像确实没有标签,但需要禁止显式使用 latest
结合 Mutate 策略 先使用 Mutate 策略自动添加标签,再使用 Validate 策略兜底 渐进式治理:先自动修复,再对无法修复的配置进行拦截
生产环境最佳实践: 建议先在 Audit 模式下运行策略一段时间,通过 kubectl get policyreport 查看集群中已有的违规资源,评估影响范围后再切换为 Enforce 模式。这样可以避免因策略突然生效导致线上服务中断。

4.6 常见问题与排查

  • 策略未生效: 检查 Kyverno Pod 是否正常运行,以及 MutatingWebhookConfiguration 和 ValidatingWebhookConfiguration 是否正确配置。使用 kubectl get validatingwebhookconfigurations 查看。
  • 误拦截了 InitContainer: 确认策略中的 initContainers 字段是否与你的资源定义匹配。某些 Operator 或自定义资源可能使用不同的字段名。
  • 正则表达式不生效: Kyverno 的 pattern 语法并非标准正则,而是其自定义的“反模式”语法。如果遇到复杂匹配需求,建议使用 deny 规则配合 context 和 variables 实现更灵活的验证逻辑。