I recently wrote another Mutating Webhook for K8s and read the official documentation. Some special points to remember are summarized below. Although it is mainly for Mutating type webhooks, it should work for Validating type webhooks as well.

Versioning

One of the most troublesome things about programming in K8s is the issue of versioning and the resulting dependencies on go mod. So the first thing you need to do before writing code, and before referring to other people’s code, is to check which API versions you need to support and use.

For Mutating Webhook, the API version is admissionregistration.k8s.io/v1beta1 before K8s 1.9, and admissionregistration.k8s.io/v1 for K8s after 1.16.

Default timeout time

The default timeout is 10s for admissionregistration.k8s.io/v1 and 30s for admissionregistration.k8s.io/v1beta1.

However, starting with K8s 1.14, custom timeouts are supported. It is generally recommended to use a smaller timeout value for two reasons: one is that webhooks generally run in the same cluster as K8s, so there is not much latency. Webhook takes too long, it should be said that the program has problems or design problems, in line with the principle of fast fail, should set a small timeout time.

About Resource Filters

Resource filters can be used to filter resources that need to be modified.

objectSelector

For example, the following example selects only resources with the foo: bar label.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
webhooks:
- name: my-webhook.example.com
  objectSelector:
    matchLabels:
      foo: bar
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "*"

namespaceSelector

namespaceSelector filters for namespaced resources or resources of type Namespace by determining whether the labels of the namespace in which the resource is located contain the specified laable. If the object type to be checked is Namespace, then its object.metadata.labels will be determined.

namespaceSelector does not work for cluster-level resources.

This example shows a validating type webhook that will match CREATR requests to namespaced resources with environment set to “prod” or “staging " of the resource.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  namespaceSelector:
    matchExpressions:
    - key: environment
      operator: In
      values: ["prod","staging"]
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "Namespaced"

Specify the webhook connection method

There are two connection settings that tell the API server how to find the webhook address, one is specified directly using the URL, and the other uses the K8s service resource.

URL method

This method requires only specifying a URL in the scheme://host:port/path format, which is relatively straightforward and can be used, for example, to specify the address of a service other than K8s.

One limitation is that the scheme must be https, which means you may encounter problems with certificate authentication when deploying, and there is no explanation here about how to create a certificate, especially a self-signed one.

Also this approach has the limitation that basic authentication like user@pass is not supported, nor is the use of ? or #, which are special separators in the href.

Example.

1
2
3
4
5
6
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
webhooks:
- name: my-webhook.example.com
  clientConfig:
    url: "https://my-webhook.example.com:9443/my-webhook-path"

service references

If the webhook is running in a cluster, it is easier to specify the address of the webhook via service. namespace and name of the service are required, port is not required and has a default value of 443 because of the https protocol.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration

webhooks:
- name: my-webhook.example.com
  clientConfig:
    caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
    service:
      namespace: my-service-namespace
      name: my-service-name
      path: /my-path
      port: 1234

Note: In this case, when the ca certificate is signed, the server name must be <svc_name>. <svc_namespace>.svc.