add admission webhook best practices and warnings (#15876)
This commit is contained in:
committed by
Kubernetes Prow Robot
parent
ae73bf69b9
commit
a7e11c24ae
@@ -1256,7 +1256,7 @@ webhooks:
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
Mutating webhooks must be idempotent, able to successfully process an object they have already admitted
|
||||
Mutating webhooks must be [idempotent](#idempotence), able to successfully process an object they have already admitted
|
||||
and potentially modified. This is true for all mutating admission webhooks, since any change they can make
|
||||
in an object could already exist in the user-provided object, but it is essential for webhooks that opt into reinvocation.
|
||||
|
||||
@@ -1458,4 +1458,103 @@ apiserver_admission_webhook_rejection_count{error_type="calling_webhook_error",n
|
||||
apiserver_admission_webhook_rejection_count{error_type="no_error",name="deny-unwanted-configmap-data.example.com",operation="CREATE",rejection_code="400",type="validating"} 13
|
||||
```
|
||||
|
||||
## Best practices and warnings
|
||||
|
||||
### Idempotence
|
||||
|
||||
An idempotent mutating admission webhook is able to successfully process an object it has already admitted
|
||||
and potentially modified. The admission can be applied multiple times without changing the result beyond
|
||||
the initial application.
|
||||
|
||||
#### Example of idempotent mutating admission webhooks:
|
||||
|
||||
1. For a `CREATE` pod request, set the field `.spec.securityContext.runAsNonRoot` of the
|
||||
pod to true, to enforce security best practices.
|
||||
|
||||
2. For a `CREATE` pod request, if the field `.spec.containers[].resources.limits`
|
||||
of a container is not set, set default resource limits.
|
||||
|
||||
3. For a `CREATE` pod request, inject a sidecar container with name `foo-sidecar` if no container with the name `foo-sidecar` already exists.
|
||||
|
||||
In the cases above, the webhook can be safely reinvoked, or admit an object that already has the fields set.
|
||||
|
||||
#### Example of non-idempotent mutating admission webhooks:
|
||||
|
||||
1. For a `CREATE` pod request, inject a sidecar container with name `foo-sidecar`
|
||||
suffixed with the current timestamp (e.g. `foo-sidecar-19700101-000000`).
|
||||
|
||||
2. For a `CREATE`/`UPDATE` pod request, reject if the pod has label `"env"` set,
|
||||
otherwise add an `"env": "prod"` label to the pod.
|
||||
|
||||
3. For a `CREATE` pod request, blindly append a sidecar container named
|
||||
`foo-sidecar` without looking to see if there is already a `foo-sidecar`
|
||||
container in the pod.
|
||||
|
||||
In the first case above, reinvoking the webhook can result in the same sidecar being injected multiple times to a pod, each time
|
||||
with a different container name. Similarly the webhook can inject duplicated containers if the sidecar already exists in
|
||||
a user-provided pod.
|
||||
|
||||
In the second case above, reinvoking the webhook will result in the webhook failing on its own output.
|
||||
|
||||
In the third case above, reinvoking the webhook will result in duplicated containers in the pod spec, which makes
|
||||
the request invalid and rejected by the API server.
|
||||
|
||||
### Intercepting all versions of an object
|
||||
|
||||
It is recommended that admission webhooks should always intercept all versions of an object by setting `.webhooks[].matchPolicy`
|
||||
to `Equivalent`. It is also recommended that admission webhooks should prefer registering for stable versions of resources.
|
||||
Failure to intercept all versions of an object can result in admission policies not being enforced for requests in certain
|
||||
versions. See [Matching requests: matchPolicy](#matching-requests-matchpolicy) for examples.
|
||||
|
||||
### Availability
|
||||
|
||||
It is recommended that admission webhooks should evaluate as quickly as possible (typically in milliseconds), since they add to API request latency.
|
||||
It is encouraged to use a small timeout for webhooks. See [Timeouts](#timeouts) for more detail.
|
||||
|
||||
It is recommended that admission webhooks should leverage some format of load-balancing, to provide high availability and
|
||||
performance benefits. If a webhook is running within the cluster, you can run multiple webhook backends behind a service
|
||||
to leverage the load-balancing that service supports.
|
||||
|
||||
### Guaranteeing the final state of the object is seen
|
||||
|
||||
Admission webhooks that need to guarantee they see the final state of the object in order to enforce policy
|
||||
should use a validating admission webhook, since objects can be modified after being seen by mutating webhooks.
|
||||
|
||||
For example, a mutating admission webhook is configured to inject a sidecar container with name "foo-sidecar" on every
|
||||
`CREATE` pod request. If the sidecar *must* be present, a validating admisson webhook should also be configured to intercept `CREATE` pod requests, and validate
|
||||
that a container with name "foo-sidecar" with the expected configuration exists in the to-be-created object.
|
||||
|
||||
### Avoiding deadlocks in self-hosted webhooks
|
||||
|
||||
A webhook running inside the cluster might cause deadlocks for its own deployment if it is configured
|
||||
to intercept resources required to start its own pods.
|
||||
|
||||
For example, a mutating admission webhook is configured to admit `CREATE` pod requests only if a certain label is set in the
|
||||
pod (e.g. `"env": "prod"`). The webhook server runs in a deployment which doesn't set the `"env"` label.
|
||||
When a node that runs the webhook server pods
|
||||
becomes unhealthy, the webhook deployment will try to reschedule the pods to another node. However the requests will
|
||||
get rejected by the existing webhook server since the `"env"` label is unset, and the migration cannot happen.
|
||||
|
||||
It is recommended to exclude the namespace where your webhook is running with a [namespaceSelector](#matching-requests-namespaceselector).
|
||||
|
||||
### Side effects
|
||||
|
||||
It is recommended that admission webhooks should avoid side effects if possible, which means the webhooks operate only on the
|
||||
content of the `AdmissionReview` sent to them, and do not make out-of-band changes. The `.webhooks[].sideEffects` field should
|
||||
be set to `None` if a webhook doesn't have any side effect.
|
||||
|
||||
If side effects are required during the admission evaluation, they must be suppressed when processing an
|
||||
`AdmissionReview` object with `dryRun` set to `true`, and the `.webhooks[].sideEffects` field should be
|
||||
set to `NoneOnDryRun`. See [Side effects](#side-effects) for more detail.
|
||||
|
||||
### Avoiding operating on the kube-system namespace
|
||||
|
||||
The `kube-system` namespace contains objects created by the Kubernetes system,
|
||||
e.g. service accounts for the control plane components, pods like `kube-dns`.
|
||||
Accidentally mutating or rejecting requests in the `kube-system` namespace may
|
||||
cause the control plane components to stop functioning or introduce unknown behavior.
|
||||
If your admission webhooks don't intend to modify the behavior of the Kubernetes control
|
||||
plane, exclude the `kube-system` namespace from being intercepted using a
|
||||
[`namespaceSelector`](#matching-requests-namespaceselector).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
Reference in New Issue
Block a user