Kyverno 实战:用策略即代码守护 Kubernetes 集群安全

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 先做前置判断,再决定是否执行动作,从而把一条策略拆成多个互斥分支。三套方案的能力对比如下:

维度KyvernoOPA GatekeeperValidatingAdmissionPolicy
策略语言YAML(原生 K8s 风格)RegoCEL
变更(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 是把”原生校验”升级为”策略即代码”最平滑的一步。

上一篇 Roo Code 实战:用自定义模式打造专属 AI 编程智能体
下一篇 程序员副业实战:技术人如何把技能变成第二收入
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]