<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>validating webhook on Digi Hunch</title><link>https://static.digihunch.com/tag/validating-webhook/</link><description>Recent content in validating webhook on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Wed, 02 Apr 2025 13:02:31 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/validating-webhook/index.xml" rel="self" type="application/rss+xml"/><item><title>Kubernetes Admission Control</title><link>https://static.digihunch.com/2022/01/kubernetes-admission-control/</link><pubDate>Fri, 07 Jan 2022 22:21:00 -0400</pubDate><guid>https://static.digihunch.com/2022/01/kubernetes-admission-control/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-k8s-admin-control.webp" alt="Featured image of post Kubernetes Admission Control" /&gt;&lt;p class="wp-block-paragraph"&gt;This post discusses admission control, and its implementation &amp;#8211; the OPA Gatekeeper. I also discuss Azure Policy as a different Gatekeeper implementation.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="admission-webhooks"&gt;Admission Webhooks&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Admission controller intercepts requests to the Kubernetes API server after the request has been authenticated and authorized, and prior to persistence of the object into etcd store. There are many compiled-in &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#what-does-each-admission-controller-do"&gt;controllers&lt;/a&gt;, which can be turned on and off on the node with the arguments of &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/"&gt;kube-apiserver&lt;/a&gt; process. For example, the &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#imagepolicywebhook"&gt;ImagePolicyWebhook&lt;/a&gt; can be enabled with value ImagePolicyWebhook added to the &amp;#8211;enable-admission-plugins switch. Its configuration can be provided via the &amp;#8211;admission-control-config-file &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/#options"&gt;switch&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition to the compiled-in admission plugins (which must be configured for kube-apiserver process on the node), admission plugins can be developed as extensions and run as webhooks configured at runtime. This allows users to configure webhooks via API access, dynamically without having to restart kube-apiserver process on the Node, which is usually hard to do with managed Kubernetes platforms. They are therefore called Dynamic Admission Control.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can define two types of admission webhooks in dynamic admission control: validating admission webhook, and mutating admission webhook. Their interaction with API server can be illustrated in the diagram below:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="307" src="https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-1024x307.jpeg" alt="" class="wp-image-7733" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-1024x307.jpeg 1024w, https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-300x90.jpeg 300w, https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-768x231.jpeg 768w, https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-1536x461.jpeg 1536w, https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-2048x615.jpeg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The mutating admission hook takes action to change the API request, whereas the validating admission hook accepts or denies the request. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A good example of mutating webhook is Istio&amp;#8217;s sidecar injector. We can view the configuration with this command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get MutatingWebhookConfiguration istio-sidecar-injector -o yaml | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;From the manifest returned, we can see that in this configuration the request is forwarded to istiod service on port 443, at path /inject for processing. We can also see some matching rules to find the target Pod creation API request.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Validating webhook can be display with the following call:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get ValidatingWebhookConfiguration&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The output of validating webhook is a yes or no decision. We usually use validating webhook in conjunction with a policy engine to decide whether the request should be accepted or denied.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="open-policy-agent"&gt;Open Policy Agent&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Open Policy Agent (OPA) is an open-source general-purpose policy engine that applies policies written in &lt;a href="https://www.openpolicyagent.org/docs/latest/policy-language/"&gt;Rego language&lt;/a&gt; to ingested JSON document and returns a result. It is usually integrated with system which requires a policy engine. For example, &lt;a href="https://kyverno.io/"&gt;Kyverno&lt;/a&gt; is a policy engine designed for Kubernetes. &lt;a href="https://blog.styra.com/blog/authorize-better-istio-traffic-policies-with-opa-styra-das"&gt;Styra&lt;/a&gt; (one of the OPA contributors) develops policy engines to integrate with Istio&amp;#8217;s authorization policy. They have &lt;a href="https://academy.styra.com/"&gt;online courses&lt;/a&gt; on &lt;a href="https://academy.styra.com/courses/opa-rego"&gt;OPA policy authoring&lt;/a&gt; and &lt;a href="https://academy.styra.com/courses/microservice"&gt;microservice authorization&lt;/a&gt; with their product.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;OPA is build to be a general-purpose, unified way of solving policy and authorization problem. With microservice authorization, the activities includes decision making (determine action based on input, aka Policy Decision Point, PDP), and decision enforcement (issue 400 code or 200 code depending on decision, aka Policy Enforcement Point, PEP). OPA is introduced to decouple these two activities. OPA&amp;#8217;s input is a JSON payload and it uses Policy in Rego language to come to decision.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The team that developers Open Policy Agent also created their controller (with OPA as the core component) to run validating web hook and mutating web hook. The original version is OPA-Kubernetes that uses kube-mgmt. This original version is also dubbed Gatekeeper v1.0. When OPA starts, the kube-mgmt sidecar container will load Kubernetes Namespace and Ingress objects into OPA. You can configure the sidecar to load any kind of Kubernetes object into OPA. The sidecar establishes watches on the Kubernetes API server so that OPA has access to an eventually consistent cache of Kubernetes objects. It has gone through a couple of major version changes as summarized in &lt;a href="https://kubernetes.io/blog/2019/08/06/opa-gatekeeper-policy-and-governance-for-kubernetes/#evolution"&gt;this&lt;/a&gt; section. As of today, when we deploy Gatekeeper we should use version 3.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="gatekeeper-v3"&gt;Gatekeeper v3&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Currently, Gatekeeper v3 is the most popular choice for Kubernetes Policy Controller. The diagram bellow illustrate how Gatekeeper integrates with Kubernetes API server.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="943" height="478" src="https://static.digihunch.com/wp-content/uploads/2022/02/apiserver.png" alt="" class="wp-image-3481"/&gt;&lt;figcaption class="wp-element-caption"&gt;Gatekeeper and Kubernetes&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can follow &lt;a href="https://open-policy-agent.github.io/gatekeeper/website/docs/install/"&gt;this&lt;/a&gt; guide to install Gatekeeper but the key step is as simple as to apply the correct version of manifest. Alternatively it can be installed &lt;a href="https://open-policy-agent.github.io/gatekeeper/website/docs/install#deploying-via-helm"&gt;using Helm&lt;/a&gt;. After the installation, we should see a Service named &lt;em&gt;gatekeeper-webhook-service&lt;/em&gt; in the &lt;em&gt;gatekeeper-system&lt;/em&gt; namespace. We can also inspect the newly created validationg web hook configuration&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;k get validatingwebhookconfiguration gatekeeper-validating-webhook-configuration -o yaml | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The result indicates that the configuration forwards incoming manifests to the &lt;em&gt;gatekeeper-webhook-service&lt;/em&gt; web service at the path /v1/admin for validation, and then at /v1/admitlabel for labelling. The configuration also stores rules as matching criteria.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can smoke test Gatekeeper v3, with the basic example in its &lt;a href="https://github.com/open-policy-agent/gatekeeper/tree/master/example"&gt;directory&lt;/a&gt;. Apply the template, constraint and then the manifests in resources. The pod creation will fail with an error like:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Error from server &lt;span style="color:#f92672"&gt;([&lt;/span&gt;pod-must-have-gk&lt;span style="color:#f92672"&gt;]&lt;/span&gt; you must provide labels: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;gatekeeper&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;})&lt;/span&gt;: error when creating &lt;span style="color:#e6db74"&gt;&amp;#34;resources/bad_pod_namespaceselector.yaml&amp;#34;&lt;/span&gt;: admission webhook &lt;span style="color:#e6db74"&gt;&amp;#34;validation.gatekeeper.sh&amp;#34;&lt;/span&gt; denied the request: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;pod-must-have-gk&lt;span style="color:#f92672"&gt;]&lt;/span&gt; you must provide labels: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;gatekeeper&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The gatekeeper &lt;a href="https://open-policy-agent.github.io/gatekeeper/website/docs/howto"&gt;document&lt;/a&gt; also covers the details of using ConstraintTemplate and Constraints. However, Writing your own a policy in Rego still takes time and we want to piggyback on the community for commonly used policies. &lt;a href="https://github.com/open-policy-agent"&gt;OPA&lt;/a&gt;&amp;#8216;s &lt;a href="https://github.com/open-policy-agent/gatekeeper-library"&gt;gatekeeper-library&lt;/a&gt; projects keeps a handful of those in its &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library"&gt;library&lt;/a&gt; directory. We can test the &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/pod-security-policy/privileged-containers"&gt;privileged container&lt;/a&gt; example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd gatekeeper-library/library/pod-security-policy/privileged-containers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kustomize build . | kubectl apply -f -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;constrainttemplate.templates.gatekeeper.sh/k8spspprivilegedcontainer created&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f samples/psp-privileged-container/example_disallowed.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pod/nginx-privileged-disallowed created&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl delete -f samples/psp-privileged-container/example_disallowed.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pod &lt;span style="color:#e6db74"&gt;&amp;#34;nginx-privileged-disallowed&amp;#34;&lt;/span&gt; deleted&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f samples/psp-privileged-container/constraint.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container created&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f samples/psp-privileged-container/example_disallowed.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Error from server &lt;span style="color:#f92672"&gt;([&lt;/span&gt;psp-privileged-container&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Privileged container is not allowed: nginx, securityContext: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;privileged&amp;#34;&lt;/span&gt;: true&lt;span style="color:#f92672"&gt;})&lt;/span&gt;: error when creating &lt;span style="color:#e6db74"&gt;&amp;#34;samples/psp-privileged-container/example_disallowed.yaml&amp;#34;&lt;/span&gt;: admission webhook &lt;span style="color:#e6db74"&gt;&amp;#34;validation.gatekeeper.sh&amp;#34;&lt;/span&gt; denied the request: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;psp-privileged-container&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Privileged container is not allowed: nginx, securityContext: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;privileged&amp;#34;&lt;/span&gt;: true&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Currently the library &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library"&gt;directory&lt;/a&gt; contains two sub-directories, general and pod-scurity-policy. The latter is to regulate Pod creation, while the former includes more common usecases such as disable node port, enforce https, and enforce probes. This is the place I start with when building a policy.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The policy constraints take effect cluster wide. When we have multiple clusters, we would like a unified place to manage policies. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="azure-policy-with-aks"&gt;Azure Policy with AKS&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We take Azure Policy with AKS as an example to illustrate how public cloud platform can simplify policy management. When building AKS cluster, an &lt;a href="https://docs.microsoft.com/en-us/azure/governance/policy/concepts/policy-for-kubernetes#install-azure-policy-add-on-for-aks"&gt;addon&lt;/a&gt; profile for Azure Policy can be installed. This allows Azure Policy to connect to the AKS cluster. Azure Policy contains many built-in policies definitions (as well as initiative definitions which are groups of related policies). We can simply search by Kubernetes keyword and look for the built-in policies. For example, there is a built-in policy definition &amp;#8220;Kubernetes clusters should not allow container privilege escalation. The definitions (policy or initiative) can be assigned to a resource group with enforcement action set to denied, and with excluded namespaces, as shown in the screenshot below&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1566" height="1056" src="https://static.digihunch.com/wp-content/uploads/2022/02/image-2.png" alt="" class="wp-image-3497"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The assignment can take as long as 10 minutes to push down to the cluster. Then we should be able to confirm by checking the constraint CRDs. We can see this This setup brings a centralized policy management system that can be easily hooked up to multiple clusters.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://ahmedkhamessi.com/img/azurepolicy/azurepolicy.png" alt="Azure Policy and OPA Gatekeeper underlay for AKS"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Other benefits of this architecture includes the ability to report compliance. As per CIS report for Azure AKS recommendation 4.3:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure Policy extends Gatekeeper v3, an admission controller webhook for Open Policy Agent (OPA), to apply at-scale enforcements and safeguards on your clusters in a centralized, consistent manner. It covers many &lt;a href="https://static.digihunch.com/2021/01/basic-kubernetes-resource-object-1-of-2/"&gt;basic resource&lt;/a&gt; &lt;a href="https://static.digihunch.com/2021/02/basic-resource-object-in-kubernetes-2-of-2/"&gt;types&lt;/a&gt; but does not cover any well-known CRDs. Azure Policy makes it possible to manage and report on the compliance state of your Kubernetes clusters from one place.&amp;nbsp;&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Checks with Azure Policy service for policy assignments to the cluster.&lt;/li&gt;&#10;&lt;li&gt;Deploys policy definitions into the cluster as constraint template and constraint custom resources.&lt;/li&gt;&#10;&lt;li&gt;Reports auditing and compliance details back to Azure Policy service.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As of February 2022, AWS EKS doesn&amp;#8217;t seem to have the equivalent of this capability to integrate with a policy management. The only option would be to install Gatekeeper v3 &lt;a href="https://aws.amazon.com/blogs/opensource/using-open-policy-agent-on-amazon-eks/"&gt;yourself&lt;/a&gt; on the cluster, or host it separately. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="bottom-line"&gt;Bottom line&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Admission control should be a standard setup in Kubernetes deployment. When building gatekeeper system on your own, it can be set up separately on a different cluster. When Kubernetes is provided as a platform, it is very helpful for platform operator to manage their tenants. If the tenant is application development team, it also makes sense for them to develop their own policies for the developers in their team.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/12/from-ingress-to-gateway-why-you-need-istio-gateways-on-kubernetes-platforms/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;From Ingress to CRD: why my solution needs Istio Gateways on Kubernetes platforms&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/01/fluxcd-continuous-deployment-with-gitops/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;FluxCD: Continuous Deployment with GitOps&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>