修改性准入策略

特性狀態: Kubernetes v1.34 [beta]

此頁面概述了 **MutatingAdmissionPolicy**。變更准入策略允許你更改當使用者向 Kubernetes API 寫入更改時所發生的事情。如果你只想使用宣告性策略來阻止特定型別的資源更改(例如:保護平臺名稱空間免遭刪除),則 ValidatingAdmissionPolicy 是一種更簡單、更有效的替代方案。

要使用此功能,請啟用 `MutatingAdmissionPolicy` 特性門控(預設關閉),並在 kube-apiserver 上設定 `--runtime-config=admissionregistration.k8s.io/v1beta1=true`。

什麼是變更准入策略?

變更准入策略提供了一種宣告式的、程序內的、替代變更准入 Webhook 的方案。

變更准入策略使用通用表示式語言 (CEL) 來宣告資源的變更。變更可以透過使用 Server Side Apply 合併策略 合併的 **應用配置** 來定義,或者透過 JSON Patch 來定義。

變更准入策略具有高度可配置性,使策略作者能夠根據叢集管理員的需要定義可引數化並作用於特定資源的策略。

策略由哪些資源組成

策略通常由三個資源組成:

  • MutatingAdmissionPolicy 描述了策略的抽象邏輯(例如:“此策略將特定標籤設定為特定值”)。

  • **引數資源** 為 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` 欄位由一個表示式列表組成,這些表示式求值為資源補丁。發出的補丁可以是 應用配置JSON Patch 補丁。你不能指定空的變更列表。在評估所有表示式之後,API 伺服器將這些更改應用於正在透過准入的資源。

為了在叢集中使用變更准入策略,需要進行繫結。MutatingAdmissionPolicy 僅在存在相應的繫結,且其引用的 `spec.policyName` 與策略的 `spec.name` 匹配時才會生效。

一旦建立了繫結和策略,任何與策略的 `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()` 初始化宣告)。

應用配置不能修改原子結構體、對映或陣列,因為這有意外刪除未包含在應用配置中的值的風險。

CEL 表示式可以訪問建立應用配置所需的以下物件型別:

  • `Object` - 資源物件的 CEL 型別。
  • `Object.` - 物件欄位的 CEL 型別(例如 `Object.spec`)。
  • `Object.....` - 巢狀欄位的 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。

`apiVersion`、`kind`、`metadata.name`、`metadata.generateName` 和 `metadata.labels` 始終可以從物件的根訪問。
其他元資料屬性均不可訪問。

JSONPatch

相同的變更可以表示為如下的 JSON Patch

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 補丁,用於有條件地修改一個值。

  [
    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 補丁和物件所需的型別:

  • `JSONPatch` - JSON 補丁操作的 CEL 型別。JSONPatch 具有 `op`、`from`、`path` 和 `value` 欄位。有關更多詳細資訊,請參閱 JSON 補丁。`value` 欄位可以設定為以下任何一種型別:字串、整數、陣列、對映或物件。如果設定了 `path` 和 `from` 欄位,它們必須設定為 JSON 指標 字串,其中 `jsonpatch.escapeKey()` CEL 函式可用於轉義包含 ` /` 和 `~` 的路徑鍵。
  • `Object` - 資源物件的 CEL 型別。
  • `Object.` - 物件欄位的 CEL 型別(例如 `Object.spec`)。
  • `Object.....` - 巢狀欄位的 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 年 8 月 6 日下午 6:42:KEP-3962 文件 (e65e744407)