更改准入策略

功能状态: Kubernetes v1.34 [beta]

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

要使用此功能,请在 kube-apiserver 上启用 MutatingAdmissionPolicy 特性门控(默认关闭),并设置 --runtime-config=admissionregistration.k8s.io/v1beta1=true

什么是修改准入策略?

修改准入策略为修改准入 Webhook(mutating admission webhooks)提供了一种声明式的、进程内的替代方案。

修改准入策略使用通用表达式语言 (CEL) 来声明对资源的修改。修改可以通过使用 服务器端应用合并策略 进行合并的 应用配置 (apply configuration) 来定义,或者通过 JSON 补丁 (JSON patch) 来定义。

修改准入策略具有高度的可配置性,允许策略作者根据集群管理员的需求,定义可参数化且可限定资源范围的策略。

构成策略的资源

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

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

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

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

必须至少定义一个 MutatingAdmissionPolicy 和相应的 MutatingAdmissionPolicyBinding,策略才能生效。

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

修改准入策略入门

修改准入策略是集群控制平面的一部分。编写和部署它们时应倍加小心。以下描述了如何快速实验修改准入策略。

创建一个 MutatingAdmissionPolicy

以下是 MutatingAdmissionPolicy 的一个示例。此策略会修改新创建的 Pod,如果不存在边车(sidecar)容器,则添加一个。

apiVersion: admissionregistration.k8s.io/v1beta1
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 字段由一系列计算为资源补丁的表达式组成。生成的补丁可以是 应用配置 (apply configurations)JSON 补丁 (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 始终可以从对象的根目录访问。
无法访问其他元数据属性。

JSON 补丁 (JSONPatch)

同样的修改可以写成 JSON 补丁,如下所示:

apiVersion: admissionregistration.k8s.io/v1beta1
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 补丁。参考:https://github.com/google/cel-spec

每个计算出的 expression 必须返回一个 JSONPatch 值的数组。
JSONPatch 类型代表 JSON 补丁中的一个操作。

例如,这个 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 补丁操作的 CEL 类型。JSONPatch 具有字段 opfrompathvalue。详见 JSON 补丁value 字段可以设置为:字符串、整数、数组、映射或对象。如果设置了 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。

豁免的 API 类型列表包括:

最后修改于 2025 年 12 月 29 日 11:12 PM PST: mutating-admission-policy.md - 语法修正 (6e2b00a3ab)