{"id":11663,"date":"2025-10-19T14:10:27","date_gmt":"2025-10-19T14:10:27","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=11663"},"modified":"2025-10-19T14:10:27","modified_gmt":"2025-10-19T14:10:27","slug":"webhooks-in-kubernetes","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/webhooks-in-kubernetes\/","title":{"rendered":"Webhooks in Kubernetes"},"content":{"rendered":"<p>Webhooks are HTTP callbacks triggered by the Kubernetes API server during resource operations.<\/p>\n<p>There are two main types<\/p>\n<ul>\n<li>Mutating Webhook: Modify or inject fields into a resource<\/li>\n<li>Validating Webook: Accept or reject a resource based upon logic<\/li>\n<\/ul>\n<p>A validating webhook configuration<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\napiVersion: admissionregistration.k8s.io\/v1\r\nkind: ValidatingWebhookConfiguration\r\nmetadata:\r\n  name: validate-pods.k8s.io\r\nwebhooks:\r\n  - name: podcheck.k8s.io\r\n    rules:\r\n      - apiGroups: &#x5B;&quot;&quot;]\r\n        apiVersions: &#x5B;&quot;v1&quot;]\r\n        operations: &#x5B;&quot;CREATE&quot;]\r\n        resources: &#x5B;&quot;pods&quot;]\r\n    clientConfig:\r\n      service:\r\n        name: pod-validator\r\n        namespace: default\r\n        path: &quot;\/validate&quot;\r\n      caBundle: &lt;base64-ca&gt;\r\n    admissionReviewVersions: &#x5B;&quot;v1&quot;]\r\n    sideEffects: None\r\n<\/pre>\n<p>Essentially k8s web hooks give us the opportunity to intercept k8s API requests such as CREATE, UPDATE or DELETE. Using webhooks we can accept of reject requests without modifying the k8s object.<\/p>\n<p>In the example YAML above, we&#8217;re going to intercept CREATE calls for pods. This is a <em>validate-pods.k8s.io<\/em> or validating web hook, which is non-mutating and can reject requests but not modify them. The name of the web hook is <em>podcheck.k8s.io<\/em> and then we have the rules, which we&#8217;ve already touched on. Then we have the <em>clientConfig<\/em> which will use our <em>pod-validator<\/em> service in the default namespace and the path <em>\/validate<\/em>. For example this would mean a service is accessible via https:\/\/pod-validator.default.svc\/validate. The <em>sideEffects<\/em> of <em>None<\/em> means this webhook doesn&#8217;t write to external systems, hence is safe for retries.<\/p>\n<p>The webhook server must expose an HTTPS endpoint which access AdmissionReview requests and should return a response to denote whether the operation can proceed.<\/p>\n<p>The AdmissionReview request will look similar to this for a pod CREATE<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n{\r\n  &quot;apiVersion&quot;: &quot;admission.k8s.io\/v1&quot;,\r\n  &quot;kind&quot;: &quot;AdmissionReview&quot;,\r\n  &quot;request&quot;: {\r\n    &quot;uid&quot;: &quot;1234abcd-5678-efgh-ijkl-9012mnopqrst&quot;,\r\n    &quot;kind&quot;: {\r\n      &quot;group&quot;: &quot;&quot;,\r\n      &quot;version&quot;: &quot;v1&quot;,\r\n      &quot;kind&quot;: &quot;Pod&quot;\r\n    },\r\n    &quot;resource&quot;: {\r\n      &quot;group&quot;: &quot;&quot;,\r\n      &quot;version&quot;: &quot;v1&quot;,\r\n      &quot;resource&quot;: &quot;pods&quot;\r\n    },\r\n    &quot;requestKind&quot;: {\r\n      &quot;group&quot;: &quot;&quot;,\r\n      &quot;version&quot;: &quot;v1&quot;,\r\n      &quot;kind&quot;: &quot;Pod&quot;\r\n    },\r\n    &quot;requestResource&quot;: {\r\n      &quot;group&quot;: &quot;&quot;,\r\n      &quot;version&quot;: &quot;v1&quot;,\r\n      &quot;resource&quot;: &quot;pods&quot;\r\n    },\r\n    &quot;name&quot;: null,\r\n    &quot;namespace&quot;: &quot;default&quot;,\r\n    &quot;operation&quot;: &quot;CREATE&quot;,\r\n    &quot;userInfo&quot;: {\r\n      &quot;username&quot;: &quot;system:serviceaccount:default:deployer&quot;,\r\n      &quot;uid&quot;: &quot;abc123&quot;,\r\n      &quot;groups&quot;: &#x5B;\r\n        &quot;system:serviceaccounts&quot;,\r\n        &quot;system:authenticated&quot;\r\n      ]\r\n    },\r\n    &quot;object&quot;: {\r\n      &quot;apiVersion&quot;: &quot;v1&quot;,\r\n      &quot;kind&quot;: &quot;Pod&quot;,\r\n      &quot;metadata&quot;: {\r\n        &quot;name&quot;: &quot;example-pod&quot;,\r\n        &quot;namespace&quot;: &quot;default&quot;,\r\n        &quot;labels&quot;: {\r\n          &quot;app&quot;: &quot;demo&quot;\r\n        }\r\n      },\r\n      &quot;spec&quot;: {\r\n        &quot;containers&quot;: &#x5B;\r\n          {\r\n            &quot;name&quot;: &quot;nginx&quot;,\r\n            &quot;image&quot;: &quot;nginx:1.21&quot;,\r\n            &quot;resources&quot;: {\r\n              &quot;limits&quot;: {\r\n                &quot;cpu&quot;: &quot;500m&quot;,\r\n                &quot;memory&quot;: &quot;128Mi&quot;\r\n              }\r\n            }\r\n          }\r\n        ]\r\n      }\r\n    },\r\n    &quot;oldObject&quot;: null,\r\n    &quot;dryRun&quot;: false\r\n  }\r\n}\r\n<\/pre>\n<p>A response will look something like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n{\r\n  &quot;apiVersion&quot;: &quot;admission.k8s.io\/v1&quot;,\r\n  &quot;kind&quot;: &quot;AdmissionReview&quot;,\r\n  &quot;response&quot;: {\r\n    &quot;uid&quot;: &quot;1234abcd-5678-efgh-ijkl-9012mnopqrst&quot;,\r\n    &quot;allowed&quot;: true,\r\n    &quot;status&quot;: {\r\n      &quot;code&quot;: 200,\r\n      &quot;message&quot;: &quot;Pod validated successfully&quot;\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<p>The <em>allowed<\/em> field can just be sent to false which minimal response like the one below<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&quot;allowed&quot;: false,\r\n&quot;status&quot;: {\r\n  &quot;code&quot;: 400,\r\n  &quot;message&quot;: &quot;Missing required label: team&quot;\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Webhooks are HTTP callbacks triggered by the Kubernetes API server during resource operations. There are two main types Mutating Webhook: Modify or inject fields into a resource Validating Webook: Accept or reject a resource based upon logic A validating webhook configuration apiVersion: admissionregistration.k8s.io\/v1 kind: ValidatingWebhookConfiguration metadata: name: validate-pods.k8s.io webhooks: &#8211; name: podcheck.k8s.io rules: &#8211; apiGroups: [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[314],"tags":[],"class_list":["post-11663","post","type-post","status-publish","format-standard","hentry","category-kubernetes"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11663","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=11663"}],"version-history":[{"count":3,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11663\/revisions"}],"predecessor-version":[{"id":11954,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11663\/revisions\/11954"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=11663"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=11663"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=11663"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}