Kyverno 是 Kubernetes 原生的策略即代码(Policy as Code)引擎。在多人共用一套 Kubernetes 集群的环境下,光靠文档约定无法阻止有人把特权容器、latest 镜像或 0.0.0.0/0 的 Service 暴露出去。Kyverno 通过动态准入控制,在资源写入 etcd 之前自动校验、修正甚至批量生成关联对象,把安全与合规规则固化成可版本化、可评审的代码,让集群从”靠人自觉”升级为”靠策略兜底”。
一、为什么需要 Kyverno
Kubernetes 自带的 RBAC 只管”谁能调哪个 API”,却管不了”这个 Pod 长得合不合规”。社区先后给出三套解法:Kubernetes 准入控制里的 ValidatingAdmissionPolicy 原生、OPA Gatekeeper,以及本文主角 Kyverno。前两者要么能力受限、要么要学新查询语言(Rego),而 Kyverno 直接用 YAML 写策略,对已经熟悉 K8s 的团队几乎零学习成本。
举个真实的事故雏形:某次上线把 image: nginx:latest 推了上去,而 latest 标签在仓库被重新构建后,滚动更新拉到的竟是一个带已知漏洞的新版本,回滚时连旧 digest 都找不到。如果当时有一条 Kyverno 策略禁止 :latest 并强制锁死镜像 digest,这类事故在准入阶段就会被直接拦下,根本到不了生产。策略的价值,恰恰是把”事后救火”变成”事前拦截”。
二、核心概念:Policy 与三类规则
Kyverno 的策略对象是 Policy(只作用于指定命名空间)或 ClusterPolicy(集群级)。每条策略由若干 rule 组成,每个 rule 通过 match 选定目标资源,再通过三种动作生效:
- validate:校验资源是否满足约束,不满足则拒绝创建(准入拦截)。
- mutate:在写入前自动修改资源,例如强制注入 securityContext 或补全标签。
- generate:当某资源创建时,自动在同命名空间生成另一份关联资源(如 NetworkPolicy、ServiceAccount、ConfigMap)。
rule 还支持 exclude 排除特定资源,比如放行 kube-system 等系统命名空间;复杂策略可用 preconditions 先做前置判断,再决定是否执行动作,从而把一条策略拆成多个互斥分支。三套方案的能力对比如下:
| 维度 | Kyverno | OPA Gatekeeper | ValidatingAdmissionPolicy |
|---|---|---|---|
| 策略语言 | YAML(原生 K8s 风格) | Rego | CEL |
| 变更(mutate) | 支持 | 需外部插件 | 不支持(仅校验) |
| 生成(generate) | 支持 | 不支持 | 不支持 |
| 学习成本 | 低 | 中高 | 低 |
| 适用场景 | 校验+变更+生成一体化 | 复杂逻辑校验 | 轻量原生校验 |
三、快速安装
生产环境推荐用 Helm 安装,自动拉起 admission webhook 与后台控制器:
# 添加仓库并安装到独立命名空间
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace
# 等待所有组件就绪
kubectl get pods -n kyverno
kubectl get validatingwebhookconfigurations | grep kyverno
若集群启用了 Karpenter 这类节点自动伸缩器,记得给 kyverno 命名空间打上 karpenter.sh/do-not-evict: "true",避免 webhook 被缩容导致准入链路抖动。安装完成后还需确认 webhook 的 failurePolicy:默认值是 Fail,意味着 Kyverno 不可用时所有准入请求都会被拒绝,集群将暂时无法创建任何资源;对可用性要求极高的环境可临时改为 Ignore 做过渡,但这会牺牲安全兜底,需要仔细权衡。
四、实战:validate 拦截不合规资源
下面这条集群策略禁止创建特权容器(privileged: true),并强制每个容器声明 CPU/内存限制:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-safe-workload
spec:
validationFailureAction: Enforce
rules:
- name: no-privileged
match:
any:
- resources:
kinds: [Pod]
validate:
message: "特权容器被禁止"
pattern:
spec:
containers:
- securityContext:
privileged: false
- name: require-resources
match:
any:
- resources:
kinds: [Pod]
validate:
message: "每个容器必须声明 resources.limits"
pattern:
spec:
containers:
- resources:
limits:
memory: "?*"
cpu: "?*"
validationFailureAction: Enforce 表示直接拒绝;改成 Audit 则只记录不拦截,适合先灰度观察误杀率再收紧。除了请求时的实时拦截,Kyverno 还会对集群中已存在的资源做后台扫描,结果写入 PolicyReport 与 ClusterPolicyReport 对象,配合 kubectl get policyreport 就能看到存量不合规项,方便在不阻断业务的前提下循序渐进地治理。
五、实战:mutate 自动补全安全配置
与其让开发自己写 securityContext,不如用 mutate 在准入时自动注入。下面的策略给所有没有显式声明 runAsNonRoot 的 Pod 补上非 root 运行:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-security-context
spec:
rules:
- name: set-nonroot
match:
any:
- resources:
kinds: [Pod]
mutate:
patchStrategicMerge:
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
mutate 还支持用 { } 变量从请求对象取值。例如自动给资源打上负责人标签:metadata.labels.owner: "{ request.object.spec.containers[0].name }",无需业务改一行代码。当 Pod 包含多个容器时,可用 foreach 遍历每一个容器分别注入,避免只改到第一个容器而漏掉 sidecar,这是 mutate 实战中最容易踩的坑之一。
六、实战:generate 自动创建关联资源
当某个命名空间被打上 team: payments 标签时,自动为其生成一份默认放通同命名空间流量的 NetworkPolicy,避免”新命名空间裸奔”:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: gen-default-netpol
spec:
rules:
- name: default-deny-ingress
match:
any:
- resources:
kinds: [Namespace]
generate:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
name: default-deny
namespace: "{ request.object.metadata.name }"
synchronize: true
data:
spec:
podSelector: {}
policyTypes: [Ingress]
synchronize: true 会在源资源变化时同步更新生成的资源,删除源资源时也会级联清理,非常适合做”默认安全基线”。generate 还支持 clone 模式,从某个模板命名空间直接克隆已有的 ConfigMap、Secret 等资源到新命名空间,在多租户场景下非常适合复用同一套配置基线。
七、与 CI/CD 和 GitOps 集成
把策略文件放进 Git 仓库,配合 ArgoCD 的 GitOps 流程做版本化管理与自动同步,正是”策略即代码”的精髓。提交前还能在 GitHub Actions 里用 Kyverno CLI 本地预检,把不合规的 YAML 在 MR 阶段就拦下来:
# 本地校验某目录下的所有 YAML 是否违反集群策略
kyverno apply ./policies \
--resource ./manifests/ \
--policy ./cluster-policies/
# 仅做校验、不修改,CI 中非零即失败
kyverno apply ./policies --resource ./manifests/ --fail-on-error
这样策略在测试环境生效前,开发就能在本地拿到明确的失败原因,而不是等部署时被 webhook 拒之门外才排查。新策略上线前,建议用 kyverno test 配合测试用例 YAML 做单元化验证,把策略当成代码一样写测试,避免一条正则写错就造成全集群误杀。
八、生产排障清单
Kyverno 接入后最常见的几类问题及定位方向:
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| 所有创建都被拒绝 | webhook 不可用/证书过期 | kubectl get pods -n kyverno 看控制器;检查 Mutating/Validating Webhook 的 caBundle |
| 策略不生效 | validationFailureAction 设为 Audit | 确认是 Enforce;检查 match 的 kinds/apiGroups 是否写对 |
| 误杀正常资源 | pattern 过严 | 先切 Audit 观察 PolicyReport,再放宽规则 |
| generate 资源不出现 | synchronize/selector 不匹配 | 查源资源标签与 generate 的 namespace 表达式 |
生产上建议把 PolicyReport 接入已有的 Prometheus 监控做告警,当策略拦截率异常飙升时第一时间感知,区分是真实攻击还是策略过严。这样 Kyverno 既是守门员,也是集群健康的可观测信号源。
九、小结
Kyverno 用纯 YAML 把”集群该长什么样”写成了可评审、可测试、可随 GitOps 同步的代码。validate 负责拦错、mutate 负责补位、generate 负责铺基线,三者组合能在不侵入业务代码的前提下,把安全与合规沉淀为集群的默认能力。对于已经跑起 Kubernetes 准入控制的团队,Kyverno 是把”原生校验”升级为”策略即代码”最平滑的一步。




