|
| 1 | +--- |
| 2 | +reviewers: |
| 3 | +- deads2k |
| 4 | +- sttts |
| 5 | +- cici37 |
| 6 | +title: Mutating Admission Policy |
| 7 | +content_type: concept |
| 8 | +--- |
| 9 | + |
| 10 | +<!-- overview --> |
| 11 | + |
| 12 | +{{< feature-state for_k8s_version="v1.32" state="alpha" >}} |
| 13 | +<!-- due to feature gate history, use manual version specification here --> |
| 14 | + |
| 15 | +This page provides an overview of _MutatingAdmissionPolicies_. |
| 16 | + |
| 17 | +<!-- body --> |
| 18 | + |
| 19 | +## What are MutatingAdmissionPolicies? |
| 20 | + |
| 21 | +Mutating admission policies offer a declarative, in-process alternative to mutating admission webhooks. |
| 22 | + |
| 23 | +Mutating admission policies use the Common Expression Language (CEL) to declare mutations to resources. |
| 24 | +Mutations can be defined either with an *apply configuration* that is merged using the |
| 25 | +[server side apply merge strategy](/docs/reference/using-api/server-side-apply/#merge-strategy), |
| 26 | +or a [JSON patch](https://jsonpatch.com/). |
| 27 | + |
| 28 | +Mutating admission policies are highly configurable, enabling policy authors to define policies |
| 29 | +that can be parameterized and scoped to resources as needed by cluster administrators. |
| 30 | + |
| 31 | +## What resources make a policy |
| 32 | + |
| 33 | +A policy is generally made up of three resources: |
| 34 | + |
| 35 | +- The MutatingAdmissionPolicy describes the abstract logic of a policy |
| 36 | + (think: "this policy sets a particular label to a particular value"). |
| 37 | + |
| 38 | +- A _parameter resource_ provides information to a MutatingAdmissionPolicy to make it a concrete |
| 39 | + statement (think "set the `owner` label to something like `company.example.com`"). |
| 40 | + Parameter resources refer to Kubernetes resources, available in the Kubernetes API. They can be built-in types or extensions, |
| 41 | + such as a {{< glossary_tooltip term_id="CustomResourceDefinition" text="CustomResourceDefinition" >}} (CRD). For example, you can use a ConfigMap as a parameter. |
| 42 | +- A MutatingAdmissionPolicyBinding links the above (MutatingAdmissionPolicy and parameter) resources together and provides scoping. |
| 43 | + If you only want to set an `owner` label for `Pods`, and not other API kinds, the binding is where you |
| 44 | + specify this mutation. |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | +At least a MutatingAdmissionPolicy and a corresponding MutatingAdmissionPolicyBinding |
| 49 | +must be defined for a policy to have an effect. |
| 50 | + |
| 51 | +If a MutatingAdmissionPolicy does not need to be configured via parameters, simply leave |
| 52 | +`spec.paramKind` in MutatingAdmissionPolicy not specified. |
| 53 | + |
| 54 | +## Getting Started with MutatingAdmissionPolicies |
| 55 | + |
| 56 | +Mutating admission policy is part of the cluster control-plane. You should write |
| 57 | +and deploy them with great caution. The following describes how to quickly |
| 58 | +experiment with Mutating admission policy. |
| 59 | + |
| 60 | +### Create a MutatingAdmissionPolicy |
| 61 | + |
| 62 | +The following is an example of a MutatingAdmissionPolicy. This policy mutates newly created Pods to have a sidecar container if it does not exist. |
| 63 | + |
| 64 | +{{% code_sample language="yaml" file="mutatingadmissionpolicy/applyconfiguration-example.yaml" %}} |
| 65 | + |
| 66 | +The `.spec.mutations` field consists of a list of expressions that evaluate to resource patches. |
| 67 | +The emitted patches may be either [apply configurations](#patch-type-apply-configuration) or [JSON Patch](#patch-type-json-patch) |
| 68 | +patches. You cannot specify an empty list of mutations. After evaluating all the |
| 69 | +expressions, the API server applies those changes to the resource that is |
| 70 | +passing through admission. |
| 71 | + |
| 72 | +To configure a mutating admission policy for use in a cluster, a binding is |
| 73 | +required. The MutatingAdmissionPolicy will only be active if a corresponding |
| 74 | +binding exists with the referenced `spec.policyName` matching the `spec.name` of |
| 75 | +a policy. |
| 76 | + |
| 77 | +Once the binding and policy are created, any resource request that matches the |
| 78 | +`spec.matchConditions` of a policy will trigger the set of mutations defined. |
| 79 | + |
| 80 | +In the example above, creating a Pod will add the `mesh-proxy` initContainer mutation: |
| 81 | + |
| 82 | +```yaml |
| 83 | +apiVersion: v1 |
| 84 | +kind: Pod |
| 85 | +metadata: |
| 86 | + name: myapp |
| 87 | + namespace: default |
| 88 | +spec: |
| 89 | + ... |
| 90 | + initContainers: |
| 91 | + - name: mesh-proxy |
| 92 | + image: mesh/proxy:v1.0.0 |
| 93 | + args: ["proxy", "sidecar"] |
| 94 | + restartPolicy: Always |
| 95 | + - name: myapp-initializer |
| 96 | + image: example/initializer:v1.0.0 |
| 97 | + ... |
| 98 | +``` |
| 99 | + |
| 100 | +#### Parameter resources |
| 101 | + |
| 102 | +Parameter resources allow a policy configuration to be separate from its |
| 103 | +definition. A policy can define `paramKind`, which outlines GVK of the parameter |
| 104 | +resource, and then a policy binding ties a policy by name (via `policyName`) to a |
| 105 | +particular parameter resource via `paramRef`. |
| 106 | + |
| 107 | +Please refer to [parameter resources](/docs/reference/access-authn-authz/validating-admission-policy/#parameter-resources) for more information. |
| 108 | + |
| 109 | +#### `ApplyConfiguration` {#patch-type-apply-configuration} |
| 110 | + |
| 111 | +MutatingAdmissionPolicy expressions are always CEL. Each apply configuration |
| 112 | +`expression` must evaluate to a CEL object (declared using `Object()` |
| 113 | +initialization). |
| 114 | + |
| 115 | +Apply configurations may not modify atomic structs, maps or arrays due to the risk of accidental deletion of |
| 116 | +values not included in the apply configuration. |
| 117 | + |
| 118 | +CEL expressions have access to the object types needed to create apply configurations: |
| 119 | + |
| 120 | +- `Object` - CEL type of the resource object. |
| 121 | +- `Object.<fieldName>` - CEL type of object field (such as `Object.spec`) |
| 122 | +- `Object.<fieldName1>.<fieldName2>...<fieldNameN>` - CEL type of nested field (such as `Object.spec.containers`) |
| 123 | + |
| 124 | +CEL expressions have access to the contents of the API request, organized into CEL variables as well as some other useful variables: |
| 125 | + |
| 126 | +- `object` - The object from the incoming request. The value is null for DELETE requests. |
| 127 | +- `oldObject` - The existing object. The value is null for CREATE requests. |
| 128 | +- `request` - Attributes of the API request. |
| 129 | +- `params` - Parameter resource referred to by the policy binding being evaluated. Only populated if the policy has a ParamKind. |
| 130 | +- `namespaceObject` - The namespace object that the incoming object belongs to. The value is null for cluster-scoped resources. |
| 131 | +- `variables` - Map of composited variables, from its name to its lazily evaluated value. |
| 132 | + For example, a variable named `foo` can be accessed as `variables.foo`. |
| 133 | +- `authorizer` - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request. |
| 134 | + See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz |
| 135 | +- `authorizer.requestResource` - A CEL ResourceCheck constructed from the `authorizer` and configured with the |
| 136 | + request resource. |
| 137 | + |
| 138 | +The `apiVersion`, `kind`, `metadata.name`, `metadata.generateName` and `metadata.labels` are always accessible from the root of the |
| 139 | +object. No other metadata properties are accessible. |
| 140 | + |
| 141 | +#### `JSONPatch` {#patch-type-json-patch} |
| 142 | + |
| 143 | +The same mutation can be written as a [JSON Patch](https://jsonpatch.com/) as follows: |
| 144 | + |
| 145 | +{{% code_sample language="yaml" file="mutatingadmissionpolicy/json-patch-example.yaml" %}} |
| 146 | + |
| 147 | +The expression will be evaluated by CEL to create a [JSON patch](https://jsonpatch.com/). |
| 148 | +ref: https://github.com/google/cel-spec |
| 149 | + |
| 150 | +Each evaluated `expression` must return an array of `JSONPatch` values. The |
| 151 | +`JSONPatch` type represents one operation from a JSON patch. |
| 152 | + |
| 153 | +For example, this CEL expression returns a JSON patch to conditionally modify a value: |
| 154 | + |
| 155 | +``` |
| 156 | + [ |
| 157 | + JSONPatch{op: "test", path: "/spec/example", value: "Red"}, |
| 158 | + JSONPatch{op: "replace", path: "/spec/example", value: "Green"} |
| 159 | + ] |
| 160 | +``` |
| 161 | + |
| 162 | +To define a JSON object for the patch operation `value`, use CEL `Object` types. For example: |
| 163 | + |
| 164 | +``` |
| 165 | + [ |
| 166 | + JSONPatch{ |
| 167 | + op: "add", |
| 168 | + path: "/spec/selector", |
| 169 | + value: Object.spec.selector{matchLabels: {"environment": "test"}} |
| 170 | + } |
| 171 | + ] |
| 172 | +``` |
| 173 | + |
| 174 | +To use strings containing '/' and '~' as JSONPatch path keys, use `jsonpatch.escapeKey()`. For example: |
| 175 | + |
| 176 | +``` |
| 177 | + [ |
| 178 | + JSONPatch{ |
| 179 | + op: "add", |
| 180 | + path: "/metadata/labels/" + jsonpatch.escapeKey("example.com/environment"), |
| 181 | + value: "test" |
| 182 | + }, |
| 183 | + ] |
| 184 | +``` |
| 185 | + |
| 186 | +CEL expressions have access to the types needed to create JSON patches and objects: |
| 187 | + |
| 188 | +- `JSONPatch` - CEL type of JSON Patch operations. JSONPatch has the fields `op`, `from`, `path` and `value`. |
| 189 | + See [JSON patch](https://jsonpatch.com/) for more details. The `value` field may be set to any of: string, |
| 190 | + integer, array, map or object. If set, the `path` and `from` fields must be set to a |
| 191 | + [JSON pointer](https://datatracker.ietf.org/doc/html/rfc6901/) string, where the `jsonpatch.escapeKey()` CEL |
| 192 | + function may be used to escape path keys containing `/` and `~`. |
| 193 | +- `Object` - CEL type of the resource object. |
| 194 | +- `Object.<fieldName>` - CEL type of object field (such as `Object.spec`) |
| 195 | +- `Object.<fieldName1>.<fieldName2>...<fieldNameN>` - CEL type of nested field (such as `Object.spec.containers`) |
| 196 | + |
| 197 | +CEL expressions have access to the contents of the API request, organized into CEL variables as well as some other useful variables: |
| 198 | + |
| 199 | +- `object` - The object from the incoming request. The value is null for DELETE requests. |
| 200 | +- `oldObject` - The existing object. The value is null for CREATE requests. |
| 201 | +- `request` - Attributes of the API request. |
| 202 | +- `params` - Parameter resource referred to by the policy binding being evaluated. Only populated if the policy has a ParamKind. |
| 203 | +- `namespaceObject` - The namespace object that the incoming object belongs to. The value is null for cluster-scoped resources. |
| 204 | +- `variables` - Map of composited variables, from its name to its lazily evaluated value. |
| 205 | + For example, a variable named `foo` can be accessed as `variables.foo`. |
| 206 | +- `authorizer` - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request. |
| 207 | + See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz |
| 208 | +- `authorizer.requestResource` - A CEL ResourceCheck constructed from the `authorizer` and configured with the |
| 209 | + request resource. |
| 210 | + |
| 211 | +CEL expressions have access to [Kubernetes CEL function libraries](/docs/reference/using-api/cel/#cel-options-language-features-and-libraries) |
| 212 | +as well as: |
| 213 | + |
| 214 | +- `jsonpatch.escapeKey` - Performs JSONPatch key escaping. `~` and `/` are escaped as `~0` and `~1` respectively. |
| 215 | + |
| 216 | +Only property names of the form `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*` are accessible. |
0 commit comments