更改准入策略

特性状态: Kubernetes v1.36 [稳定版](默认启用)

本页面概述了 可变准入策略 (MutatingAdmissionPolicies)。可变准入策略允许您在有人向 Kubernetes API 写入变更时修改所发生的操作。如果您只想使用声明式策略来防止对资源进行特定类型的更改(例如:防止删除平台命名空间),则 验证准入策略 (ValidatingAdmissionPolicy) 是一个更简单、更有效的替代方案。

什么是可变准入策略 (MutatingAdmissionPolicies)?

可变准入策略为可变准入 Webhook 提供了一种声明式的进程内替代方案。

可变准入策略使用通用表达式语言 (CEL) 来声明对资源的变更。变更既可以通过使用 服务端应用合并策略 (server side apply merge strategy) 合并的 应用配置 (apply configuration) 来定义,也可以使用 JSON Patch 来定义。

可变准入策略具有高度可配置性,使策略编写者能够根据集群管理员的需要定义可参数化且作用于特定资源的策略。

构成策略的资源

一个策略通常由三种资源组成

  • MutatingAdmissionPolicy 描述了策略的抽象逻辑(例如:“此策略将特定标签设置为特定值”)。

  • 参数资源 (parameter resource) 向 MutatingAdmissionPolicy 提供信息,使其成为具体的声明(例如:“将 owner 标签设置为类似 company.example.com 的值”)。参数资源引用 Kubernetes API 中可用的 Kubernetes 资源。它们可以是内置类型或扩展,例如 自定义资源定义 (CustomResourceDefinition) (CRD)。例如,您可以使用 ConfigMap 作为参数。

  • MutatingAdmissionPolicyBinding 将上述资源(MutatingAdmissionPolicy 和参数)链接在一起并提供作用域范围。如果您只想为 Pods 设置 owner 标签,而不涉及其他 API 类型,则可以在绑定中指定此变更。

策略要生效,至少必须定义一个 MutatingAdmissionPolicy 和一个对应的 MutatingAdmissionPolicyBinding。

说明

.static.k8s.io 结尾的名称保留用于 基于清单的准入控制 (manifest-based admission control),不能用于基于 API 的策略或绑定。当启用 ManifestBasedAdmissionControlConfig 特性门控 (feature gate) 时,此保留规则会强制执行。

如果 MutatingAdmissionPolicy 不需要通过参数进行配置,只需在 MutatingAdmissionPolicy 中不指定 spec.paramKind 即可。

可变准入策略入门

可变准入策略是集群控制平面的一部分。编写和部署时应格外谨慎。以下内容描述了如何快速尝试可变准入策略。

创建可变准入策略

以下是 MutatingAdmissionPolicy 的一个示例。此策略会修改新创建的 Pod,如果尚不存在 Sidecar 容器,则为其添加一个。

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
  name: "sidecar-policy.example.com"
spec:
  paramKind:
    kind: Sidecar
    apiVersion: mutations.example.com/v1
  matchConstraints:
    resourceRules:
    - apiGroups:   [""]
      apiVersions: ["v1"]
      operations:  ["CREATE"]
      resources:   ["pods"]
  matchConditions:
    - name: does-not-already-have-sidecar
      expression: "!object.spec.initContainers.exists(ic, ic.name == \"mesh-proxy\")"
  failurePolicy: Fail
  reinvocationPolicy: IfNeeded
  mutations:
    - patchType: "ApplyConfiguration"
      applyConfiguration:
        expression: >
          Object{
            spec: Object.spec{
              initContainers: [
                Object.spec.initContainers{
                  name: "mesh-proxy",
                  image: "mesh/proxy:v1.0.0",
                  args: ["proxy", "sidecar"],
                  restartPolicy: "Always"
                }
              ]
            }
          }          

.spec.mutations 字段包含一系列计算结果为资源补丁的表达式。所发出的补丁可以是 应用配置JSON Patch 补丁。您不能指定空的变更列表。在评估完所有表达式后,API 服务器会将这些变更应用于正在通过准入的资源。

要配置用于集群的可变准入策略,需要一个绑定。只有在存在对应的绑定且引用的 spec.policyName 与策略的 spec.name 匹配时,MutatingAdmissionPolicy 才会处于活跃状态。

一旦创建了绑定和策略,任何匹配策略 spec.matchConditions 的资源请求都会触发定义的变更集合。

在上面的示例中,创建 Pod 将会添加 mesh-proxy initContainer 变更

apiVersion: v1
kind: Pod
metadata:
  name: myapp
  namespace: default
spec:
  ...
  initContainers:
  - name: mesh-proxy
    image: mesh/proxy:v1.0.0
    args: ["proxy", "sidecar"]
    restartPolicy: Always
  - name: myapp-initializer
    image: example/initializer:v1.0.0
  ...

参数资源

参数资源允许策略配置与定义分离。策略可以定义 paramKind,这概述了参数资源的 GVK;然后策略绑定通过 policyName 按名称将策略链接起来,并通过 paramRef 链接到特定的参数资源。

请参阅 参数资源 以获取更多信息。

应用配置 (ApplyConfiguration)

MutatingAdmissionPolicy 表达式始终为 CEL。每个应用配置 expression 必须计算为一个 CEL 对象(使用 Object() 初始化声明)。

Apply configurations 不能修改原子结构、映射或数组,因为存在意外删除未包含在 apply configuration 中的值的风险。

CEL 表达式可以访问创建 apply configurations 所需的对象类型

  • Object - 资源对象的 CEL 类型。
  • Object.<fieldName> - 对象字段的 CEL 类型(例如 Object.spec
  • Object.<fieldName1>.<fieldName2>...<fieldNameN> - 嵌套字段的 CEL 类型(例如 Object.spec.containers

CEL 表达式可以访问 API 请求的内容,组织到 CEL 变量以及其他一些有用的变量中

  • object - 来自传入请求的对象。对于 DELETE 请求,该值为 null。
  • oldObject - 现有对象。对于 CREATE 请求,该值为 null。
  • request - API 请求的属性。
  • params - 被评估的策略绑定所引用的参数资源。仅当策略具有 ParamKind 时才填充。
  • namespaceObject - 传入对象所属的命名空间对象。对于集群范围的资源,该值为 null。
  • variables - 组合变量映射,从名称到其延迟评估的值。例如,名为 foo 的变量可以作为 variables.foo 访问。
  • authorizer - CEL 授权器。可用于为请求的主体(用户或服务账号)执行授权检查。请参阅 https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
  • authorizer.requestResource - 由 authorizer 构建并配置有请求资源的 CEL ResourceCheck。

apiVersionkindmetadata.namemetadata.generateNamemetadata.labels 始终可以从对象的根访问。
无法访问其他元数据属性。

JSONPatch

同样的变更可以写作 JSON Patch,如下所示

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
  name: "sidecar-policy.example.com"
spec:
  paramKind:
    kind: Sidecar
    apiVersion: mutations.example.com/v1
  matchConstraints:
    resourceRules:
    - apiGroups:   [""]
      apiVersions: ["v1"]
      operations:  ["CREATE"]
      resources:   ["pods"]
  matchConditions:
    - name: does-not-already-have-sidecar
      expression: "!object.spec.initContainers.exists(ic, ic.name == \"mesh-proxy\")"
  failurePolicy: Fail
  reinvocationPolicy: IfNeeded
  mutations:
    - patchType: "JSONPatch"
      jsonPatch:
        expression: >
          [
            JSONPatch{
              op: "add", path: "/spec/initContainers/-",
              value: Object.spec.initContainers{
                name: "mesh-proxy",
                image: "mesh-proxy/v1.0.0",
                restartPolicy: "Always"
              }
            }
          ]          

该表达式将由 CEL 评估以创建 JSON patch。参考:https://github.com/google/cel-spec

每个评估的 expression 必须返回一个 JSONPatch 值数组。
JSONPatch 类型表示 JSON patch 中的一个操作。

例如,这个 CEL 表达式返回一个 JSON patch,用于有条件地修改一个值

  [
    JSONPatch{op: "test", path: "/spec/example", value: "Red"},
    JSONPatch{op: "replace", path: "/spec/example", value: "Green"}
  ]

要为补丁操作 value 定义 JSON 对象,请使用 CEL Object 类型。例如

  [
    JSONPatch{
      op: "add",
      path: "/spec/selector",
      value: Object.spec.selector{matchLabels: {"environment": "test"}}
    }
  ]

要使用包含 '/' 和 '~' 的字符串作为 JSONPatch 路径键,请使用 jsonpatch.escapeKey()。例如

  [
    JSONPatch{
      op: "add",
      path: "/metadata/labels/" + jsonpatch.escapeKey("example.com/environment"),
      value: "test"
    },
  ]

CEL 表达式可以访问创建 JSON patch 和对象所需的类型

  • JSONPatch - JSON Patch 操作的 CEL 类型。JSONPatch 具有字段 opfrompathvalue。详见 JSON patchvalue 字段可设置为:字符串、整数、数组、映射或对象。如果已设置,则 pathfrom 字段必须设置为 JSON 指针 字符串,其中可以使用 jsonpatch.escapeKey() CEL 函数来转义包含 /~ 的路径键。
  • Object - 资源对象的 CEL 类型。
  • Object.<fieldName> - 对象字段的 CEL 类型(例如 Object.spec
  • Object.<fieldName1>.<fieldName2>...<fieldNameN> - 嵌套字段的 CEL 类型(例如 Object.spec.containers

CEL 表达式可以访问 API 请求的内容,组织到 CEL 变量以及其他一些有用的变量中

  • object - 来自传入请求的对象。对于 DELETE 请求,该值为 null。
  • oldObject - 现有对象。对于 CREATE 请求,该值为 null。
  • request - API 请求的属性。
  • params - 被评估的策略绑定所引用的参数资源。仅当策略具有 ParamKind 时才填充。
  • namespaceObject - 传入对象所属的命名空间对象。对于集群范围的资源,该值为 null。
  • variables - 组合变量映射,从名称到其延迟评估的值。例如,名为 foo 的变量可以作为 variables.foo 访问。
  • authorizer - CEL 授权器。可用于为请求的主体(用户或服务账号)执行授权检查。请参阅 https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
  • authorizer.requestResource - 由 authorizer 构建并配置有请求资源的 CEL ResourceCheck。

CEL 表达式有权访问 Kubernetes CEL 函数库 以及

  • jsonpatch.escapeKey - 执行 JSONPatch 键转义。~/ 分别转义为 ~0~1

[a-zA-Z_.-/][a-zA-Z0-9_.-/]* 格式的属性名称可被访问。

豁免可变准入的 API 类型

某些 API 类型豁免于准入时的变更。例如,您无法创建修改 MutatingAdmissionPolicy 的 MutatingAdmissionPolicy。

说明

当通过 基于清单的准入控制 进行配置时,MutatingAdmissionPolicy 可以拦截下面列出的所有资源类型。这绕过了通常应用于通过 REST API 创建的策略的限制,允许您甚至修改准入配置和安全敏感资源。与 REST API 不同,拦截这些资源的错误清单准入策略不会导致系统不可恢复,因为它是在磁盘上定义的,而不是通过 API 定义的。

豁免的 API 类型列表如下


最后修改于 2026 年 4 月 8 日上午 9:37 PST:docs(kep-5793): address review nits on admission control docs (99775be699)