This article explores Admission Controllers in Kubernetes, detailing their types, configuration, and examples of custom implementations.
In this lesson, we explore the various types of Admission Controllers in Kubernetes and demonstrate how to configure custom ones. Admission Controllers are plugins that govern and enforce cluster usage. They fall into two main categories:
Validating Admission Controllers: These controllers check incoming requests and either allow or deny them based on predefined rules.
Mutating Admission Controllers: These controllers modify requests by adjusting the object before it is persisted to the cluster.
One example of a validating admission controller is the namespace existence (or namespace lifecycle) controller, which ensures that a namespace exists before allowing a request. If the namespace does not exist, the request is rejected.Another example is the default storage class admission controller, which is enabled by default. Consider the following scenario: when you submit a request to create a PersistentVolumeClaim (PVC) without specifying a storage class, the built-in admission controller intervenes by modifying the request to include the preconfigured default storage class.
This PVC creation request passes through several stages: authentication, authorization, and finally, the admission controllers. The default storage class controller detects the missing storage class and automatically adds it to the request. The resulting PVC appears as follows:
Mutating admission controllers modify the request (e.g., adding a default storage class), while validating admission controllers only verify the request against set policies. In some cases, controllers perform both actions.
Typically, mutating controllers run before validating controllers so that any modifications are validated. For example, a namespace auto-provisioning controller (a mutating controller) can create missing namespaces before the validating “namespace exists” controller runs. If the order were reversed, the validating controller might reject requests for non-existent namespaces, preventing auto-provisioning from occurring.If any admission controller in the processing chain rejects a request, the entire operation fails and an error message is returned to the user.
In addition to built-in admission controllers, Kubernetes allows you to implement custom logic via two types of external webhooks:
Mutating Admission Webhook
Validating Admission Webhook
These webhooks let you direct admission review requests to a custom server—either within or outside your cluster. After the built-in admission controllers process a request, it is forwarded to the webhook. The webhook server receives an admission review object in JSON format containing details such as the user, requested operation, and the object involved.
To utilize a custom admission controller, you must deploy your own webhook server, which contains the custom logic for mutation and/or validation. The server can be developed using any programming language that supports HTTPS (TLS is required for secure communication with the Kubernetes API server).
Below is an excerpt from a sample admission webhook server written in Go:
Copy
Ask AI
package mainimport ( "encoding/json" "flag" "fmt" "io/ioutil" "net/http" "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog")// toAdmissionResponse is a helper function to create an AdmissionResponse with an embedded error.func toAdmissionResponse(err error) v1beta1.AdmissionResponse { return v1beta1.AdmissionResponse{ Result: &metav1.Status{ Message: err.Error(), }, }}// admitFunc defines the function signature used for validators and mutators.type admitFunc func(v1beta1.AdmissionReview) v1beta1.AdmissionResponse// serve handles the HTTP portion of a request prior to passing it to an admit function.func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) { var body []byte if r.Body != nil { if data, err := ioutil.ReadAll(r.Body); err == nil { body = data } } // Further processing would continue here...}
Although this example is written in Go, you can build your webhook server in any language that accommodates HTTPS and JSON-based API communications.
The following pseudocode demonstrates a simple webhook server in Python using Flask. It includes two routes: one for validation and another for mutation.
In this Python example, the validation endpoint rejects requests where the object’s name matches the user name, while the mutation endpoint adds a label with the username using a JSON patch.
After deploying your webhook server, configure your Kubernetes cluster to use it by creating a webhook configuration object. Below is an example of a ValidatingWebhookConfiguration:
TLS is used for secure communication, as indicated by the caBundle.
The API server references the webhook service by its name and namespace when deployed within the cluster.
For mutating webhooks, a similar configuration is created with kind: MutatingWebhookConfiguration.Once applied, every time a pod is created (or another resource event specified in your rules), the API server calls your webhook server. Depending on whether the response indicates approval or rejection, the API server will allow or reject the request.
This lesson provided an overview of validating and mutating admission controllers in Kubernetes. Key takeaways include:
An understanding of built-in admission controllers and their roles in request validation and mutation.
How external admission webhooks can extend Kubernetes by allowing custom logic.
Practical examples of webhook servers implemented in Go and Python.
Steps to configure your Kubernetes cluster to integrate with these webhooks.
Experimenting in a lab environment is crucial to reinforce these concepts. Continue exploring advanced scenarios to further enhance your Kubernetes security and operational flexibility.