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 策略引擎做出准入决策的完整流程:
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实现更灵活的验证逻辑。