Configuring dynamic admission

You can complete high-level steps to configure dynamic admission. These steps extend the admission chain by configuring a webhook admission plugin to call out to a webhook server.

The webhook server is also configured as an aggregated API server. This allows other Red Hat OpenShift Container Platform components to communicate with the webhook that uses internal credentials and facilitates testing that uses the oc command. Additionally, this enables role-based access control (RBAC) into the webhook and prevents token information from other API servers from being disclosed to the webhook.

Prerequisites
  • An Red Hat OpenShift Container Platform account with cluster administrator access.

  • The Red Hat OpenShift Container Platform OpenShift CLI (oc) installed.

  • A published webhook server container image.

Procedure
  1. Build a webhook server container image and make it available to the cluster by using an image registry.

  2. Create a local CA key and certificate and use them to sign the webhook server’s certificate signing request (CSR).

  3. Create a new project for webhook resources:

    $ oc new-project my-webhook-namespace
    • Note that the webhook server might expect a specific name.

  4. Define RBAC rules for the aggregated API service in a file called rbac.yaml:

    apiVersion: v1
    kind: List
    items:
    
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: auth-delegator-my-webhook-namespace
      roleRef:
        kind: ClusterRole
        apiGroup: rbac.authorization.k8s.io
        name: system:auth-delegator
      subjects:
      - kind: ServiceAccount
        namespace: my-webhook-namespace
        name: server
    
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        annotations:
        name: system:openshift:online:my-webhook-server
      rules:
      - apiGroups:
        - online.openshift.io
        resources:
        - namespacereservations
        verbs:
        - get
        - list
        - watch
    
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: system:openshift:online:my-webhook-requester
      rules:
      - apiGroups:
        - admission.online.openshift.io
        resources:
        - namespacereservations
        verbs:
        - create
    
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: my-webhook-server-my-webhook-namespace
      roleRef:
        kind: ClusterRole
        apiGroup: rbac.authorization.k8s.io
        name: system:openshift:online:my-webhook-server
      subjects:
      - kind: ServiceAccount
        namespace: my-webhook-namespace
        name: server
    
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        namespace: kube-system
        name: extension-server-authentication-reader-my-webhook-namespace
      roleRef:
        kind: Role
        apiGroup: rbac.authorization.k8s.io
        name: extension-apiserver-authentication-reader
      subjects:
      - kind: ServiceAccount
        namespace: my-webhook-namespace
        name: server
    
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: my-cluster-role
      rules:
      - apiGroups:
        - admissionregistration.k8s.io
        resources:
        - validatingwebhookconfigurations
        - mutatingwebhookconfigurations
        verbs:
        - get
        - list
        - watch
      - apiGroups:
        - ""
        resources:
        - namespaces
        verbs:
        - get
        - list
        - watch
    
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: my-cluster-role
      roleRef:
        kind: ClusterRole
        apiGroup: rbac.authorization.k8s.io
        name: my-cluster-role
      subjects:
      - kind: ServiceAccount
        namespace: my-webhook-namespace
        name: server

    where:

    apiVersion: rbac.authorization.k8s.io/v1

    For ClusterRoleBinding, specifies authentication and authorization metadata to the webhook server API.

    apiVersion: rbac.authorization.k8s.io/v1

    For ClusterRole, specifies the webhook server that is allowed access cluster resources.

    rules.resources

    For ClusterRole, specifies the location to resources. This example points to the namespacereservations resource.

    apiVersion: rbac.authorization.k8s.io/v1

    For ClusterRole, specifies the enablement of the aggregated API server to create admission reviews.

    apiVersion: rbac.authorization.k8s.io/v1

    For ClusterRoleBinding, specifies the enablement of the webhook server to access cluster resources.

    apiVersion: rbac.authorization.k8s.io/v1

    For RoleBinding, specifies role binding to read the configuration for terminating authentication.

    apiVersion: rbac.authorization.k8s.io/v1

    For ClusterRole, specifies the default cluster role and cluster role bindings for an aggregated API server.

  5. Apply those RBAC rules to the cluster:

    $ oc auth reconcile -f rbac.yaml
  6. Create a YAML file called webhook-daemonset.yaml that is used to deploy a webhook as a daemon set server in a namespace:

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      namespace: my-webhook-namespace
      name: server
      labels:
        server: "true"
    spec:
      selector:
        matchLabels:
          server: "true"
      template:
        metadata:
          name: server
          labels:
            server: "true"
        spec:
          serviceAccountName: server
          containers:
          - name: my-webhook-container
            image: <image_registry_username>/<image_path>:<tag>
            imagePullPolicy: IfNotPresent
            command:
            - <container_commands>
            ports:
            - containerPort: 8443
            volumeMounts:
            - mountPath: /var/serving-cert
              name: serving-cert
            readinessProbe:
              httpGet:
                path: /healthz
                port: 8443
                scheme: HTTPS
          volumes:
          - name: serving-cert
            secret:
              defaultMode: 420
              secretName: server-serving-cert

    where:

    spec.template.spec.name

    Specifies the container name. Note that the webhook server might expect a specific container name.

    spec.template.spec.image

    Specifies the path to a webhook server container image. Replace <image_registry_username>/<image_path>:<tag> with the appropriate value.

    spec.template.spec.command

    Specifies webhook container run commands. Replace <container_commands> with the appropriate value.

    spec.template.spec.ports.containerPort

    Specifies the target port within pods. This example uses port 8443.

    spec.template.spec.readinessProbe.port

    Specifies the port used by the readiness probe. This example uses port 8443.

  7. Deploy the daemon set:

    $ oc apply -f webhook-daemonset.yaml
  8. Define a secret for the service serving certificate signer, within a YAML file called webhook-secret.yaml:

    apiVersion: v1
    kind: Secret
    metadata:
      namespace: my-webhook-namespace
      name: server-serving-cert
    type: kubernetes.io/tls
    data:
      tls.crt: <server_certificate>
      tls.key: <server_key>

    where:

    data.tls.crt

    References the signed webhook server certificate. Replace <server_certificate> with the appropriate certificate in base64 format.

    data.tls.key

    References the signed webhook server key. Replace <server_key> with the appropriate key in base64 format.

  9. Create the secret:

    $ oc apply -f webhook-secret.yaml
  10. Define a service account and service, within a YAML file called webhook-service.yaml:

    apiVersion: v1
    kind: List
    items:
    
    - apiVersion: v1
      kind: ServiceAccount
      metadata:
        namespace: my-webhook-namespace
        name: server
    
    - apiVersion: v1
      kind: Service
      metadata:
        namespace: my-webhook-namespace
        name: server
        annotations:
          service.beta.openshift.io/serving-cert-secret-name: server-serving-cert
      spec:
        selector:
          server: "true"
        ports:
        - port: 443
          targetPort: 8443

    where:

    spec.ports.port

    Specifies the port that the service listens on. This example uses port 443.

    spec.ports.targetPort

    Specifies the target port within pods that the service forwards connections to. This example uses port 8443.

  11. Expose the webhook server within the cluster:

    $ oc apply -f webhook-service.yaml
  12. Define a custom resource definition for the webhook server, in a file called webhook-crd.yaml:

    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: namespacereservations.online.openshift.io
    spec:
      group: online.openshift.io
      version: v1alpha1
      scope: Cluster
      names:
        plural: namespacereservations
        singular: namespacereservation
        kind: NamespaceReservation

    where:

    metadata.name

    Reflects CustomResourceDefinition spec values and is in the format <plural>.<group>. This example uses the namespacereservations resource.

    spec.group

    Specifies the REST API group name.

    spec.version

    Specifies the REST API version name.

    spec.scope

    Specifies accepted values are Namespaced or Cluster.

    spec.names.plural

    Specifies the plural name to be included in URL.

    spec.names.singular

    Specifies the alias seen in oc output.

    spec.names.kind

    Specifies the reference for resource manifests.

  13. Apply the custom resource definition:

    $ oc apply -f webhook-crd.yaml
  14. Configure the webhook server also as an aggregated API server, within a file called webhook-api-service.yaml:

    apiVersion: apiregistration.k8s.io/v1beta1
    kind: APIService
    metadata:
      name: v1beta1.admission.online.openshift.io
    spec:
      caBundle: <ca_signing_certificate>
      group: admission.online.openshift.io
      groupPriorityMinimum: 1000
      versionPriority: 15
      service:
        name: server
        namespace: my-webhook-namespace
      version: v1beta1
    • The spec.caBundle field specifies a PEM-encoded CA certificate that signs the server certificate. This certificate is used by the webhook server. Replace <ca_signing_certificate> with the appropriate certificate in base64 format.

  15. Deploy the aggregated API service:

    $ oc apply -f webhook-api-service.yaml
  16. Define the webhook admission plugin configuration within a file called webhook-config.yaml. This example uses the validating admission plugin:

    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: kubernetes
          path: /apis/admission.online.openshift.io/v1beta1/namespacereservations
        caBundle: <ca_signing_certificate>
      rules:
      - operations:
        - CREATE
        apiGroups:
        - project.openshift.io
        apiVersions:
        - "*"
        resources:
        - projectrequests
      - operations:
        - CREATE
        apiGroups:
        - ""
        apiVersions:
        - "*"
        resources:
        - namespaces
      failurePolicy: Fail

    where:

    metadata.name

    Specifies the name for the ValidatingWebhookConfiguration object. This example uses the namespacereservations resource.

    webhooks.name

    Specifies the name of the webhook to call. This example uses the namespacereservations resource.

    name.clientConfig.service

    Enables access to the webhook server through the aggregated API.

    name.clientConfig.service.path

    Specifies the webhook URL used for admission requests. This example uses the namespacereservation resource.

    name.clientConfig.caBundle

    Specifies a PEM-encoded CA certificate that signs the server certificate that is used by the webhook server. Replace <ca_signing_certificate> with the appropriate certificate in base64 format.

  17. Deploy the webhook:

    $ oc apply -f webhook-config.yaml
  18. Verify that the webhook is functioning as expected. For example, if you have configured dynamic admission to reserve specific namespaces, confirm that requests to create those namespaces are rejected and that requests to create non-reserved namespaces succeed.