Skip to content

Commit 1422082

Browse files
committed
Move best practices from dynamic admission control page to best practices page
Moved content as-is (no text changes) for a more readable diff between commits. The following sections werent moved: * Idempotence main section (better content in new page) * Intercepting all versions of an object (better content in new page) * Guaranteeing the final state of an object is seen * Avoiding operating in the kube-system namespace
1 parent bf971d2 commit 1422082

File tree

2 files changed

+61
-142
lines changed

2 files changed

+61
-142
lines changed

content/en/docs/concepts/cluster-administration/admission-webhooks-good-practices.md

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,11 +283,27 @@ Consider the following when modifying arrays:
283283

284284
### Avoid side effects {#avoid-side-effects}
285285

286-
TODO: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#side-effects-1
286+
It is recommended that admission webhooks should avoid side effects if possible, which means the webhooks operate only on the
287+
content of the `AdmissionReview` sent to them, and do not make out-of-band changes. The `.webhooks[].sideEffects` field should
288+
be set to `None` if a webhook doesn't have any side effect.
289+
290+
If side effects are required during the admission evaluation, they must be suppressed when processing an
291+
`AdmissionReview` object with `dryRun` set to `true`, and the `.webhooks[].sideEffects` field should be
292+
set to `NoneOnDryRun`. See [Side effects](#side-effects) for more detail.
287293

288294
### Avoid self-mutations {#avoid-self-mutation}
289295

290-
TODO: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#avoiding-deadlocks-in-self-hosted-webhooks
296+
A webhook running inside the cluster might cause deadlocks for its own deployment if it is configured
297+
to intercept resources required to start its own pods.
298+
299+
For example, a mutating admission webhook is configured to admit `CREATE` pod requests only if a certain label is set in the
300+
pod (e.g. `"env": "prod"`). The webhook server runs in a deployment which doesn't set the `"env"` label.
301+
When a node that runs the webhook server pods
302+
becomes unhealthy, the webhook deployment will try to reschedule the pods to another node. However the requests will
303+
get rejected by the existing webhook server since the `"env"` label is unset, and the migration cannot happen.
304+
305+
It is recommended to exclude the namespace where your webhook is running with a
306+
[namespaceSelector](#matching-requests-namespaceselector).
291307

292308
### Fail open and validate the final state {#fail-open-validate-final-state}
293309

@@ -386,7 +402,39 @@ challenging. The following recommendations might help:
386402
multiple times by the same webhook.
387403
* Ensure that the scope of each mutating webhook is specific and limited.
388404

389-
TODO: bring examples from https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#idempotence
405+
#### Example of idempotent mutating admission webhooks:
406+
407+
1. For a `CREATE` pod request, set the field `.spec.securityContext.runAsNonRoot` of the
408+
pod to true, to enforce security best practices.
409+
410+
2. For a `CREATE` pod request, if the field `.spec.containers[].resources.limits`
411+
of a container is not set, set default resource limits.
412+
413+
3. For a `CREATE` pod request, inject a sidecar container with name `foo-sidecar` if no container
414+
with the name `foo-sidecar` already exists.
415+
416+
In the cases above, the webhook can be safely reinvoked, or admit an object that already has the fields set.
417+
418+
#### Example of non-idempotent mutating admission webhooks:
419+
420+
1. For a `CREATE` pod request, inject a sidecar container with name `foo-sidecar`
421+
suffixed with the current timestamp (e.g. `foo-sidecar-19700101-000000`).
422+
423+
2. For a `CREATE`/`UPDATE` pod request, reject if the pod has label `"env"` set,
424+
otherwise add an `"env": "prod"` label to the pod.
425+
426+
3. For a `CREATE` pod request, blindly append a sidecar container named
427+
`foo-sidecar` without looking to see if there is already a `foo-sidecar`
428+
container in the pod.
429+
430+
In the first case above, reinvoking the webhook can result in the same sidecar being injected multiple times to a pod, each time
431+
with a different container name. Similarly the webhook can inject duplicated containers if the sidecar already exists in
432+
a user-provided pod.
433+
434+
In the second case above, reinvoking the webhook will result in the webhook failing on its own output.
435+
436+
In the third case above, reinvoking the webhook will result in duplicated containers in the pod spec, which makes
437+
the request invalid and rejected by the API server.
390438

391439
## Mutation testing and validation {#mutation-testing-validation}
392440

@@ -493,6 +541,15 @@ Consider situations like the preceding example when writing your webhooks.
493541
Exclude operations that are a result of Kubernetes responding to unavoidable
494542
incidents.
495543

544+
It is recommended that admission webhooks should evaluate as quickly as possible (typically in
545+
milliseconds), since they add to API request latency.
546+
It is encouraged to use a small timeout for webhooks. See [Timeouts](#timeouts) for more detail.
547+
548+
It is recommended that admission webhooks should leverage some format of load-balancing, to
549+
provide high availability and performance benefits. If a webhook is running within the cluster,
550+
you can run multiple webhook backends behind a service to leverage the load-balancing that service
551+
supports.
552+
496553
## Examples of good implementations {#example-good-implementations}
497554

498555
{{% thirdparty-content %}}

content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md

Lines changed: 1 addition & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,142 +1178,4 @@ apiserver_admission_webhook_rejection_count{error_type="no_error",name="deny-unw
11781178

11791179
For recommendations and considerations when writing mutating admission webhooks,
11801180
see
1181-
[Mutating Webhooks Good Practices](/docs/concepts/security/mutating-webhooks-good-practices).
1182-
1183-
### Idempotence
1184-
1185-
An idempotent mutating admission webhook is able to successfully process an object it has already admitted
1186-
and potentially modified. The admission can be applied multiple times without changing the result beyond
1187-
the initial application.
1188-
1189-
#### Example of idempotent mutating admission webhooks:
1190-
1191-
1. For a `CREATE` pod request, set the field `.spec.securityContext.runAsNonRoot` of the
1192-
pod to true, to enforce security best practices.
1193-
1194-
2. For a `CREATE` pod request, if the field `.spec.containers[].resources.limits`
1195-
of a container is not set, set default resource limits.
1196-
1197-
3. For a `CREATE` pod request, inject a sidecar container with name `foo-sidecar` if no container
1198-
with the name `foo-sidecar` already exists.
1199-
1200-
In the cases above, the webhook can be safely reinvoked, or admit an object that already has the fields set.
1201-
1202-
#### Example of non-idempotent mutating admission webhooks:
1203-
1204-
1. For a `CREATE` pod request, inject a sidecar container with name `foo-sidecar`
1205-
suffixed with the current timestamp (e.g. `foo-sidecar-19700101-000000`).
1206-
1207-
2. For a `CREATE`/`UPDATE` pod request, reject if the pod has label `"env"` set,
1208-
otherwise add an `"env": "prod"` label to the pod.
1209-
1210-
3. For a `CREATE` pod request, blindly append a sidecar container named
1211-
`foo-sidecar` without looking to see if there is already a `foo-sidecar`
1212-
container in the pod.
1213-
1214-
In the first case above, reinvoking the webhook can result in the same sidecar being injected multiple times to a pod, each time
1215-
with a different container name. Similarly the webhook can inject duplicated containers if the sidecar already exists in
1216-
a user-provided pod.
1217-
1218-
In the second case above, reinvoking the webhook will result in the webhook failing on its own output.
1219-
1220-
In the third case above, reinvoking the webhook will result in duplicated containers in the pod spec, which makes
1221-
the request invalid and rejected by the API server.
1222-
1223-
### Intercepting all versions of an object
1224-
1225-
It is recommended that admission webhooks should always intercept all versions of an object by setting `.webhooks[].matchPolicy`
1226-
to `Equivalent`. It is also recommended that admission webhooks should prefer registering for stable versions of resources.
1227-
Failure to intercept all versions of an object can result in admission policies not being enforced for requests in certain
1228-
versions. See [Matching requests: matchPolicy](#matching-requests-matchpolicy) for examples.
1229-
1230-
### Availability
1231-
1232-
It is recommended that admission webhooks should evaluate as quickly as possible (typically in
1233-
milliseconds), since they add to API request latency.
1234-
It is encouraged to use a small timeout for webhooks. See [Timeouts](#timeouts) for more detail.
1235-
1236-
It is recommended that admission webhooks should leverage some format of load-balancing, to
1237-
provide high availability and performance benefits. If a webhook is running within the cluster,
1238-
you can run multiple webhook backends behind a service to leverage the load-balancing that service
1239-
supports.
1240-
1241-
### Guaranteeing the final state of the object is seen
1242-
1243-
Admission webhooks that need to guarantee they see the final state of the object in order to enforce policy
1244-
should use a validating admission webhook, since objects can be modified after being seen by mutating webhooks.
1245-
1246-
For example, a mutating admission webhook is configured to inject a sidecar container with name
1247-
"foo-sidecar" on every `CREATE` pod request. If the sidecar *must* be present, a validating
1248-
admisson webhook should also be configured to intercept `CREATE` pod requests, and validate that a
1249-
container with name "foo-sidecar" with the expected configuration exists in the to-be-created
1250-
object.
1251-
1252-
### Avoiding deadlocks in self-hosted webhooks
1253-
1254-
There are several ways that webhooks can cause deadlocks, where the cluster cannot make progress in
1255-
scheduling pods:
1256-
1257-
* A webhook running inside the cluster might cause deadlocks for its own deployment if it is configured
1258-
to intercept resources required to start its own pods.
1259-
1260-
For example, a mutating admission webhook is configured to admit **create** Pod requests only if a certain label is set in the
1261-
pod (such as `env: "prod"`). However, the webhook server runs as a Deployment that doesn't set the `env` label.
1262-
When a node that runs the webhook server pods
1263-
becomes unhealthy, the webhook deployment will try to reschedule the pods to another node. However the requests will
1264-
get rejected by the existing webhook server since the `env` label is unset, and the replacement Pod
1265-
cannot be created. Eventually, the entire Deployment for the webhook server may become unhealthy.
1266-
1267-
If you use admission webhooks to check Pods, consider excluding the namespace where your webhook
1268-
listener is running, by specifying a
1269-
[namespaceSelector](#matching-requests-namespaceselector).
1270-
1271-
* If the cluster has multiple webhooks configured (possibly from independent applications deployed on
1272-
the cluster), they can form a cycle. Webhook A must be called to process startup of webhook B's
1273-
pods and vice versa. If both webhook A and webhook B ever become unavailable at the same time (for
1274-
example, due to a cluster-wide outage or a node failure where both pods run on the same node)
1275-
deadlock occurs because neither webhook pod can be recreated without the other already running.
1276-
1277-
One way to prevent this is to exclude webhook A's pods from being acted on be webhook B. This
1278-
allows webhook A's pods to start, which in turn allows webhook B's pods to start. If you had a
1279-
third webhook, webhook C, you'd need to exclude both webhook A and webhook B's pods from
1280-
webhook C. This ensures that webhook A can _always_ start, which then allows webhook B's pods
1281-
to start, which in turn allows webhook C's pods to start.
1282-
1283-
If you want to ensure protection that avoids these risks, [ValidatingAdmissionPolicies](/docs/reference/access-authn-authz/validating-admission-policy/)
1284-
can
1285-
provide many protection capabilities without introducing dependency cycles.
1286-
1287-
* Admission webhooks can intercept resources used by critical cluster add-ons, such as CoreDNS,
1288-
network plugins, or storage plugins. These add-ons may be required to schedule or successfully run the
1289-
pods for a particular admission webhook on the cluster. This can cause a deadlock if both the
1290-
webhook and critical add-on is unavailable at the same time.
1291-
1292-
You may wish to exclude cluster infrastructure namespaces from webhooks, or make sure that
1293-
the webhook does not depend on the particular add-on that it acts on. For exmaple, running
1294-
a webhook as a host-networked pod ensures that it does not depend on a networking plugin.
1295-
1296-
If you want to ensure protection for a core add-on / or its namespace,
1297-
[ValidatingAdmissionPolicies](/docs/reference/access-authn-authz/validating-admission-policy/)
1298-
can
1299-
provide many protection capabilities without any dependency on worker nodes and Pods.
1300-
1301-
### Side effects
1302-
1303-
It is recommended that admission webhooks should avoid side effects if possible, which means the webhooks operate only on the
1304-
content of the `AdmissionReview` sent to them, and do not make out-of-band changes. The `.webhooks[].sideEffects` field should
1305-
be set to `None` if a webhook doesn't have any side effect.
1306-
1307-
If side effects are required during the admission evaluation, they must be suppressed when processing an
1308-
`AdmissionReview` object with `dryRun` set to `true`, and the `.webhooks[].sideEffects` field should be
1309-
set to `NoneOnDryRun`. See [Side effects](#side-effects) for more detail.
1310-
1311-
### Avoiding operating on the kube-system namespace
1312-
1313-
The `kube-system` namespace contains objects created by the Kubernetes system,
1314-
e.g. service accounts for the control plane components, pods like `kube-dns`.
1315-
Accidentally mutating or rejecting requests in the `kube-system` namespace may
1316-
cause the control plane components to stop functioning or introduce unknown behavior.
1317-
If your admission webhooks don't intend to modify the behavior of the Kubernetes control
1318-
plane, exclude the `kube-system` namespace from being intercepted using a
1319-
[`namespaceSelector`](#matching-requests-namespaceselector).
1181+
[Admission Webhooks Good Practices](/docs/concepts/cluster-administration/admission-webhooks-good-practices).

0 commit comments

Comments
 (0)