LabHub
学习 学习路径 课程

KCA — Kyverno 认证助理

策略仍在,违规 Pod 却被创建了

在 LabHub 中继续学习

目标

即使策略对象仍然存在,只要调用注册已被移除,就不能算测试了 Fail 对调用失败的处理。比较正常缩容后注册与响应的恢复时间以及对象 UID,并通过 server dry-run 区分验证与持久化。

为什么重要

如果用“失败”一个词同时概括策略的明确拒绝和 Webhook 调用错误,就会选择错误的应对措施。 必须分别观察策略、注册、响应以及已在运行的 Pod。两个实验都会从新的 VM 开始,不需要其他实验的资料。不要在学生专用 VM 之外制造故障。

正常缩容使用 55 秒恢复监视器;响应中断使用 pidfd 和 20 秒自动恢复计时器。 本实验预计需要 55 分钟。默认会话为 60 分钟,如有需要,请在到期前通过 +时间 延长。最长 180 分钟,结束时 VM 和文件都会消失,请先下载所需资料。

所有学生文件都位于 /root/kca-webhook 下。每个 act N 的原始资料保存在 evidence/NN.json 中, 内容从 facts 读取。说明中提到的 02.json 等均指该 evidence 路径。 规范 JSON 哈希是 /opt/fixtures/kca_webhook_common.py 中的 digest(read(路径)), 与 sha256sum 的文件字节哈希不同。请在 Python 中把 /opt/fixtures 加入 sys.path 后使用。

步骤

  1. 使用 inspect 查看当前 VM 的 vm.node_uid 和 namespaces。在 scope.json 中记录 target=kca-webhook-target、control=kca-webhook-control、node_uid、namespaces。namespaces 使用真实名称作为键、UID 作为值。执行 act 1 保存当前 VM 的范围。
  2. 在 policy.json 中编写 policies.kyverno.io/v1 的 ValidatingPolicy。名称为 kca-webhook-label,validationActions=[Deny],failurePolicy=Fail,webhookConfiguration.timeoutSeconds=3,evaluation.background.enabled=false。matchConstraints.namespaceSelector.matchLabels 为 kubernetes.io/metadata.name=kca-webhook-target;resourceRules 为 apiGroups=[空字符串]、apiVersions=[v1]、operations=[CREATE]、resources=[pods]。validations 的 expression 为 "'environment' in object.metadata.?labels.orValue({})",message 为 KCA_ENVIRONMENT_REQUIRED。不要添加无关字段,执行 act 2 确认真实注册。
  3. 在 registration.json 中记录 service=kyverno-svc、namespace=kyverno、path=/vpol/kca-webhook-label、selector_target=kca-webhook-target、selector_source=namespace-label、operation=CREATE、resource=pods、failure_policy=Fail、timeout_seconds=3,以及 policy_uid=02.json 中的 facts.policy.metadata.uid。执行 act 3,观察注册以及范围外无标签请求的持久化 UID。
  4. 执行 act 4。evidence/04.json 的 facts.good 应是带标签 Pod 的持久化 UID;bad 应表示缺少标签时的明确拒绝且未持久化;existing 应保持同一个 UID 且状态为 Running。请同时阅读原始错误文本和持久化状态。
  5. 在 shutdown-plan.json 中记录 action=observe-graceful-shutdown,把 inspect 的 controller.metadata.uid 记为 deployment_uid,并记录 replicas_before=1、replicas_during=0、replicas_after=1、restore_deadline_sec=55。act 5 会正常缩容并恢复专用 VM 控制器。在 evidence/05.json 中区分相同的策略 UID、注册缺失、违规资源被持久化、恢复后的拒绝以及新的控制器 Pod。
  6. 将 05.json 的 facts.replicas_restored_at、facts.recovery.registered_at、facts.recovery.response_at 分别以同名键移入 recovery.json。填写 replicas_mean=desired-count-not-policy-readiness、controller_pod=replaced、policy=same-uid,并将 shutdown_evidence_sha256 设为 05.json 的规范 JSON 哈希。act 6 会再次确认新违规请求被拒绝且基线 Pod 仍然存活。
  7. 在 dryrun.json 中记录 mode=server、admission=evaluated、good=accepted-not-stored、bad=explicit-deny、existing=same-uid-running,并将 evidence_sha256 设为 06.json 的规范 JSON 哈希。act 7 会使用新名称执行 server dry-run。比较 evidence/07.json 中正常 Pod 的响应与未持久化状态,以及违规请求的明确拒绝。
  8. 在 report.json 中记录 shutdown=registration-removed-not-fail-bypass、policy=same-uid、controller_pod=replaced、existing=same-uid-running、dryrun=admission-without-storage。shutdown_evidence_sha256 和 dryrun_evidence_sha256 分别填写 05.json 和 07.json 的规范 JSON 哈希。完成 act 8 后再次运行完整评分。

参考

命令为 python3 /opt/fixtures/kca_webhook_lab.py inspect、act 1 到 act 8, grade 1 到 grade 8。grade 会读取输入和已保存的真实观测,不会再次制造故障。 已完成的 act 会保留资料和资源,也不会自动覆盖部分输入。 中断的执行结果不确定,因此请下载失败原始资料,并在新实验中复现。 策略目标是 CREATE pods。不要将结论泛化到所有 API、所有安装版本或高可用场景。 Kubernetes server dry-run

VM 与目标、对照范围

使用 inspect 查看当前 VM 的 vm.node_uid 和 namespaces。在 scope.json 中记录 target=kca-webhook-target、control=kca-webhook-control、node_uid、namespaces。namespaces 使用真实名称作为键、UID 作为值。执行 act 1 保存当前 VM 的范围。

查看 inspect 的 vm.node_uid 和 namespaces。名称与 UID 并不相同。

直接编写 Deny、Fail 策略

在 policy.json 中编写 policies.kyverno.io/v1 的 ValidatingPolicy。名称为 kca-webhook-label,validationActions=[Deny],failurePolicy=Fail,webhookConfiguration.timeoutSeconds=3,evaluation.background.enabled=false。matchConstraints.namespaceSelector.matchLabels 为 kubernetes.io/metadata.name=kca-webhook-target;resourceRules 为 apiGroups=[空字符串]、apiVersions=[v1]、operations=[CREATE]、resources=[pods]。validations 的 expression 为 "'environment' in object.metadata.?labels.orValue({})",message 为 KCA_ENVIRONMENT_REQUIRED。不要添加无关字段,执行 act 2 确认真实注册。

namespaceSelector 选择的是 namespace 标签。请区分验证动作 Deny 与调用失败处理 Fail。

通过请求确认调用注册范围

在 registration.json 中记录 service=kyverno-svc、namespace=kyverno、path=/vpol/kca-webhook-label、selector_target=kca-webhook-target、selector_source=namespace-label、operation=CREATE、resource=pods、failure_policy=Fail、timeout_seconds=3,以及 policy_uid=02.json 中的 facts.policy.metadata.uid。执行 act 3,观察注册以及范围外无标签请求的持久化 UID。

不仅要查看策略声明,还要核对 02.json 中真实的 service 路径、namespaceSelector 和 rules。范围外请求并不意味着绕过了 Fail。

正常允许、拒绝与现有 Pod 基线

执行 act 4。evidence/04.json 的 facts.good 应是带标签 Pod 的持久化 UID;bad 应表示缺少标签时的明确拒绝且未持久化;existing 应保持同一个 UID 且状态为 Running。请同时阅读原始错误文本和持久化状态。

AlreadyExists 不是策略拒绝。后续步骤会把现有 Pod 的 UID 与该基线进行比较。

正常关闭后策略与注册的不同生命周期

在 shutdown-plan.json 中记录 action=observe-graceful-shutdown,把 inspect 的 controller.metadata.uid 记为 deployment_uid,并记录 replicas_before=1、replicas_during=0、replicas_after=1、restore_deadline_sec=55。act 5 会正常缩容并恢复专用 VM 控制器。在 evidence/05.json 中区分相同的策略 UID、注册缺失、违规资源被持久化、恢复后的拒绝以及新的控制器 Pod。

即使策略仍存在,调用注册也可能消失。不要假设 replicas=1 后策略已经立即恢复。

分别验证恢复时间与真实拒绝

将 05.json 的 facts.replicas_restored_at、facts.recovery.registered_at、facts.recovery.response_at 分别以同名键移入 recovery.json。填写 replicas_mean=desired-count-not-policy-readiness、controller_pod=replaced、policy=same-uid,并将 shutdown_evidence_sha256 设为 05.json 的规范 JSON 哈希。act 6 会再次确认新违规请求被拒绝且基线 Pod 仍然存活。

这些时间不是事件的精确发生时间,而是执行器确认状态的观测时间。不要把确认注册与收到真实拒绝响应合并成同一个状态。

区分服务器验证成功与持久化成功

在 dryrun.json 中记录 mode=server、admission=evaluated、good=accepted-not-stored、bad=explicit-deny、existing=same-uid-running,并将 evidence_sha256 设为 06.json 的规范 JSON 哈希。act 7 会使用新名称执行 server dry-run。比较 evidence/07.json 中正常 Pod 的响应与未持久化状态,以及违规请求的明确拒绝。

client dry-run 不会检查服务器 Webhook。server dry-run 的正常响应中即使包含对象,也不能解释为对象已经真正持久化。

按不同对象的生命周期编写事故报告

在 report.json 中记录 shutdown=registration-removed-not-fail-bypass、policy=same-uid、controller_pod=replaced、existing=same-uid-running、dryrun=admission-without-storage。shutdown_evidence_sha256 和 dryrun_evidence_sha256 分别填写 05.json 和 07.json 的规范 JSON 哈希。完成 act 8 后再次运行完整评分。

请区分重新创建的控制器 Pod 与持续存活的基线 Pod。即使报告哈希正确,如果缺少前面步骤的真实原始资料,也无法通过。