From 0058c629adc5e5f53392cbb0dd07476af9572d3b Mon Sep 17 00:00:00 2001 From: windsonsea Date: Thu, 2 Jan 2025 11:37:51 +0800 Subject: [PATCH] [zh] Add mutating-admission-policy.md --- .../mutating-admission-policy.md | 383 ++++++++++++++++++ .../applyconfiguration-example.yaml | 35 ++ .../json-patch-example.yaml | 33 ++ 3 files changed, 451 insertions(+) create mode 100644 content/zh-cn/docs/reference/access-authn-authz/mutating-admission-policy.md create mode 100644 content/zh-cn/examples/mutatingadmissionpolicy/applyconfiguration-example.yaml create mode 100644 content/zh-cn/examples/mutatingadmissionpolicy/json-patch-example.yaml diff --git a/content/zh-cn/docs/reference/access-authn-authz/mutating-admission-policy.md b/content/zh-cn/docs/reference/access-authn-authz/mutating-admission-policy.md new file mode 100644 index 0000000000000..707d347c11a89 --- /dev/null +++ b/content/zh-cn/docs/reference/access-authn-authz/mutating-admission-policy.md @@ -0,0 +1,383 @@ +--- +title: 变更性准入策略 +content_type: concept +--- + + + + +{{< feature-state for_k8s_version="v1.32" state="alpha" >}} + + + +本页概要介绍 **MutatingAdmissionPolicy(变更性准入策略)**。 + + + + +## 什么是 MutatingAdmissionPolicy? {#what-are-mutatingadmissionpolicies} + +变更性准入策略(Mutating Admission Policy)提供了一种声明式的、进程内的方案, +可以用来替代变更性准入 Webhook。 + + +变更性准入策略使用通用表达语言(Common Expression Language,CEL)来声明对资源的变更。 +变更操作可以通过使用[服务器端应用合并策略](/zh-cn/docs/reference/using-api/server-side-apply/#merge-strategy)所合并的**应用配置**来定义, +也可以使用 [JSON 补丁](https://jsonpatch.com/)来定义。 + +变更性准入策略的可配置能力很强,策略的编写者可以根据集群管理员的需要,定义参数化的策略以及限定到某类资源的策略。 + + +## 策略包含哪些资源 {#what-resources-make-a-policy} + +策略通常由三种资源组成: + +- MutatingAdmissionPolicy 描述策略的抽象逻辑(可以理解为:“此策略将特定标签设置为特定值”)。 + + +- 为 MutatingAdmissionPolicy 提供信息的一个**参数资源(parameter resource)**, + 有了参数之后,策略成为一条具体的语句 + (假想:“将 `owner` 标签设置为类似 `company.example.com` 的值”)。 + 参数资源引用 Kubernetes API 中可用的 Kubernetes 某种资源。被引用的资源可以是内置类别或类似 + {{< glossary_tooltip term_id="CustomResourceDefinition" text="CustomResourceDefinition" >}}(CRD)这种扩展资源。 + 例如,你可以使用 ConfigMap 作为参数。 + +- MutatingAdmissionPolicyBinding 将上述两种资源(MutatingAdmissionPolicy 和参数)关联在一起, + 并提供作用域限定。如果你只想为 `Pods` 设置 `owner` 标签,而不想为其他 API 类别设置标签, + 则绑定就是你用来限定此变更的地方。 + + +你必须定义至少一个 MutatingAdmissionPolicy 和一个相应的 MutatingAdmissionPolicyBinding, +才能使策略生效。 + +如果 MutatingAdmissionPolicy 不需要通过参数进行配置,在 +MutatingAdmissionPolicy 中不指定 `spec.paramKind` 即可。 + + +## 开始使用 MutatingAdmissionPolicy {#getting-started-with-mutatingadmissionpolicies} + +变更性准入策略是集群控制平面的一部分。你在编写和部署这些策略时要非常谨慎。 +下文描述如何快速试用变更性准入策略。 + + +### 创建 MutatingAdmissionPolicy {#create-a-mutatingadmissionpolicy} + +以下是一个 MutatingAdmissionPolicy 的示例。 +此策略会将变更新建的 Pod,为其添加一个边车容器(如果以前没有边车容器的话)。 + +{{% code_sample language="yaml" file="mutatingadmissionpolicy/applyconfiguration-example.yaml" %}} + + +`.spec.mutations` 字段由一系列表达式组成,这些表达式求值后将形成资源补丁。 +所生成的补丁可以是[应用配置](#patch-type-apply-configuration)或 [JSON 补丁](#patch-type-json-patch)。 +你不能将 mutations 设置为空列表。在对所有表达式求值后,API 服务器将所得到的变更应用到正在通过准入阶段的资源。 + + +要配置变更准入策略以便用于某个集群中,需要先创建绑定。 +只有存在 `spec.policyName` 字段值与某策略的 `spec.name` 相匹配的绑定时,该策略才会生效。 + +一旦创建了绑定和策略,策略的 `spec.matchConditions` 相匹配的所有资源请求都会触发已定义的所有变更集合。 + +在上面的示例中,创建 Pod 将触发添加 `mesh-proxy` initContainer 这一变更: + +```yaml +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 + ... +``` + + +#### 参数资源 {#parameter-resources} + +使用参数资源,我们可以将策略配置与其定义分隔开。策略可以定义 `paramKind`,划定参数资源的 GVK, +随后的策略绑定操作会通过 `paramRef` 按名称(通过 `policyName`)将某个策略绑定到特定参数资源。 + +有关细节参阅[参数资源](/zh-cn/docs/reference/access-authn-authz/validating-admission-policy/#parameter-resources)。 + +#### `ApplyConfiguration` {#patch-type-apply-configuration} + + +MutatingAdmissionPolicy 表达式始终是 CEL 格式的。 +每个应用配置 `expression` 必须求值为(使用 `Object()` 初始化声明的)CEL 对象。 + +这些应用配置不能修改原子结构、映射或数组,因为这类修改可能导致意外删除未包含在应用配置中的值。 + + +CEL 表达式可以访问以 CEL 变量组织起来的 API 请求内容及一些其他有用变量: + +- `Object` - 资源对象的 CEL 类型。 +- `Object.` - 对象字段的 CEL 类型(例如 `Object.spec`) +- `Object.....` - 嵌套字段的 CEL 类型(例如 `Object.spec.containers`) + + +CEL 表达式可以访问以 CEL 变量及一些其他有用变量分组的 API 请求的内容: + +- `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` {#patch-type-json-patch} + + +相同的变更可以被写成以下的 [JSON 补丁](https://jsonpatch.com/): + +{{% code_sample language="yaml" file="mutatingadmissionpolicy/json-patch-example.yaml" %}} + + +表达式将通过 CEL 求值,以创建 [JSON 补丁](https://jsonpatch.com/)。 +参阅 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 补丁](https://jsonpatch.com/)。 + `value` 字段可以设置为字符串、整数、数组、映射或对象。 + 如果设置,`path` 和 `from` 字段的值必须为 + [JSON 指针](https://datatracker.ietf.org/doc/html/rfc6901/)字符串, + 可以在指针中使用 `jsonpatch.escapeKey()` CEL 函数来转义包含 `/` 和 `~` 的路径键。 + +- `Object` - 资源对象的 CEL 类型。 +- `Object.` - 对象字段的 CEL 类型(例如 `Object.spec`) +- `Object.....` - 嵌套字段的 CEL 类型(例如 `Object.spec.containers`) + + +CEL 表达式可以访问以 CEL 变量组织的 API 请求的内容及一些其他有用变量: + +- `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 函数库](/zh-cn/docs/reference/using-api/cel/#cel-options-language-features-and-libraries)以及: + +- `jsonpatch.escapeKey` - 执行 JSONPatch 键转义。`~` 和 `/` 分别被转义为 `~0` 和 `~1`。 + +只有格式为 `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*` 的属性名称是可访问的。 diff --git a/content/zh-cn/examples/mutatingadmissionpolicy/applyconfiguration-example.yaml b/content/zh-cn/examples/mutatingadmissionpolicy/applyconfiguration-example.yaml new file mode 100644 index 0000000000000..a0daeeb608418 --- /dev/null +++ b/content/zh-cn/examples/mutatingadmissionpolicy/applyconfiguration-example.yaml @@ -0,0 +1,35 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: MutatingAdmissionPolicy +metadata: + name: "sidecar-policy.example.com" +spec: + paramKind: + kind: Sidecar + apiVersion: mutations.example.com/v1 + matchConstraints: + resourceRules: + - apiGroups: ["apps"] + 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" + } + ] + } + } diff --git a/content/zh-cn/examples/mutatingadmissionpolicy/json-patch-example.yaml b/content/zh-cn/examples/mutatingadmissionpolicy/json-patch-example.yaml new file mode 100644 index 0000000000000..00c17e9a64868 --- /dev/null +++ b/content/zh-cn/examples/mutatingadmissionpolicy/json-patch-example.yaml @@ -0,0 +1,33 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +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" + } + } + ]