LabHub
学习 学习路径 课程

策略即代码

写必填标签与仓库限制的策略

在 LabHub 中继续学习

目标

亲自编写要求必需标签的验证策略和限制镜像仓库的拒绝规则,在本地确认通过、失败判定及策略报告。最后,用狭窄的范围表达合理的例外。

为什么重要

验证策略中导致事故的通常不是条件表达式,而是匹配范围。条件错误会在测试中被发现,但匹配错误时,策略会悄无声息地什么也不做,因此无人察觉。所以,同时放入应当通过和应当被阻止的资源进行测试是编写策略的基本功。还有一点,拒绝消息是策略的一半。部署受阻的人只能看到 kubectl apply 输出的一行文字;如果这一行不够友好,策略的全部运维成本都会变成咨询请求。最后,本环境中没有运行策略引擎控制器,因此集群不会实际阻止错误的 Pod。判定通过 kyverno apply 在本地进行,评分也会检查策略 YAML 的结构和执行结果。

步骤

  1. 创建 /root/policy/validate/require-labels.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata.namerequire-labels。将 spec.validationFailureAction 设为 Enforce(或将规则的 validate.failureAction 设为 Enforce),将 spec.background 设为 true,并把 spec.rules[0].name 命名为 check-required-labels
  2. 在同一规则中,通过 match.any[0].resources.kinds 指定 Pod,通过 namespaces 指定 pol-lab。然后在规则的 exclude.any[0].resources.namespaces 中排除 kube-system
  3. validate.pattern.metadata.labels 下,要求 app.kubernetes.io/nameteam 两个标签的值均为 "?*"。在同一个 validate 中加入 message,内容至少 15 个字符,并让人能够知道该修正什么。
  4. 运行 kyverno apply /root/policy/validate/require-labels.yaml --resource /opt/lab/fixtures/policy/resources/good-pod.yaml,将结果保存为 /root/policy/validate/out/pass.txt。结果中必须显示名为 require-labels 的策略和通过标记,失败数必须为 0。
  5. /opt/lab/fixtures/policy/resources/bad-pod.yaml 运行同一策略,并保存为 /root/policy/validate/out/fail.txt(失败数至少为 1,并包含策略名称)。然后在 /root/policy/validate/out/fail-note.txt 中用韩文写明缺少哪个标签而触发策略。
  6. /root/policy/validate/restrict-registry.yaml 中创建第二个 ClusterPolicy。在规则中使用 validate.deny.conditions.all(或 any),将 registry.labhub.io 设为允许的镜像仓库,拒绝来自其他仓库的镜像。然后对 /opt/lab/fixtures/policy/resources/bad-registry.yaml 运行它,并将结果保存为 /root/policy/validate/out/registry.txt(必须显示拒绝或失败)。
  7. restrict-registry.yaml 的规则中添加 preconditions。使用类似 {{ request.operation }} 的请求上下文变量,使规则仅在 CREATEUPDATE 时运行。然后在 /root/policy/validate/out/precondition-note.txt 中写明 preconditions 与 deny 的区别——必须同时说明 preconditions 为假时规则会被跳过,而 deny 是规则执行结果所产生的拒绝
  8. require-labels.yaml,将 good-pod 和 bad-pod 两者都通过 --resource 传入,使用 --policy-report 运行并保存为 /root/policy/validate/out/policy-report.yamlsummary.pass 至少为 1,summary.fail 至少为 1)。然后在 /root/policy/validate/exception.yaml 中创建 kind: PolicyException,将 spec.exceptions[0].policyName 设为 require-labelsruleNames 设为 check-required-labels,并将 spec.match.any[0].resources.nameslegacy-batch-* 一样缩小到名称级别

参考

确定策略骨架和强制模式

创建 /root/policy/validate/require-labels.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata.namerequire-labels。将 spec.validationFailureAction 设为 Enforce(或将规则的 validate.failureAction 设为 Enforce),将 spec.background 设为 true,并把 spec.rules[0].name 命名为 check-required-labels

ClusterPolicy 是 kyverno.io 组的 CRD。在 spec 中决定失败时是阻止还是只记录,以及是否将现有资源也视为检查对象。

缩小适用对象和排除对象

在同一规则中,通过 match.any[0].resources.kinds 指定 Pod,通过 namespaces 指定 pol-lab。然后在规则的 exclude.any[0].resources.namespaces 中排除 kube-system

在 match 的 any 下,通过 resources 写入类型和命名空间。如果遗漏配套的 exclude,系统命名空间也会成为目标。

编写必需标签模式和拒绝消息

validate.pattern.metadata.labels 下,要求 app.kubernetes.io/nameteam 两个标签的值均为 "?*"。在同一个 validate 中加入 message,内容至少 15 个字符,并让人能够知道该修正什么。

pattern 按照与要检查的对象相同的形状编写。有一个专门表示“只要存在即可”的运算符。消息是被拒绝者能够阅读的唯一文档。

用应当通过的 Pod 运行测试

运行 kyverno apply /root/policy/validate/require-labels.yaml --resource /opt/lab/fixtures/policy/resources/good-pod.yaml,将结果保存为 /root/policy/validate/out/pass.txt。结果中必须显示名为 require-labels 的策略和通过标记,失败数必须为 0。

kyverno CLI 会在本地评估策略文件和通过 --resource 接收的清单。请选择能让结果显示策略名称的输出格式。

用违规 Pod 运行并写明原因

/opt/lab/fixtures/policy/resources/bad-pod.yaml 运行同一策略,并保存为 /root/policy/validate/out/fail.txt(失败数至少为 1,并包含策略名称)。然后在 /root/policy/validate/out/fail-note.txt 中用韩文写明缺少哪个标签而触发策略。

如果只确认通过,就无法将该策略与完全没有匹配任何内容的策略区分开。还要记住,存在失败时退出码为 1。

编写限制镜像仓库的 deny 规则

/root/policy/validate/restrict-registry.yaml 中创建第二个 ClusterPolicy。在规则中使用 validate.deny.conditions.all(或 any),将 registry.labhub.io 设为允许的镜像仓库,拒绝来自其他仓库的镜像。然后对 /opt/lab/fixtures/policy/resources/bad-registry.yaml 运行它,并将结果保存为 /root/policy/validate/out/registry.txt(必须显示拒绝或失败)。

像“如果不在列表中就拒绝”这样的条件很难用 pattern 表达。请思考 conditions 下 any 和 all 中哪一个合适。

使用 preconditions 缩小规则适用范围

restrict-registry.yaml 的规则中添加 preconditions。使用类似 {{ request.operation }} 的请求上下文变量,使规则仅在 CREATEUPDATE 时运行。然后在 /root/policy/validate/out/precondition-note.txt 中写明 preconditions 与 deny 的区别——必须同时说明 preconditions 为假时规则会被跳过,而 deny 是规则执行结果所产生的拒绝

preconditions 为假时,规则甚至不会被评估。必须将它与 deny 的区别整理到文件中才能通过。

创建策略报告和狭窄例外

require-labels.yaml,将 good-pod 和 bad-pod 两者都通过 --resource 传入,使用 --policy-report 运行并保存为 /root/policy/validate/out/policy-report.yamlsummary.pass 至少为 1,summary.fail 至少为 1)。然后在 /root/policy/validate/exception.yaml 中创建 kind: PolicyException,将 spec.exceptions[0].policyName 设为 require-labelsruleNames 设为 check-required-labels,并将 spec.match.any[0].resources.nameslegacy-batch-* 一样缩小到名称级别

要让一条通过记录和一条失败记录同时出现在一个报告摘要中,必须同时加入两个资源。请将例外缩小到策略名称、规则名称和资源名称。