{"id":19730883,"url":"https://github.com/kelseyhightower/denyenv-validating-admission-webhook","last_synced_at":"2025-04-30T01:33:40.216Z","repository":{"id":65979003,"uuid":"120789525","full_name":"kelseyhightower/denyenv-validating-admission-webhook","owner":"kelseyhightower","description":"An Kubernetes validating admission webhook that rejects pods that use environment variables.","archived":false,"fork":false,"pushed_at":"2019-01-31T13:40:23.000Z","size":8,"stargazers_count":155,"open_issues_count":5,"forks_count":25,"subscribers_count":4,"default_branch":"master","last_synced_at":"2023-11-07T17:02:28.511Z","etag":null,"topics":["faas","gcp-cloud-functions","kubernetes","serverless"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kelseyhightower.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-08T16:50:15.000Z","updated_at":"2023-09-08T17:36:23.000Z","dependencies_parsed_at":"2023-02-19T18:46:07.783Z","dependency_job_id":null,"html_url":"https://github.com/kelseyhightower/denyenv-validating-admission-webhook","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelseyhightower%2Fdenyenv-validating-admission-webhook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelseyhightower%2Fdenyenv-validating-admission-webhook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelseyhightower%2Fdenyenv-validating-admission-webhook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelseyhightower%2Fdenyenv-validating-admission-webhook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kelseyhightower","download_url":"https://codeload.github.com/kelseyhightower/denyenv-validating-admission-webhook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224193298,"owners_count":17271279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["faas","gcp-cloud-functions","kubernetes","serverless"],"created_at":"2024-11-12T00:18:19.097Z","updated_at":"2024-11-12T00:18:19.663Z","avatar_url":"https://github.com/kelseyhightower.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Getting Started with Kubernetes Validating Admission Webhooks the FaaS Way\n\nKubernetes is a platform for running and managing application containers and has slowly evolved into a platform for building platforms, largely thanks to its extensible API. Kubernetes has many extension points including extensions that enable you to define [custom resource types](https://kubernetes.io/docs/concepts/api-extension/custom-resources), [cloud provider](https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller) and [container runtime integrations](https://github.com/kubernetes/community/blob/master/contributors/devel/container-runtime-interface.md).\n\nAnother, less well known, set of extension points are the admission controllers. An admission controller is a piece of code that intercepts requests to the Kubernetes API prior to persistence of the object, but after the request is authenticated and authorized. Most admission controllers are built into Kubernetes and cover a range of functionality.\n\nTo understand how admission controllers work you need to see them in action. Take the [namespace exists admission controller](https://kubernetes.io/docs/admin/admission-controllers/#namespaceexists) for example, it rejects all requests that attempt to create resources in a namespace that does not exist.\n\nIf you were to list the active namespaces available to a new Kubernetes install you would see two or three namespaces including the `default` and `kube-system` namespaces. The `kube-system` namespace is where things like [Kubernetes DNS](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service) and the [Kubernetes Dashboard](https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/) live.\n\n```\nkubectl get ns\n```\n\noutput:\n\n```\nNAME          STATUS    AGE\ndefault       Active    3m\nkube-public   Active    3m\nkube-system   Active    3m\n```\n\nIf you tried to create a deployment in a namespace that did not exist you would get an error because the `namespace exists` admission controller would reject it.\n\n```\nkubectl run nginx --image nginx --namespace does-not-exist\n```\n\noutput:\n\n```\nError from server (NotFound): namespaces \"does-not-exist\" not found\n```\n\nWith a basic understanding of how admission controllers work it's time to take a look at the newest admission controller, the [validating admission webhook](https://kubernetes.io/docs/admin/admission-controllers/#validatingadmissionwebhook-alpha-in-18-beta-in-19). As it names implies, the validating admission webhook allows you to intercept and validate requests to the Kubernetes API using an external webhook, but not mutate them. That last point is critical; because validating admission webhooks can't mutate resources it's safe to run them in parallel, and quickly reject a request if any of the webhooks fail.\n\nBefore you can use them you'll need access to a Kubernetes cluster.\n\n## Kubernetes the Easy Way\n\nBefore you can use validating admission webhooks you need access to a Kubernetes cluster.\n\nThere are many ways to provision a Kubernetes cluster, but I'm going to assume you want me to tell you exactly what to do so we can get back to building a validating admission webhook. This is where I point you to [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine) and swear it's not a vendor pitch. While I'm recommending GKE, everything should work on [minikube](https://kubernetes.io/docs/getting-started-guides/minikube) or [Docker support for Kubernetes](https://www.docker.com/kubernetes).\n\nIf you've chosen to follow along with GKE, run the following commands and wait for them to finish.\n\nFirst create a 1.9.2+ Kubernetes cluster. We are going to spin a 1 node cluster to help save you some cash, and lighten the blow those bitcoin crashes are taking on your wallet.\n\nUse the `gcloud` command to create the `k0` Kubernetes cluster:\n\n```\ngcloud container clusters create k0 \\\n  --cluster-version 1.9.2-gke.1 \\\n  --zone us-central1-a \\\n  --num-nodes 1\n```\n\nWith the `k0` cluster in place it's time to design and build a validating admission webhook.\n\n## How to Write a Validating Admission Webhook\n\nWe are going to write our first validating admission webhook using [nocode](https://github.com/kelseyhightower/nocode).\n\nI'll give you a minute.\n\nThat's right, don't write a single line of code until you determine what rules you plan to use for accepting or rejecting a Kubernetes resource. For our first webhook we are going to keep things simple. We are going to reject all pods that leverage [environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container) for application configuration.\n\nYou can write validating admission webhooks in just about any programming language, except nocode, and deploy it on any platform, including Kubernetes. But remember, the only goal is to validate incoming Kubernetes resources, not build a generic web application. In theory we only need to write a small bit of code to make that happen.\n\n```javascript\nfunction denyenv (req, res) {\n  // Review the Kubernetes Pod resource and reject it if any\n  // of the containers are using environment variables.\n}\n```\n\nGiven the minimual requirements for our validating admission webhook, we are going to skip containers altogether and deploy our webhook using a Function as a Service (FaaS) platform. Also know as Serverless.\n\n### Serverless to the Rescue\n\nWe are going to implement our validating admission webhook using [Node.js](https://nodejs.org) and deploy it to [Google Cloud Functions](https://cloud.google.com/functions).\n\nNow it's time to write the validating admission webhook. Create a directory named `denyenv` and move into it:\n\n```\nmkdir denyenv \u0026\u0026 cd denyenv\n```\n\nNext, save the following code block to a file named `index.js`:\n\n```javascript\n'use strict';\n\nexports.denyenv = function denyenv (req, res) {\n  var admissionRequest = req.body;\n\n  // Get a reference to the pod spec\n  var object = admissionRequest.request.object;\n\n  console.log(`validating the ${object.metadata.name} pod`);\n\n  var admissionResponse = {\n    allowed: false\n  };\n\n  var found = false;\n  for (var container of object.spec.containers) {\n    if (\"env\" in container) {\n      console.log(`${container.name} is using env vars`);\n\n      admissionResponse.status = {\n        status: 'Failure',\n        message: `${container.name} is using env vars`,\n        reason: `${container.name} is using env vars`,\n        code: 402\n      };\n\n      found = true;\n    };\n  };\n\n  if (!found) {\n    admissionResponse.allowed = true;\n  }\n\n  var admissionReview = {\n    response: admissionResponse\n  };\n\n  res.setHeader('Content-Type', 'application/json');\n  res.send(JSON.stringify(admissionReview));\n  res.status(200).end();\n};\n```\n\nRun the following command to create a new function named `denyenv`:\n\n```\ngcloud beta functions deploy denyenv --trigger-http\n```\n\nRetrieve the HTTPS URL that triggers the `denyenv` function as we'll need it later when configuring our Kubernetes cluster to use it.\n\n```\nHTTPS_TRIGGER_URL=$(gcloud beta functions describe denyenv \\\n  --format 'value(httpsTrigger.url)')\n```\n\n## Validating Admission Webhook Configuration\n\nWith the `denyenv` function in place, it’s time to configure the Kubernetes cluster to use it.\n\nStart by generating a validating webhook configuration and submitting it to the Kubernetes API:\n\n```\ncat \u003c\u003cEOF | kubectl apply -f -\napiVersion: admissionregistration.k8s.io/v1beta1\nkind: ValidatingWebhookConfiguration\nmetadata:\n  name: denyenv\nwebHooks:\n  - name: denyenv.hightowerlabs.com\n    rules:\n      - apiGroups:\n          - \"\"\n        apiVersions:\n          - v1\n        operations:\n          - CREATE\n        resources:\n          - pods\n    failurePolicy: Fail\n    clientConfig:\n      url: \"${HTTPS_TRIGGER_URL}\"\nEOF\n```\n\noutput:\n\n```\nvalidatingwebhookconfiguration \"denyenv\" created\n```\n\nAt this point we are all set to start testing the `denyenv` webhook.\n\n## Testing\n\nWith the the `denyenv` validating admission webhook in place we need to ensure that it’s working.\n\nFirst let’s make sure pods without env vars can be deployed to our Kubernetes clusters:\n\n```\nkubectl run nginx --image=nginx\n```\n\noutput:\n\n```\ndeployment \"nginx\" created\n```\n\nList the pods:\n\n```\nkubectl get pods\n```\noutput:\n\n```\nNAME                   READY     STATUS    RESTARTS   AGE\nnginx-8586cf59-qmdm4   1/1       Running   0          25s\n```\n\nIt works. We can review the logs of the `denyenv` cloud function to show that it was indeed called:\n\n```\ngcloud beta functions logs read denyenv\n```\n\noutput:\n\n```\nD      denyenv  wb9bmjb34uyh  2018-02-09 02:06:35.534  Function execution started\nI      denyenv  wb9bmjb34uyh  2018-02-09 02:06:35.542  validating the nginx-8586cf59-qmdm4 pod\nD      denyenv  wb9bmjb34uyh  2018-02-09 02:06:35.545  Function execution took 12 ms, finished with status code: 200\n```\n\nNext we need to ensure our webhook actually does the thing it’s designed to do, which is prevent pods with containers using env vars.\n\n```\nkubectl run nginx-with-env --image=nginx --env=\"PASSWORD=fail\"\n```\n\noutput:\n\n```\ndeployment \"nginx-with-env\" created\n```\n\nList the pods:\n\n```\nkubectl get pods\n```\n\noutput:\n\n```\nNAME                   READY     STATUS    RESTARTS   AGE\nnginx-8586cf59-qmdm4   1/1       Running   0          1m\n```\n\nIts not there. What's going on?\n\nThe best way to determine why the `nginx-with-env` pod is not running is to review the Kubernetes event stream: \n\n```\nkubectl get events\n```\n\noutput:\n\n```\nWarning   FailedCreate  replicaset-controller Error creating: admission webhook \"denyenv.hightowerlabs.com\" denied the request: nginx-with-env is using env vars\n```\n\nLooks like the `nginx-with-env` pod was denied by the `denyenv` admission webhook. We can confirm by fetching the logs for the `denyenv` function.\n\n```\ngcloud beta functions logs read denyenv\n```\n\n```\nI      denyenv  s1ij4wfykerr  2018-02-09 02:09:31.457  validating the nginx-with-env-76498b5b66-nw259 pod\nI      denyenv  s1ij4wfykerr  2018-02-09 02:09:31.459  nginx-with-env is using env vars\nD      denyenv  s1ij4wfykerr  2018-02-09 02:09:31.461  Function execution took 8 ms, finished with status code: 200\n```\n\n## Conclusion\n\nValidating admission webhooks are one of easiest ways of extending Kubernetes with new policy controls. Building and running admission webhooks using a FaaS platform can help streamline the development process, and make it easy to enforce policy across multiple Kubernetes clusters using a single function.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkelseyhightower%2Fdenyenv-validating-admission-webhook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkelseyhightower%2Fdenyenv-validating-admission-webhook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkelseyhightower%2Fdenyenv-validating-admission-webhook/lists"}