从 Audit 到 Enforce — 真正把策略打开的顺序
一句话总结
策略,启用比编写更难,而启用的顺序永远是观测 → 整理例外 → 强制三个阶段。
为什么需要它
把策略写好之后立刻提升到 Enforce 的团队,遇到的事情大都一样。部署成批地被拦住,Slack 里咨询堆积如山,几个小时后有人说“先把策略撤下来吧”。策略被撤下来,就再也没有重新上去。失败的原因不在于策略的质量,而在于没有人知道正在运行的那些东西是否遵守这条规则。
集群里不只有新部署的工作负载。两年前上线的批处理作业、供应商提供的 Helm Chart、某个团队临时启动后被遗忘的 Pod,都生活在同一个集群里。新规则会撞上其中多少个,在把规则挂上去之前是无法知道的。所以策略引擎必然带有不拦截、只统计的模式。
工作原理
核心是两个机制。
第一,Audit 与 Enforce。
| 模式 | 违规请求 | 留下什么 |
|---|---|---|
Audit |
放行 | 在报告中记录为 fail |
Enforce |
拒绝 | 报告中也会留下,用户也会立刻知道 |
Audit 不是“策略没有启用的状态”,而是“只关闭了强制的状态”。判定照常发生,结果不断累积。所以用 Audit 放上几天,就能用数字回答“启用这条规则会拦住多少个”这个问题。自从强制级别下沉到规则级别(validate.failureAction)之后,可以在同一个策略内,只把已验证的规则提升到 Enforce,而把新规则以 Audit 加上去。
第二,后台扫描与 PolicyReport。
准入阶段只看今后要进入的内容。已经在集群中的对象,不会有人再次检查。所以 spec.background: true 的策略,会由后台控制器定期遍历现有资源,用同一条规则进行判定。结果会累积成报告。
PolicyReport— 命名空间范围。该命名空间内资源的判定结果ClusterPolicyReport— 集群范围资源的判定结果
报告的 results 数组中包含每个资源的判定(policy、rule、result、message),summary 中包含 pass、fail、warn、error、skip 的汇总。这个 summary.fail 就是引入工作的进度指标。如果启用策略那天是 47,两周后变成 3,那么这 3 个就是剩下的例外候选。
第三,PolicyException。
剩下的内容中,有些真的无法修复。比如供应商的镜像无法加入 limits,或者节点代理需要特权。这时不要撤回策略,而是把例外以文档形式留下来。例外有三层范围。
spec.exceptions[].policyName— 是针对哪个策略的例外spec.exceptions[].ruleNames— 只豁免该策略中的哪条规则spec.match— 只适用于哪些资源(kinds、namespaces,以及 names)
三层都收窄很重要。如果省略 ruleNames,豁免整个策略,这个资源今后就连该策略中新增的所有规则也一并豁免了。如果不写 names,只写命名空间,那么其中今后新创建的工作负载也会被永久排除在规则之外。例外不应该是关闭策略的开关,而应该是一份债务清单。列表变长就会被看到,被看到就能缩短。如果给每个例外用注解附上到期日或负责团队,这份列表就能自行得到管理。
按顺序使用这三个机制,就得出了引入流程。
1) 정책을 Audit 으로 배포 + background: true
2) 며칠~몇 주 리포트의 summary.fail 을 관찰
3) 고칠 수 있는 것은 팀과 함께 고친다 (fail 이 줄어드는 것을 본다)
4) 못 고치는 것만 좁은 PolicyException 으로 남긴다
5) fail 이 예외 건수까지 내려오면 그 규칙을 Enforce 로 올린다
6) 예외 목록을 주기적으로 다시 본다
在现场相遇的样子
第一,开着 Audit 却没有人看。报告会不断累积,但如果没有仪表板也没有告警,就只是 CRD 对象越来越多。Audit 是观测,但不是会阅读观测结果的人。把策略以 Audit 部署的那一刻,就要同时确定“谁在什么时候看这个数字”。
第二,报告堆积,压垮集群。在资源很多的集群中,如果对匹配一切的策略开启 background,就会大量创建报告对象。如果报告控制器跟不上汇总速度,就会开始积压。缩小匹配范围,在这里同样是答案。
第三,例外悄悄变成永久。因为“下个 Sprint 我们就修”而创建的例外,两年后仍然留着的集群并不少见。要给例外写上到期日和负责人,并建立每个季度遍历一遍列表的流程。比起创建例外,建立删除例外的流程更难,也更重要。
第四,这个环境坦率的局限。这里没有运行后台控制器,所以集群中不会自动累积 PolicyReport。取而代之的是,可以用 kyverno apply --policy-report 在本地生成同样格式的报告,其 summary 中的 pass/fail 数值与真实报告中的含义相同。pol-validate 实验中生成的报告就是它。
下一项检查要关注什么
在接下来的实验中,亲手做出本文最后两段所说的内容。建立写有负责人、到期日和依据的例外登记册,编写查找并拦截已过期例外的检查器,确认例外是否真的缩小了策略的适用范围,然后把违规汇总到一处,制作一份用数字回答“现在可以提升到 Enforce 吗”的报告。你会在那里体会到,建立删除例外的流程,比创建例外更难。实验之后的测验中,将确认 /root/policy/validate/exception.yaml 中 policyName、ruleNames、资源 names 这三层如何收窄例外范围,以及为什么要与到期日、负责人一起,作为债务清单来管理。