Skip to content

Commit e0919b8

Browse files
developer-guyalexellis
authored andcommitted
Add blog post on Kubernetes webhooks with OpenFaaS
Signed-off-by: Batuhan Apaydın <batuhan.apaydin@trendyol.com> Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
1 parent e923a15 commit e0919b8

File tree

2 files changed

+257
-0
lines changed

2 files changed

+257
-0
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
---
2+
title: "Kubernetes Webhooks made easy with OpenFaaS"
3+
description: "In this post you'll learn how to write Kubernetes Admission webhooks using OpenFaaS functions"
4+
date: 2020-10-27
5+
image: /images/2020-10-27-k8s-validatingwebhook-openfaas/admission-controller-phases.png
6+
categories:
7+
- arkade
8+
- kubectl
9+
- faas-cli
10+
- admissionwebhooks
11+
- validatingadmissionwebhooks
12+
- k8s extensibility
13+
author_staff_member: developer-guy
14+
dark_background: true
15+
---
16+
17+
In this post you'll learn how to write Kubernetes Admission webhooks using OpenFaaS functions
18+
19+
<p align="center">
20+
<img height="128" src="/images/openfaas/kubernetes.png">
21+
</p>
22+
23+
## Introduction to Kubernetes Admission webhooks
24+
Admission webhooks are HTTP callbacks that receive admission requests and do something with them. You can define two types of admission webhooks, validating admission webhook and mutating admission webhook. Mutating admission webhooks are invoked first, and can modify objects sent to the API server to enforce custom defaults. After all object modifications are complete, and after the incoming object is validate by the API server, validating admission webhooks are invoked and can reject requests to enforce custom policies.
25+
26+
Using OpenFaaS in this design, we can focus on our core logic more than designing the microservice itself and simply create application without being worry about how to build and deploy.
27+
28+
## The Scenario
29+
Let's assume, in our company, we have some requirements that we must meet while deploying applications onto the Kubernetes cluster. We need to set some required labels to our Kubernetes manifest. Unless we specify the required labels our request will reject.
30+
31+
So, in order to apply those requirements to the Kubernetes cluster to ensure the best practices, we can use Kubernetes [ValidatingAdmissionWebhook](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#validatingadmissionwebhook) and [OpenFaaS](https://www.openfaas.com) together. Since ValidatingAdmissionWebhooks intercepts requests to the apiserver, OpenFaaS functions includes a little code to check required labels and determines the request either allowed or not.
32+
33+
Webhook Admission Server is just plain http server that adhere to Kubernetes API. For each Pod create request to the apiserver(I said Pod because we specify which kind of resources that we consider while registering our webhook to the apiserver using [ValidatingWebhookConfiguration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#validatingwebhookconfiguration-v1-admissionregistration-k8s-io) resource) the ValidatingAdmissionWebhook sends an admissionReview([API](https://github.com/kubernetes/kubernetes/blob/release-1.19/pkg/apis/admission/types.go) for reference) to the relevant webhook admission server. The webhook admission server gathers information like object, oldobject, and userInfo from admissionReview's AdmissionRequest and sends AdmissionRequest to the serverless function through the OpenFaaS Gateway. The function checks the required labels exist on Pod and determines the request either valid or not and then sends back the AdmissionResponse whose Allowed and Result fields are filled with the admission decision to the webhook admission server then the webhook admission servers sends back a admissionReview to the apiserver.
34+
35+
* Kubernetes API -> Webhook (w/TLS) -> OpenFaaS Gateway (w/HTTP) -> OpenFaaS Function
36+
37+
Supporting TLS for external webhook server is also required because admission is a high security operation. As part of the process, we need to create a TLS certificate signed by the Kubernetes CA to secure the communication between the webhook server and apiserver.
38+
39+
### Prerequisites
40+
##### Arkade
41+
42+
* [arkade](https://get-arkade.dev) is The OpenFaaS community built tool for Kubernetes developers, with arkade you can easily install all necessary cli tools to your host and deploy apps to the cluster.
43+
44+
```sh
45+
$ curl -sLS https://dl.get-arkade.dev | sudo sh
46+
```
47+
48+
##### KinD (Kubernetes in Docker)
49+
50+
* Kubernetes is our recommendation for teams running at scale, but in this demo we will be using [KinD](https://kind.sigs.k8s.io/docs/user/quick-start/) for the sake of simplicity.
51+
52+
```sh
53+
$ arkade get kind
54+
```
55+
56+
##### kubectl
57+
58+
* You can control your cluster using [kubectl](https://github.com/kubernetes/kubectl) CLI.
59+
60+
```sh
61+
$ arkade get kubectl
62+
```
63+
64+
##### faas-cli
65+
66+
* [faas-cli](https://github.com/openfaas/faas-cli) is an official CLI for OpenFaaS , with "faas-cli" you can build and deploy functions easily.
67+
68+
```sh
69+
$ arkade get faas-cli
70+
```
71+
72+
### Setup
73+
74+
### 1. Setup a Kubernetes Cluster with KinD
75+
76+
You can start a Kubernetes cluster with KinD if you don't have one already
77+
78+
```bash
79+
$ arkade get kind
80+
$ kind create cluster
81+
```
82+
83+
### 2. Deploy OpenFaaS to our local Kubernetes Cluster with arkade:
84+
85+
* Install a OpenFaaS
86+
87+
```sh
88+
$ arkade install openfaas
89+
```
90+
91+
Read the output from the installation and run the commands given to you.
92+
93+
You can access them again at any time with `arkade info openfaas`
94+
95+
### 3. Clone the project
96+
97+
* Clone the sample from GitHub
98+
99+
```sh
100+
$ git clone https://github.com/developer-guy/admission-webhook-example-with-openfaas
101+
$ cd admission-webhook-example-with-openfaas
102+
```
103+
104+
* Let's explore the structure of the project.
105+
106+
```
107+
deployment/ --> includes necessary manifests and scripts for the deployment of the project
108+
functions/ --> includes templates and the requiredlabel function itself
109+
Dockerfile --> includes instructions to build an image of the project
110+
build --> automated way to build and push an image of the project
111+
```
112+
113+
### 4. Deploy ValidatingAdmissionWebhook
114+
115+
* We will generate the TLS certificates required for the ValidatingAdmissionWebhook using the following: [Kubernetes TLS Certificates Management](https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/)
116+
117+
```sh
118+
$ cd deployment
119+
$ sh webhook-create-signed-cert.sh
120+
```
121+
122+
* Get the Certificate Authority (CA) from the local cluster
123+
124+
```sh
125+
$ export CA_BUNDLE=$(kubectl config view --minify --flatten -o json | jq -r '.clusters[] | select(.name == "'$(kubectl config current-context)'") | .cluster."certificate-authority-data"')
126+
$ sed -e "s|\${CA_BUNDLE}|${CA_BUNDLE}|g" validatingwebhook.yaml | kubectl apply -f -
127+
$ cd ..
128+
```
129+
130+
* Build the project
131+
132+
```sh
133+
$ export DOCKER_USER="docker-hub-username"
134+
$ ./build
135+
```
136+
137+
Now edit `deployment.yaml` and set 'DOCKER_USER' to the above.
138+
139+
* Deploy it project
140+
141+
```sh
142+
$ cd deployment
143+
$ kubectl apply -f rbac.yaml,service.yaml,deployment.yaml
144+
```
145+
146+
### 5. Build and Deploy OpenFaaS Function (Optional)
147+
148+
* Pull the [golang-middleware](https://github.com/openfaas-incubator/golang-http-template) template from [OpenFaaS Official Template Store](https://github.com/openfaas/store)
149+
150+
```sh
151+
$ faas-cli template store list # check available templates in store
152+
$ faas-cli template store describe golang-middleware # describe the specific template
153+
$ faas-cli template store pull golang-middleware
154+
```
155+
156+
* Create the function
157+
158+
```sh
159+
$ export OPENFAAS_PREFIX=$DOCKER_USER
160+
$ faas-cli new requiredlabel --lang go-middleware
161+
$ cd requiredlabel
162+
$ go mod init requiredlabel
163+
$ # fill the handler.go with the corresponding code
164+
$ go get
165+
```
166+
167+
* Deploy the function
168+
169+
```sh
170+
$ cd functions
171+
$ faas-cli up -f requiredlabel.yml --build-arg GO111MODULE=on # (build-push-deploy) make sure you are using your docker hub username. i.e: devopps
172+
```
173+
174+
* Verify the functions that are working in `openfaas-fn` namespace
175+
176+
```sh
177+
$ kubectl get pods --namespace openfaas-fn
178+
```
179+
180+
### 6. Test the whole workflow
181+
182+
* The purpose of this PoC is that to validate that pods has required `labels`. Which means you must have that labels:
183+
184+
```yaml
185+
app.kubernetes.io/name: sleep
186+
app.kubernetes.io/instance: sleep
187+
app.kubernetes.io/version: "0.1"
188+
app.kubernetes.io/component: dummy
189+
app.kubernetes.io/part-of: admission-webhook-example
190+
app.kubernetes.io/managed-by: kubernetes
191+
```
192+
193+
* Any Pod who have above labels is valid for us.
194+
195+
```sh
196+
`deployment/sleep.yaml` -> Incorrect, not-valid (We should deny this creation request.)
197+
`deployment/sleep-no-validation.yaml` -> Skip-validation (Based on `admission-webhook-example.qikqiak.com/validate: "false"` annotation, we skipped validation.)
198+
`deployment/sleep-with-labels.yaml` -> Correct, valid (We should accept this creation request.)
199+
```
200+
201+
### 7. A way of extend the operation event and function
202+
203+
In this demo, we only consider the Pod create request by specifying _operations_ at the ValidatingWebhookConfiguration's [matching request rules](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-rules) section in the [deployment/validatingwebhook.yaml](https://github.com/developer-guy/admission-webhook-example-with-openfaas/blob/master/deployment/validatingwebhook.yaml) file.
204+
205+
If we want to extend the operations, we can add a new [operation](https://github.com/kubernetes/kubernetes/blob/release-1.19/pkg/apis/admission/types.go#L158) for the Pods like _DELETE_, _UPDATE_, _CONNECT_ etc. By specifying a new operation, now apiserver being started to send a new event for this operation additional to create request.
206+
207+
Now we can specify more than one serverless function for the operation types by checking request operation type. For [example](https://github.com/developer-guy/admission-webhook-example-with-openfaas/blob/master/functions/requiredlabel/handler.go#L109):
208+
209+
```go
210+
switch req.Kind.Kind {
211+
case "Pod":
212+
switch req.Operation {
213+
case v1beta1.Create:
214+
// do something for create operation
215+
case v1beta1.Delete:
216+
// do something for delete operation
217+
}
218+
}
219+
```
220+
221+
Also you can specify function name and namespace that you want to use while deploying the webhook server using these environment variables:
222+
223+
```yaml
224+
env:
225+
- name: FUNCTION_NAME
226+
value: requiredlabel
227+
- name: FUNCTION_NAMESPACE
228+
value: openfaas-fn
229+
```
230+
231+
### Taking it further
232+
233+
* Mutating webhooks
234+
235+
You could take this example and convert it from validating webhooks to mutating webhooks. This is useful when a user wants to upgrade or modify objects that are created, such as adding which user created them, or adding a compulsory memory limit.
236+
237+
* Adding more functions
238+
239+
In the example I used a single function, however, you could register more than one function, so that you can then have a function for validating memory limits, and a separate one for checking that a minimum set of labels are present
240+
241+
### Join the community
242+
243+
Have you got questions, comments, or suggestions? Join the community on [Slack](https://slack.openfaas.io).
244+
245+
Would you like help to set up your OpenFaaS installation, or someone to call when things don't quite go to plan? [Our Premium Subscription plan](https://www.openfaas.com/support/) gives you a say in the project roadmap, a support contact, and access to Enterprise-grade authentication with OIDC.
246+
247+
### Acknowledgements
248+
249+
* Special Thanks to [Alex Ellis](https://twitter.com/alexellisuk) for all guidance and for merging changes into OpenFaaS to better support this workflow.
250+
* Special Thanks to [Furkan Türkal](https://twitter.com/furkanturkaI) for all the support.
251+
252+
### References
253+
254+
* https://medium.com/ibm-cloud/diving-into-kubernetes-mutatingadmissionwebhook-6ef3c5695f74
255+
* https://blog.alexellis.io/get-started-with-openfaas-and-kind/
256+
* https://github.com/morvencao/kube-mutating-webhook-tutorial
257+
* https://github.com/developer-guy/admission-webhook-example-with-openfaas
Loading

0 commit comments

Comments
 (0)