<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Alessandro Marrella - kubernetes</title>
    <link rel="self" type="application/atom+xml" href="https://alessandromarrella.com/tags/kubernetes/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://alessandromarrella.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2020-02-09T00:00:00+00:00</updated>
    <id>https://alessandromarrella.com/tags/kubernetes/atom.xml</id>
    <entry xml:lang="en">
        <title>Kubernetes Webhooks in Haskell and Dhall</title>
        <published>2020-02-09T00:00:00+00:00</published>
        <updated>2020-02-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Alessandro Marrella
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://alessandromarrella.com/feed/posts/k8s-webhooks-in-haskell-and-dhall/"/>
        <id>https://alessandromarrella.com/feed/posts/k8s-webhooks-in-haskell-and-dhall/</id>
        <content type="html" xml:base="https://alessandromarrella.com/feed/posts/k8s-webhooks-in-haskell-and-dhall/">&lt;p&gt;I spent the past few weeks fighting with Kubernetes &lt;a href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;reference&#x2F;access-authn-authz&#x2F;admission-controllers&#x2F;&quot;&gt;Admission Controllers&lt;&#x2F;a&gt; (also known as Mutating&#x2F;Validating Webhooks). &lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Admission controllers are a quite powerful tool, that allow intercepting requests to the Kubernetes API Server before an object is persisted, and perform custom validations or mutations on it. &lt;&#x2F;p&gt;
&lt;p&gt;There are two main components to an admission controller:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;em&gt;webhook&lt;&#x2F;em&gt; exposed over HTTPS which accepts an &lt;code&gt;AdmissionReviewRequest&lt;&#x2F;code&gt; and returns an &lt;code&gt;AdmissionReviewResponse&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;em&gt;configuration&lt;&#x2F;em&gt; entry of type &lt;code&gt;MutatingWebhookConfiguration&lt;&#x2F;code&gt; or &lt;code&gt;ValidatingWebhookConfiguration&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In this post, I will present the &lt;a href=&quot;https:&#x2F;&#x2F;hackage.haskell.org&#x2F;package&#x2F;kubernetes-webhook-haskell&quot;&gt;kubernetes-webhook-haskell&lt;&#x2F;a&gt; library, which is used to create the webhook, and a &lt;code&gt;dhall&lt;&#x2F;code&gt; template that helps with the configuration and tls certificates. Many tutorials I found online show how to do this with a bash script, here we take a more declarative approach using &lt;a href=&quot;https:&#x2F;&#x2F;cert-manager.io&quot;&gt;cert-manager&lt;&#x2F;a&gt;. &lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to-write-a-kubernetes-webhook-in-haskell&quot;&gt;How to write a Kubernetes Webhook in Haskell&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; href=&quot;#how-to-write-a-kubernetes-webhook-in-haskell&quot; hidden=&quot;&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This is a step by step explanation on how to write a webhook in Haskell. If you are familiar with Haskell, and servant, you can skip this section and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;EarnestResearch&#x2F;kubernetes-webhook-haskell#kubernetes-webhook-haskell&quot;&gt;look at the example&lt;&#x2F;a&gt; instead.&lt;&#x2F;p&gt;
&lt;p&gt;First of all, &lt;em&gt;set up a project&lt;&#x2F;em&gt; using your favorite build tool, adding &lt;code&gt;kubernetes-webhook-haskell&lt;&#x2F;code&gt; as a dependency.&lt;&#x2F;p&gt;
&lt;p&gt;Second, you need to &lt;em&gt;create an endpoint&lt;&#x2F;em&gt; where you will be receiving the requests. In &lt;code&gt;servant&lt;&#x2F;code&gt;, this looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;API &lt;&#x2F;span&gt;&lt;span&gt;=
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- &#x2F;mutate
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mutate&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; :&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;ReqBody&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;AdmissionReviewRequest &lt;&#x2F;span&gt;&lt;span&gt;:&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Post&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;AdmissionReviewResponse
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Third, you need to &lt;em&gt;set up the server so that it runs on https&lt;&#x2F;em&gt; (kubernetes only allows https for webhooks), with &lt;code&gt;warp-tls&lt;&#x2F;code&gt; you can do something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;:: IO &lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;main = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tlsOpts = tlsSettings &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;certs&#x2F;tls.crt&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;certs&#x2F;tls.key&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      warpOpts = setPort &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8080&lt;&#x2F;span&gt;&lt;span&gt; defaultSettings
&lt;&#x2F;span&gt;&lt;span&gt;  runTLS tlsOpts warpOpts app
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you will be using the template provided in the section below, we will load the certificates there.&lt;&#x2F;p&gt;
&lt;p&gt;Fourth, you can &lt;em&gt;write the webhook logic&lt;&#x2F;em&gt;. Depending on whether you are writing a validating or a mutating webhook, the library exposes two different functions: &lt;code&gt;mutatingWebhook&lt;&#x2F;code&gt; and &lt;code&gt;validatingWebhook&lt;&#x2F;code&gt;. The logic is similar for both, you parse a request, write a handler for it returning either an error (of type &lt;code&gt;Status&lt;&#x2F;code&gt;) or a &lt;code&gt;Allowed&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;Patch&lt;&#x2F;code&gt; (see http:&#x2F;&#x2F;jsonpatch.com&#x2F; for information on how to write the patch).&lt;&#x2F;p&gt;
&lt;p&gt;For example, if you want to write a mutating webhook that adds a toleration to your pods, you should define the Toleration type:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Toleration
&lt;&#x2F;span&gt;&lt;span&gt;  = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Toleration
&lt;&#x2F;span&gt;&lt;span&gt;      { effect :: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Maybe TolerationEffect&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;:: Maybe Text&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;operator &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;:: Maybe TolerationOperator&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;tolerationSeconds &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;:: Maybe Integer&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;:: Maybe Text
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;deriving&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Generic&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ToJSON&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;TolerationEffect &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;NoSchedule &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;PreferNoSchedule &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;NoExecute &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;deriving&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Generic&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ToJSON&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;TolerationOperator &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Exists &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Equal &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;deriving&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Generic&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ToJSON&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and then your patch can look like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;patch &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;:: W&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;Patch
&lt;&#x2F;span&gt;&lt;span&gt;patch =
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;W&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Patch
&lt;&#x2F;span&gt;&lt;span&gt;    [ 
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;W&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;PatchOperation
&lt;&#x2F;span&gt;&lt;span&gt;        { op = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;W&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Add&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;          path = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;spec&#x2F;tolerations&#x2F;-&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;          from = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Nothing&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;          value = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Just &lt;&#x2F;span&gt;&lt;span&gt;$ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;.toJSON toleration
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    ]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;where 
&lt;&#x2F;span&gt;&lt;span&gt;    toleration = 
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Toleration
&lt;&#x2F;span&gt;&lt;span&gt;        { effect = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Just NoSchedule&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;          key = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Just &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;          operator = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Just Equal&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;          tolerationSeconds = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Nothing&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;          value = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Nothing
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then your patch in the &lt;code&gt;mutatingWebhook&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;mutate &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;:: AdmissionReviewRequest -&amp;gt; AdmissionReviewResponse
&lt;&#x2F;span&gt;&lt;span&gt;mutate = mutatingWebhook req (\_ -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Right&lt;&#x2F;span&gt;&lt;span&gt; patch)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And that&#x27;s it! Compile and create a docker image, and jump to the next section.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to-deploy-the-kubernetes-webhook-using-dhall&quot;&gt;How to deploy the Kubernetes Webhook using Dhall&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; href=&quot;#how-to-deploy-the-kubernetes-webhook-using-dhall&quot; hidden=&quot;&quot;&gt;#&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Regardless of the fact that you created the webhook with the library above or not, this part explains how to deploy a webhook to Kubernetes by using an opinionated Dhall template.&lt;&#x2F;p&gt;
&lt;p&gt;Dhall is a configuration language aimed at writing maintainable configuration files. It&#x27;s a great language to write infrastructure configuration in, with features such as: &lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;(safe) imports&lt;&#x2F;li&gt;
&lt;li&gt;functions&lt;&#x2F;li&gt;
&lt;li&gt;types&lt;&#x2F;li&gt;
&lt;li&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;See &lt;a href=&quot;https:&#x2F;&#x2F;dhall-lang.org&quot;&gt;dhall-lang.org&lt;&#x2F;a&gt; for more information about the language.&lt;&#x2F;p&gt;
&lt;p&gt;As a &lt;em&gt;pre-requisite&lt;&#x2F;em&gt; for this part, you need to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Install &lt;a href=&quot;https:&#x2F;&#x2F;cert-manager.io&quot;&gt;cert-manager&lt;&#x2F;a&gt; in your cluster. This has been tested with cert-manager &lt;code&gt;v0.13.0&lt;&#x2F;code&gt; with the ca-injector enabled.&lt;&#x2F;li&gt;
&lt;li&gt;Install &lt;a href=&quot;https:&#x2F;&#x2F;dhall-lang.org&quot;&gt;dhall-to-yaml&lt;&#x2F;a&gt; on your laptop or in your continuous deployment &#x2F; gitops. This has been tested with dhall-to-yaml &lt;code&gt;v1.6.1&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Then, &lt;em&gt;add a custom label&lt;&#x2F;em&gt; to the namespaces you want to apply the webhook to:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;span&gt; label namespace my-namespace my-webhook=enabled
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Deploying a webhook now is as easy as replacing the values in this example with yours:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- webhook.dhall
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; k8s = 
&lt;&#x2F;span&gt;&lt;span&gt;    https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;dhall-lang&#x2F;dhall-kubernetes&#x2F;6a47bd50c4d3984a13570ea62382a3ad4a9919a4&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1.14&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;package.dhall
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Webhook &lt;&#x2F;span&gt;&lt;span&gt;= 
&lt;&#x2F;span&gt;&lt;span&gt;    https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;EarnestResearch&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;dhall-packages&#x2F;v0.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11.1&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;kubernetes&#x2F;webhook&#x2F;package.dhall
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; config =
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Webhook&lt;&#x2F;span&gt;&lt;span&gt;::{
&lt;&#x2F;span&gt;&lt;span&gt;      , imageName = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;docker&#x2F;whalesay&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- replace with your webhook docker image
&lt;&#x2F;span&gt;&lt;span&gt;      , name = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;my-mutating-webhook&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- replace with a meaningful name
&lt;&#x2F;span&gt;&lt;span&gt;      , namespace = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- replace with the namespace where you want to deploy it
&lt;&#x2F;span&gt;&lt;span&gt;      , path = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mutate&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- replace with the path where the webhook is exposed
&lt;&#x2F;span&gt;&lt;span&gt;      , port = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8080 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;--replace with the port where the webhook is exposed
&lt;&#x2F;span&gt;&lt;span&gt;      , rules = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- replace with the rules you care about
&lt;&#x2F;span&gt;&lt;span&gt;        [ k8s.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;RuleWithOperations&lt;&#x2F;span&gt;&lt;span&gt;::{
&lt;&#x2F;span&gt;&lt;span&gt;          , operations = [ &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CREATE&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;UPDATE&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; ]
&lt;&#x2F;span&gt;&lt;span&gt;          , apiGroups = [ &amp;quot;&amp;quot; ]
&lt;&#x2F;span&gt;&lt;span&gt;          , apiVersions = [ &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;v1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; ]
&lt;&#x2F;span&gt;&lt;span&gt;          , resources = [ &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;pods&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; ]
&lt;&#x2F;span&gt;&lt;span&gt;          }
&lt;&#x2F;span&gt;&lt;span&gt;        ]
&lt;&#x2F;span&gt;&lt;span&gt;      , namespaceSelector = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt; k8s.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;LabelSelector&lt;&#x2F;span&gt;&lt;span&gt;::{
&lt;&#x2F;span&gt;&lt;span&gt;        , matchLabels = toMap { my-webhook = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;enabled&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- replace with the label you used for the namespace
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;Webhook&lt;&#x2F;span&gt;&lt;span&gt;.renderMutatingWebhook config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- or Webhook.renderValidatingWebhook 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once the file is ready, run &lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;echo .&#x2F;webhook.dhall | dhall-to-yaml --omit-empty | kubectl apply -n default -f -
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The webhook will be installed and ready to use, with all the certificates loaded.&lt;&#x2F;p&gt;
</content>
    </entry>
</feed>