Kubernetes策略即代码与准入治理实战

Kubernetes 的 RBAC 主要回答“谁可以调用什么 API”,却不能独立回答“提交的对象是否符合组织规则”。例如,开发者有权创建 Deployment,并不代表可以使用特权容器、无资源限制、来自未知仓库的镜像或永久有效的例外。策略即代码的目标,是把这些规则写成可审阅、可测试、可分阶段启用、可观测并能快速回退的版本化配置。

本文面向需要建立集群准入基线的平台、安全和运维团队。示例优先使用 Kubernetes 原生 ValidatingAdmissionPolicy 与 CEL,同时说明何时引入 Kyverno 等策略引擎。不同 Kubernetes 与策略引擎版本支持的字段并不相同,上线前应以当前集群和官方兼容矩阵为准。

一、准入控制在请求链路中的位置

一个写请求通常依次经过身份认证、授权和准入控制,最后才写入 etcd:

  1. 认证确认调用者身份;
  2. 授权判断该身份能否对资源执行动作;
  3. 变更型准入可补默认值或修改对象;
  4. 验证型准入决定对象是否允许写入;
  5. API Server 完成持久化。

策略不能替代镜像扫描、运行时检测、网络策略或主机加固。准入控制只看当前请求及允许访问的数据;已存在对象不会因为新策略上线而自动整改,节点上绕过 API Server 的行为也不在其保护范围内。

二、先做规则分层,而不是先选工具

层级 典型规则 建议实现
Kubernetes内建保护 Pod安全、资源配额、LimitRange 内建准入控制器和原生资源
简单对象校验 标签、镜像仓库、字段组合 ValidatingAdmissionPolicy与CEL
复杂匹配和生成 例外、上下文查询、生成资源、镜像验证 成熟策略引擎
供应链校验 签名、来源证明、SBOM门禁 镜像验证策略与制品平台
运行时治理 进程、文件、网络和异常行为 运行时安全与可观测平台

原则是能用原生能力清楚表达的规则,不必先增加外部 webhook;确实需要生成资源、复杂上下文或供应链验证时,再引入策略引擎。每条规则都应有负责人、风险等级、作用范围、例外条件、测试用例和回退方式。

三、建立准入策略清单

不要一次写几十条拒绝规则。先从实际事故和审计要求整理清单:

  • 禁止特权容器、宿主机 PID/IPC/Network 和高风险 hostPath;
  • 默认禁止以 root 运行,要求只读根文件系统和必要的 seccomp;
  • 禁止 latest、裸标签和未批准的镜像仓库;
  • 工作负载必须声明 CPU、内存 requests,关键服务同时声明 limits;
  • 强制负责人、系统、环境、数据等级等标签;
  • 禁止 NodePort、LoadBalancer 或跨命名空间引用被随意创建;
  • 限制可使用的 StorageClass、Ingress/Gateway 域名和 TLS Secret;
  • 生产命名空间禁止调试镜像、临时凭据和明文敏感配置;
  • 例外必须有工单号、负责人、原因和到期时间。

把规则分为“必须阻断”“先告警后整改”“仅盘点”三类。对低风险环境和系统命名空间单独定义边界,避免把平台组件误拦截。

四、用Pod Security建立第一道基线

Pod Security Admission 提供 privileged、baseline 和 restricted 三档标准。生产命名空间可以先启用审计和警告,再逐步转为强制:

kubectl label namespace payments \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/enforce=baseline \
  --overwrite

观察违规一段时间后,再将 enforce 提升到 restricted。建议显式固定策略版本,避免集群升级时规则语义在未评估的情况下变化。系统组件、CNI、存储插件等可能确实需要额外权限,应放在受控命名空间并记录例外,而不是全局关闭基线。

五、使用ValidatingAdmissionPolicy表达原生规则

ValidatingAdmissionPolicy 使用 CEL 表达验证逻辑,不依赖外部网络 webhook。下面禁止生产 Deployment 使用 latest 或无标签镜像:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: require-pinned-image
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups: ["apps"]
      apiVersions: ["v1"]
      operations: ["CREATE", "UPDATE"]
      resources: ["deployments"]
  validations:
  - expression: >-
      object.spec.template.spec.containers.all(c,
        c.image.contains(':') && !c.image.endsWith(':latest'))
    message: "生产工作负载必须使用明确且非 latest 的镜像标签"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: require-pinned-image-prod
spec:
  policyName: require-pinned-image
  validationActions: [Deny, Audit]
  matchResources:
    namespaceSelector:
      matchLabels:
        policy-tier: production

创建规则前先确认 CRD、子资源、控制器生成对象和 UPDATE 行为。CEL 表达式要覆盖字段缺失、空数组、initContainers 和 ephemeralContainers 等情况;复杂逻辑应拆成多条 validation,让拒绝原因可读。

六、资源与标签规则要考虑真实工作负载

“所有容器都必须有 limits”看似严格,但 CPU limit 可能引起节流;“所有对象都有 owner 标签”也可能误伤第三方控制器。可采用以下分层:

  • 所有容器必须有 CPU、内存 requests;
  • 内存 limit 为必填,CPU limit 根据工作负载类别决定;
  • 平台命名空间使用受控例外,不与业务命名空间混用;
  • 控制器生成的 Pod 应在上层 Deployment、Job 或自定义资源校验;
  • 负责人标签值必须来自组织目录,而不只是“字段存在”。

同时配置 ResourceQuota 和 LimitRange,防止策略只校验格式却没有命名空间总量约束。

七、何时使用Kyverno等策略引擎

当需要生成默认资源、校验镜像签名、访问其他对象上下文、自动变更或输出策略报告时,策略引擎更合适。示例规则只允许批准仓库:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: restrict-image-registries
spec:
  validationFailureAction: Audit
  background: true
  rules:
  - name: approved-registries
    match:
      any:
      - resources:
          kinds: [Pod]
    validate:
      message: "镜像必须来自已批准的企业仓库"
      pattern:
        spec:
          containers:
          - image: "registry.example.com/*"

上线前核对策略引擎版本的字段语义。变更型规则可能让 Git 中的声明与集群实际对象不同,应明确哪些默认值由 API 默认、策略引擎或部署模板负责,避免多套系统同时修改同一字段。

八、采用“盘点—警告—阻断”三阶段上线

  1. 盘点:后台扫描存量资源,仅生成报告;
  2. 警告:新请求仍可通过,但返回警告并通知负责人;
  3. 阻断:只对已达到合规率的命名空间启用 Deny;
  4. 收口:清理临时例外并将策略纳入新集群基线。

每个阶段都应有通过率、违规对象数、误拦截数、例外数量和最长整改时间。阻断前至少回放真实清单,并覆盖部署、扩缩容、滚动更新、Job、备份恢复和故障处置流程。

九、例外不是白名单字符串

生产例外至少包含:策略编号、资源范围、业务负责人、批准人、原因、补偿措施、创建时间和到期时间。优先使用独立命名空间、精确对象选择器或专用 ServiceAccount;不要用宽泛正则排除整个团队。

可将例外放在独立仓库,通过 CI 检查到期时间。到期前提醒,到期后自动转为警告或拒绝。紧急处置的 break-glass 账号必须有审计、短时有效和事后复核,不能成为日常绕过通道。

十、在CI中测试策略

策略和应用变更都要在进入集群前测试:

kubectl apply --dry-run=server -f manifests/
kubectl diff -f manifests/

建议维护四组测试:

  • 应允许的最小合规对象;
  • 每条规则对应的应拒绝对象;
  • 缺失字段、空值、多容器和更新操作等边界案例;
  • 平台组件、控制器生成对象和紧急恢复清单。

测试必须固定 Kubernetes 和策略引擎版本。仅做 YAML 语法检查不足以发现准入链、CRD 默认值和版本转换后的真实行为。

十一、Webhook可用性与故障边界

外部 admission webhook 位于控制面写请求关键路径。应控制超时、并发、证书轮换和副本反亲和,避免规则引擎故障演变为全站无法发布。failurePolicy: Fail 更安全,但会在 webhook 不可用时拒绝请求;Ignore 提高可用性,却可能放行违规对象。二者必须按策略风险选择,而不是全局统一。

重点观察:

  • 准入请求延迟的 P50、P95、P99;
  • 超时、拒绝、错误和 fail-open 次数;
  • API Server webhook 指标与审计日志;
  • 策略引擎副本、队列、缓存和证书剩余时间;
  • 各策略命中率及误拦截工单。

避免 webhook 调用自身依赖的受控服务形成循环依赖。不要把远程镜像扫描、工单查询等慢操作直接串在请求链路中,可用预计算结果或缓存降低风险。

十二、变更、回滚与紧急处置

策略变更应像应用发布一样分批:测试集群、非关键命名空间、少量生产、全量。回滚顺序通常是先将 Deny 降为 Warn/Audit,再修正规则,而不是立即删除所有策略组件。

当大量发布突然被拒绝时:

  1. 确认是授权、配额还是准入拒绝;
  2. 从 API 响应和审计日志定位具体策略;
  3. 检查最近策略、Kubernetes、CRD或控制器升级;
  4. 将单条故障策略降级,保留其他保护;
  5. 恢复关键发布并记录被放行对象;
  6. 修复后回放清单、恢复阻断并补做审计。

不要直接停掉整个 webhook 部署后继续操作;如果配置为 Fail,停服务可能让请求全部失败。

十三、生产验收清单

  • [ ] 每条策略都有风险说明、负责人、测试与回滚方法;
  • [ ] 规则先审计、后警告、再按命名空间阻断;
  • [ ] 系统命名空间和控制器行为经过真实回放;
  • [ ] 例外范围最小且有到期时间;
  • [ ] webhook有多副本、证书监控、超时和容量保护;
  • [ ] 策略延迟、错误、拒绝和fail-open行为可观测;
  • [ ] GitOps、扩缩容、备份恢复和事故操作均经过验证;
  • [ ] 集群升级前重新执行兼容性测试;
  • [ ] 紧急降级不会同时移除全部保护;
  • [ ] 存量违规有整改计划,而非永久忽略。

十四、官方参考

策略治理的成熟标志不是“拒绝规则很多”,而是规则与风险对应、例外可追踪、变更可验证、故障可降级。把准入策略当作控制面产品持续运营,才能在不阻塞交付的前提下提高默认安全性。

Copyright © yan-jian.com 2023 - 2026 · Powered by GitBook更新时间: 2026-10-21 09:42:18

results matching ""

    No results matching ""