策略不是拿来部署的,是拿来晋级的
一句话总结
策略运维的核心流程只有一个:先用 Audit 观察几天,确认被拦住的清单与预期一致,再晋级到 Enforce。并且把这个判断交给 PolicyReport 和 CI 门禁,而不是靠人的记忆。
为什么需要它
一开始就在开发集群里以 Enforce 方式施加策略,这种失败模式总是同一个样子。签名流水线或标签规则还没有在所有团队铺开时就打开强制模式,部署会被整体拦住,最后成为瓶颈的不是策略,而是写策略的人。接下来发生的事更糟:因为着急,就把例外开得很宽,而这些例外又变成永久的。
反过来,如果全部保持 Audit,就没有人去看报告。所以需要晋级流程:事先定好看什么、满足什么条件、把哪条规则提上去。
工作原理
观察的工具是 PolicyReport 和 ClusterPolicyReport。命名空间级别的报告中包含 results 数组和 summary(pass、fail、warn、error、skip 的数量)。养成只筛出失败项来看的习惯很重要,同时看策略名称和消息,才能判断是哪条规则因为什么被拦住。
差异化应用有两种方法。规则级别的 failureAction 决定“针对哪条规则”,validationFailureActionOverrides 决定“在哪个命名空间”。典型的配置是开发命名空间保持 Audit,只把生产命名空间提到 Enforce,把两个维度组合起来,既可以按规则区分,也可以按命名空间区分。
正当的例外用 PolicyException 管理。它指定策略名称和规则名称,并通过 match 缩小对象范围。关键在于写得窄:不要把整个命名空间排除掉,而要写到名称模式;如果例外清单超过实际运行对象的一半,这条策略带来的就不是安全,而是“有安全”的错觉。
策略级别的三个标志也要了解。background 用来开关扫描现有资源并生成报告的行为,默认值是 true。admission 决定是否在准入阶段应用规则,默认是 true,设为 false 就成为仅限 background 的策略。applyRules 决定对匹配到的资源最多应用多少条规则:One 表示在第一次匹配时停止,默认值是 All。如果规则是按顺序排列的,却在查找后面的规则为什么不运行,就先看这个字段。
CI 门禁由 kyverno apply 构成。把策略文件和要用 --resource 检查的清单交给它,就能在本地跑起来;有失败或错误时退出码为 1,可以直接卡住 CI 作业。这一个习惯能避免的事故很大:match 块写错,写出了什么都匹配不到的策略,却误以为通过了。什么都匹配不到的策略在集群里只会悄悄放行,所以人眼看上去和运转良好的策略没有区别。
还有一条要反复强调的原则。用通配符匹配所有资源的策略,会给集群的每个请求都加上延迟税。默认的 failurePolicy 是 Fail,所以一旦超过超时,请求就会被拒绝。把 match 缩小到必要的种类和命名空间,不是性能调优,而是可用性工作。
最后是什么时候不该用。如果要检查的只是某个字段的值,除此之外什么都不需要,那么 Kubernetes 内置的 ValidatingAdmissionPolicy 加 CEL 就足够了。少运维一个组件,意味着升级对象少一个,故障时需要怀疑的地方少一个,也少一件要操心的 Webhook 证书更新。再进一步,如果是 Pod 安全级别这类标准化检查,不需要策略引擎,只要在命名空间上加两行标签(Pod Security Admission)就够了。真正支撑 Kyverno 的,是 generate、mutate,以及镜像验证这类内置功能做不到的事。
在现场相遇的样子
作者处理镜像扫描报告时立下的规则,同样适用于策略运维:例外一定要写过期日期。扫描例外文件中要同时写下理由和过期日期,过期之后扫描器会重新报失败。要防止例外悄悄变成永久,唯一的办法就是这个。PolicyException 没有过期字段,所以要达到同样的效果,就得由人来管理。比较好的做法是在例外对象的注解中写下过期日期和理由,再加入定期巡检的流程。
还有一点,从扫描中学到的优先级判断在这里同样有效。报告里即使有 1,247 条,今天需要处理的通常也只有个位数。只留下有修复版本的,先看已确认被实际利用的。策略报告也一样,fail 有几百条,并不意味着今天都要修,而是按规则分组,先看哪条规则产生的失败最多。这一条规则通常要么是写错的规则,要么是组织还没有准备好的规则。
作者的家庭实验室是 7 个节点,上面运行着 Cilium eBPF、ArgoCD、Harbor 和 Gitea。即使在这个规模下,一旦把策略全面设为 Enforce,KubeVirt、GPU Operator 这类系统组件也会最先被拦住。所以用 exclude 排除系统命名空间不是选项,而是默认做法。
下一项实验要做什么
在 /root/kca-ops/ 中,用可执行的 shell 脚本写出包含按命名空间差异化应用、webhookConfiguration 和策略标志的策略文件、PolicyException 文件,以及晋级检查清单。然后实际创建一个只靠 PSA 标签强制 Pod 安全级别的命名空间,亲手确认不用策略引擎能做到什么程度。