Preface
Kubernetes provides three security access control measures for API access: authentication, authorization and Admission Control. Authentication solves the problem of who the user is, and authorization solves the problem of what the user can do. Admission Control is the role of resource management. Reasonable authority management can ensure the safety and reliability of the system.
This paper mainly talks about Validating Admission Web hook and Matting Admission Web hook in Admission.
AdmissionWebhook
We know that k8s has scalability in all aspects, such as the implementation of a variety of network models through cni, a variety of storage engines through csi, a variety of container runtime through cri and so on. Admission webhook is another extensible tool. In addition to the compiled Admission plug-ins, you can develop your own Admission plug-ins as extensions and configure them as webhooks at runtime.
Admission webhooks are HTTP callbacks that receive Admission requests and do something to them. You can define two types of Admission webhooks, Validating Admission webhook and Matting Admission webhook.
If Mutating Admission is enabled, when you start creating a k8s resource object, the creation request will be sent to the controller you write, and then we can do a series of operations. For example, in our scenario, we will do some functional enhancements in a unified way. When business development creates a new deployment, we will perform some injected operations, such as sensitive information aksk, or some optimized init scripts.
Similarly, Validating Admission Web hook allows the creation of resources according to your custom logic. For example, in the actual production of k8s cluster, we are in the stability consideration, we require that the deployment created must set request and limit.
How to Realize Your Admission Webhook Server
Prerequisite
- k8s version requires at least v1.9
- Ensure that Mutating Admission Webhook and Validating Admission Webhook admission controllers are enabled
- Make sure admission registration. k8s. IO / v1beta1 is enabled
Write an admission webhook server
Officially provided a demo This is the case. You can study it in detail. The core idea is:
webhook handles the AdmissionReview request sent by apiservers and sends back its decision as an AdmissionReview object.
package main import ( "encoding/json" "flag" "fmt" "io/ioutil" "net/http" "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog" // TODO: try this library to see if it generates correct json patch // https://github.com/mattbaird/jsonpatch ) // 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 is the type we use for all of our validators and mutators type admitFunc func(v1beta1.AdmissionReview) *v1beta1.AdmissionResponse // serve handles the http portion of a request prior to handing 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 } } // verify the content type is accurate contentType := r.Header.Get("Content-Type") if contentType != "application/json" { klog.Errorf("contentType=%s, expect application/json", contentType) return } klog.V(2).Info(fmt.Sprintf("handling request: %s", body)) // The AdmissionReview that was sent to the webhook requestedAdmissionReview := v1beta1.AdmissionReview{} // The AdmissionReview that will be returned responseAdmissionReview := v1beta1.AdmissionReview{} deserializer := codecs.UniversalDeserializer() if _, _, err := deserializer.Decode(body, nil, &requestedAdmissionReview); err != nil { klog.Error(err) responseAdmissionReview.Response = toAdmissionResponse(err) } else { // pass to admitFunc responseAdmissionReview.Response = admit(requestedAdmissionReview) } // Return the same UID responseAdmissionReview.Response.UID = requestedAdmissionReview.Request.UID klog.V(2).Info(fmt.Sprintf("sending response: %v", responseAdmissionReview.Response)) respBytes, err := json.Marshal(responseAdmissionReview) if err != nil { klog.Error(err) } if _, err := w.Write(respBytes); err != nil { klog.Error(err) } } func serveAlwaysDeny(w http.ResponseWriter, r *http.Request) { serve(w, r, alwaysDeny) } func serveAddLabel(w http.ResponseWriter, r *http.Request) { serve(w, r, addLabel) } func servePods(w http.ResponseWriter, r *http.Request) { serve(w, r, admitPods) } func serveAttachingPods(w http.ResponseWriter, r *http.Request) { serve(w, r, denySpecificAttachment) } func serveMutatePods(w http.ResponseWriter, r *http.Request) { serve(w, r, mutatePods) } func serveConfigmaps(w http.ResponseWriter, r *http.Request) { serve(w, r, admitConfigMaps) } func serveMutateConfigmaps(w http.ResponseWriter, r *http.Request) { serve(w, r, mutateConfigmaps) } func serveCustomResource(w http.ResponseWriter, r *http.Request) { serve(w, r, admitCustomResource) } func serveMutateCustomResource(w http.ResponseWriter, r *http.Request) { serve(w, r, mutateCustomResource) } func serveCRD(w http.ResponseWriter, r *http.Request) { serve(w, r, admitCRD) } func main() { var config Config config.addFlags() flag.Parse() http.HandleFunc("/always-deny", serveAlwaysDeny) http.HandleFunc("/add-label", serveAddLabel) http.HandleFunc("/pods", servePods) http.HandleFunc("/pods/attach", serveAttachingPods) http.HandleFunc("/mutating-pods", serveMutatePods) http.HandleFunc("/configmaps", serveConfigmaps) http.HandleFunc("/mutating-configmaps", serveMutateConfigmaps) http.HandleFunc("/custom-resource", serveCustomResource) http.HandleFunc("/mutating-custom-resource", serveMutateCustomResource) http.HandleFunc("/crd", serveCRD) server := &http.Server{ Addr: ":443", TLSConfig: configTLS(config), } server.ListenAndServeTLS("", "") }
Dynamic configuration of admission webhooks
You can go through the ValidatingWebhookConfiguration or MutatingWebhookConfiguration Dynamic configuration of which resources are restricted by the entry webhooks.
Specific examples are as follows:
apiVersion: admissionregistration.k8s.io/v1beta1 kind: ValidatingWebhookConfiguration metadata: name: <name of this configuration object> webhooks: - name: <webhook name, e.g., pod-policy.example.io> rules: - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods scope: "Namespaced" clientConfig: service: namespace: <namespace of the front-end service> name: <name of the front-end service> caBundle: <pem encoded ca cert that signs the server cert used by the webhook> admissionReviewVersions: - v1beta1 timeoutSeconds: 1
summary
Finally, we summarize the advantages of webhook Admission:
- Web hook can dynamically extend Admission capabilities to meet the needs of custom customers
- Without restarting API Server, you can hot-load webhook admission by creating webhook configuration