Overview

In addition to the the default admission controllers, you can use admission webhooks as part of the admission chain.

Admission webhooks call webhook servers to either mutate pods upon creation, such as to inject labels, or to validate specific aspects of the pod configuration during the admission process.

Admission webhooks intercept requests to the master API prior to the persistence of a resource, but after the request is authenticated and authorized.

Admission Webhooks

In OpenShift Container Platform you can use admission webhook objects that call webhook servers during the API admission chain.

There are two types of admission webhook objects you can configure:

Configuring the webhooks and external webhook servers is beyond the scope of this document. However, the webhooks must adhere to an interface in order to work properly with OpenShift Container Platform.

Admission webhooks is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend to use them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features support scope, see https://access.redhat.com/support/offerings/techpreview/.

When an object is instantiated, OpenShift Container Platform makes an API call to admit the object. During the admission process, a mutating admission controller can invoke webhooks to perform tasks, such as injecting affinity labels. At the end of the admissions process, a validating admission controller can invoke webhooks to make sure the object is configured properly, such as verifying affinity labels. If the validation passes, OpenShift Container Platform schedules the object as configured.

When the API request comes in, the mutating or validating admission controller uses the list of external webhooks in the configuration and calls them in parallel:

  • If all of the webhooks approve the request, the admission chain continues.

  • If any of the webhooks deny the request, the admission request is denied, and the reason for doing so is based on the first webhook denial reason.

    If more than one webhook denies the admission request, only the first will be returned to the user.

  • If there is an error encountered when calling a webhook, that request is ignored and is be used to approve/deny the admission request.

The communication between the admission controller and the webhook server needs to be secured using TLS. Generate a CA certificate and use the certificate to sign the server certificate used by your webhook server. The PEM-formatted CA certificate is supplied to the admission controller using a mechanism, such as Service Serving Certificate Secrets.

The following diagram illustrates this process with two admission webhooks that call multiple webhooks.

API admission stage

A simple example use case for admission webhooks is syntactical validation of resources. For example, you have an infrastructure that requires all pods to have a common set of labels, and you do not want any pod to be persisted if the pod does not have those labels. You could write a webhook to inject these labels and another webhook to verify that the labels are present. The OpenShift Container Platform will then schedule pod that have the labels and pass validation and reject pods that do not pass due to missing labels.

Some common use-cases include:

  • Mutating resources to inject side-car containers into pods.

  • Restricting projects to block some resources from a project.

  • Custom resource validation to perform complex validation on dependent fields.

Types of Admission Webhooks

Cluster administrators can include mutating admission webhooks or validating admission webhooks in the admission chain of the API server.

Mutating admission webhooks are invoked during the mutation phase of the admission process, which allows modification of the resource content before it is persisted. One example of a mutating admission webhook is the Pod Node Selector feature, which uses an annotation on a namespace to find a label selector and add it to the pod specification.

Sample mutating admission webhook configuration:
apiVersion: admissionregistration.k8s.io/v1beta1
  kind: MutatingWebhookConfiguration (1)
  metadata:
    name: <controller_name> (2)
  webhooks:
  - name: <webhook_name> (3)
    clientConfig: (4)
      service:
        namespace:  (5)
        name: (6)
       path: <webhook_url> (7)
      caBundle: <cert> (8)
    rules: (9)
    - operations: (10)
      - <operation>
      apiGroups:
      - ""
      apiVersions:
      - "*"
      resources:
      - <resource>
    failurePolicy: <policy> (11)
1 Specifies a mutating admission webhook configuration.
2 The name for the admission webhook object.
3 The name of the webhook to call.
4 Information about how to connect to, trust, and send data to the webhook server.
5 The project where the front-end service is created.
6 The name of the front-end service.
7 The webhook URL used for admission requests.
8 A PEM-encoded CA certificate that signs the server certificate used by the webhook server.
9 Rules that define when the API server should use this controller.
10 The operation(s) that triggers the API server to call this controller:
  • create

  • update

  • delete

  • connect

11 Specifies how the policy should proceed if the webhook admission server is unavailable. Either Ignore (allow/fail open) or Fail (block/fail closed).

Validating admission webhooks are invoked during the validation phase of the admission process. This phase allows the enforcement of invariants on particular API resources to ensure that the resource does not change again. The Pod Node Selector is also an example of a validation admission, by ensuring that all nodeSelector fields are constrained by the node selector restrictions on the project.

Sample validating admission webhook configuration:
apiVersion: admissionregistration.k8s.io/v1beta1
  kind: ValidatingWebhookConfiguration (1)
  metadata:
    name: <controller_name> (2)
  webhooks:
  - name: <webhook_name> (3)
    clientConfig: (4)
      service:
        namespace: default  (5)
        name: kubernetes (6)
       path: <webhook_url> (7)
      caBundle: <cert> (8)
    rules: (9)
    - operations: (10)
      - <operation>
      apiGroups:
      - ""
      apiVersions:
      - "*"
      resources:
      - <resource>
    failurePolicy: <policy> (11)
1 Specifies a validating admission webhook configuration.
2 The name for the webhook admission object.
3 The name of the webhook to call.
4 Information about how to connect to, trust, and send data to the webhook server.
5 The project where the front-end service is created.
6 The name of the front-end service.
7 The webhook URL used for admission requests.
8 A PEM-encoded CA certificate that signs the server certificate used by the webhook server.
9 Rules that define when the API server should use this controller.
10 The operation that triggers the API server to call this controller.
  • create

  • update

  • delete

  • connect

11 Specifies how the policy should proceed if the webhook admission server is unavailable. Either Ignore (allow/fail open) or Fail (block/fail closed).

Fail open can result in unpredictable behavior for all clients.

Create the Admission Webhook

First deploy the external webhook server and ensure it is working properly. Otherwise, depending whether the webhook is configured as fail open or fail closed, operations will be unconditionally accepted or rejected.

  1. Configure a mutating or validating admission webhook object in a YAML file.

  2. Run the following command to create the object:

    oc create -f <file-name>.yaml

    After you create the admission webhook object, OpenShift Container Platform takes a few seconds to honor the new configuration.

  3. Create a front-end service for the admission webhook:

    apiVersion: v1
    kind: Service
    metadata:
      labels:
        role: webhook (1)
      name: <name>
    spec:
      selector:
       role: webhook (1)
    1 Free-form label to trigger the webhook.
  4. Run the following command to create the object:

    oc create -f <file-name>.yaml
  5. Add the admission webhook name to pods you want controlled by the webhook:

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        role: webhook (1)
      name: <name>
    spec:
      containers:
        - name: <name>
          image: myrepo/myimage:latest
          imagePullPolicy: <policy>
          ports:
           - containerPort: 8000
    1 Label to trigger the webhook.

See the kubernetes-namespace-reservation projects for an end-to-end example of how to build your own secure and portable webhook admission server and generic-admission-apiserver for the library.

Admission Webhook Example

The following is an example admission webhook that will not allow namespace creation if the namespace is reserved:

apiVersion: admissionregistration.k8s.io/v1beta1
  kind: ValidatingWebhookConfiguration
  metadata:
    name: namespacereservations.admission.online.openshift.io
  webhooks:
  - name: namespacereservations.admission.online.openshift.io
    clientConfig:
      service:
        namespace: default
        name: webhooks
       path: /apis/admission.online.openshift.io/v1beta1/namespacereservations
      caBundle: KUBE_CA_HERE
    rules:
    - operations:
      - CREATE
      apiGroups:
      - ""
      apiVersions:
      - "b1"
      resources:
      - namespaces
    failurePolicy: Ignore

The following is an example pod that will be evaluated by the admission webhook named webhook:

apiVersion: v1
kind: Pod
metadata:
  labels:
    role: webhook
  name: webhook
spec:
  containers:
    - name: webhook
      image: myrepo/myimage:latest
      imagePullPolicy: IfNotPresent
      ports:
- containerPort: 8000

The following is the front-end service for the webhook:

apiVersion: v1
kind: Service
metadata:
  labels:
    role: webhook
  name: webhook
spec:
  ports:
    - port: 443
      targetPort: 8000
  selector:
role: webhook