This commit is contained in:
marcel-dempers 2021-04-14 19:04:42 +10:00
parent f3c8f1fb5c
commit e688761141
10 changed files with 274 additions and 62 deletions

View File

@ -37,14 +37,21 @@ After the above, we should have: <br/>
We always start with a `dockerfile` since we need a Go dev environment.
```
FROM golang:1.15-alpine as dev-env
WORKDIR /app
```
Build and run the controller
```
# get dev environment: webhook
cd sourcecode
docker build --target dev-env . -t webhook
docker run -it --rm -p 80:80 --entrypoint bash -v ${HOME}/.kube/:/root/.kube/ -v ${PWD}:/app webhook
docker build . -t webhook
docker run -it --rm -p 80:80 -v ${PWD}:/app webhook sh
```
@ -54,8 +61,8 @@ Let's define our basic main module and a web server
```
go mod init example-webhook
```
Source code:
New file : `main.go`
```
package main
@ -95,7 +102,7 @@ NOTE: In Windows, container networking is not fully supported. Our container exp
Let's exit the container and start with `--net host` so our container can access our kubernetes `kind` cluster
```
docker run -it --rm --net host --entrypoint bash -v ${HOME}/.kube/:/root/.kube/ -v ${PWD}:/app webhook
docker run -it --rm --net host -v ${HOME}/.kube/:/root/.kube/ -v ${PWD}:/app webhook sh
```
We can also test our access to our kubernetes cluster with the config that is mounted in:
@ -293,10 +300,7 @@ var parameters ServerParameters
# start our web server exposing TLS endpoint
err = http.ListenAndServeTLS(":" + strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil)
if err != nil {
panic(err.Error())
}
log.Fatal(http.ListenAndServeTLS(":" + strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil))
```
@ -318,9 +322,37 @@ if err != nil {
<hr/>
Let's built what we have and deploy it to our kubernetes cluster
We will firstly need to add a build step to our `dockerfile` to build the code </br>
And we'll also need to create a smaller runtime layer in our `dockerfile`
Full `dockerfile` :
```
docker build ./sourcecode -f ./sourcecode/dockerfile -t aimvector/example-webhook:v1
FROM golang:1.15-alpine as dev-env
WORKDIR /app
FROM dev-env as build-env
COPY go.mod /go.sum /app/
RUN go mod download
COPY . /app/
RUN CGO_ENABLED=0 go build -o /webhook
FROM alpine:3.10 as runtime
COPY --from=build-env /webhook /usr/local/bin/webhook
RUN chmod +x /usr/local/bin/webhook
ENTRYPOINT ["webhook"]
```
Let's build the container and push it to a registry:
```
docker build . -t aimvector/example-webhook:v1
docker push aimvector/example-webhook:v1
```
@ -359,14 +391,30 @@ kubectl cp example-webhook-756bcb566b-9kxjp:/tmp/request ./mock-request.json
So lets grab the info from the admission request, so we can do something with it
```
# HandleMutate()
fmt.Printf("Type: %v \t Event: %v \t Name: %v \n",
```
//dependencies
"k8s.io/api/admission/v1beta1"
"errors"
//HandleMutate()
var admissionReviewReq v1beta1.AdmissionReview
if _, _, err := universalDeserializer.Decode(body, nil, &admissionReviewReq); err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Errorf("could not deserialize request: %v", err)
} else if admissionReviewReq.Request == nil {
w.WriteHeader(http.StatusBadRequest)
errors.New("malformed admission review: request is nil")
}
fmt.Printf("Type: %v \t Event: %v \t Name: %v \n",
admissionReviewReq.Request.Kind,
admissionReviewReq.Request.Operation,
admissionReviewReq.Request.Name,
)
)
```
# Mutation
@ -385,12 +433,14 @@ err = json.Unmarshal(admissionReviewReq.Request.Object.Raw, &pod)
if err != nil {
fmt.Errorf("could not unmarshal pod on admission request: %v", err)
}
```
To perform a simple mutation on the object before the Kubernetes API sees the object, we can apply a patch to the operation.
```
//main()
//global
type patchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
@ -432,17 +482,34 @@ Once you have completed all your patching, convert the patches to byte slice:
Add it to the admission response
```
admissionReviewResponse.Response.Patch = patchBytes
admissionReviewResponse := v1beta1.AdmissionReview{
Response: &v1beta1.AdmissionResponse{
UID: admissionReviewReq.Request.UID,
Allowed: true,
},
}
admissionReviewResponse.Response.Patch = patchBytes
bytes, err := json.Marshal(&admissionReviewResponse)
if err != nil {
fmt.Errorf("marshaling response: %v", err)
}
w.Write(bytes)
//dependencies
"encoding/json"
```
# Build and push the updates
```
docker build ./sourcecode -f ./sourcecode/dockerfile -t aimvector/example-webhook:v1
docker build . -t aimvector/example-webhook:v1
docker push aimvector/example-webhook:v1
```
# Delete all pods
# Delete all pods to get latest image
```
kubectl delete pods --all
@ -457,5 +524,5 @@ kubectl -n default apply -f ./demo-pod.yaml
See the injected label
```
kubectl get pods demo-pod -o yaml
kubectl get pods --show-labels
```

View File

@ -0,0 +1,150 @@
{
"kind": "AdmissionReview",
"apiVersion": "admission.k8s.io/v1beta1",
"request": {
"uid": "dffc1f0f-0c0b-4d15-892f-71524ecfd06c",
"kind": {
"group": "",
"version": "v1",
"kind": "Pod"
},
"resource": {
"group": "",
"version": "v1",
"resource": "pods"
},
"requestKind": {
"group": "",
"version": "v1",
"kind": "Pod"
},
"requestResource": {
"group": "",
"version": "v1",
"resource": "pods"
},
"name": "demo-pod",
"namespace": "default",
"operation": "CREATE",
"userInfo": {
"username": "kubernetes-admin",
"groups": [
"system:masters",
"system:authenticated"
]
},
"object": {
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "demo-pod",
"namespace": "default",
"creationTimestamp": null,
"labels": {
"example-webhook-enabled": "true"
},
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"example-webhook-enabled\":\"true\"},\"name\":\"demo-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx\",\"name\":\"nginx\"}]}}\n"
},
"managedFields": [
{
"manager": "kubectl.exe",
"operation": "Update",
"apiVersion": "v1",
"time": "2021-04-14T07:47:56Z",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:metadata": {
"f:annotations": {
".": {},
"f:kubectl.kubernetes.io/last-applied-configuration": {}
},
"f:labels": {
".": {},
"f:example-webhook-enabled": {}
}
},
"f:spec": {
"f:containers": {
"k:{\"name\":\"nginx\"}": {
".": {},
"f:image": {},
"f:imagePullPolicy": {},
"f:name": {},
"f:resources": {},
"f:terminationMessagePath": {},
"f:terminationMessagePolicy": {}
}
},
"f:dnsPolicy": {},
"f:enableServiceLinks": {},
"f:restartPolicy": {},
"f:schedulerName": {},
"f:securityContext": {},
"f:terminationGracePeriodSeconds": {}
}
}
}
]
},
"spec": {
"volumes": [
{
"name": "default-token-4fzpv",
"secret": {
"secretName": "default-token-4fzpv"
}
}
],
"containers": [
{
"name": "nginx",
"image": "nginx",
"resources": {},
"volumeMounts": [
{
"name": "default-token-4fzpv",
"readOnly": true,
"mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
}
],
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"imagePullPolicy": "Always"
}
],
"restartPolicy": "Always",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"serviceAccountName": "default",
"serviceAccount": "default",
"securityContext": {},
"schedulerName": "default-scheduler",
"tolerations": [
{
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
},
{
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
}
],
"priority": 0,
"enableServiceLinks": true,
"preemptionPolicy": "PreemptLowerPriority"
},
"status": {}
},
"oldObject": null,
"dryRun": false,
"options": {
"kind": "CreateOptions",
"apiVersion": "meta.k8s.io/v1"
}
}
}

View File

@ -1,8 +1,5 @@
FROM golang:1.15-alpine as dev-env
RUN apk update && apk upgrade && \
apk add --no-cache bash
WORKDIR /app
FROM dev-env as build-env

View File

@ -3,7 +3,6 @@ module example-webhook
go 1.15
require (
k8s.io/api v0.21.0
k8s.io/apimachinery v0.21.0
k8s.io/client-go v0.21.0
)

View File

@ -404,8 +404,6 @@ k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA=
k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag=
k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA=
k8s.io/client-go v1.5.2 h1:JOxmv4FxrCIOS54kAABbN8/hA9jqGpns+Zc6soNgd8U=
k8s.io/client-go v1.5.2/go.mod h1:OmM68YRko3DQ0sjlnWxzjQF9lcSLHJXuGMTo23rc7wI=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=

View File

@ -2,35 +2,33 @@ package main
import (
"net/http"
"log"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"flag"
"strconv"
"os"
"fmt"
"path/filepath"
"io/ioutil"
"k8s.io/client-go/kubernetes"
rest "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
apiv1 "k8s.io/api/core/v1"
"flag"
"strconv"
"io/ioutil"
"k8s.io/api/admission/v1beta1"
"encoding/json"
"errors"
apiv1 "k8s.io/api/core/v1"
"encoding/json"
)
var (
universalDeserializer = serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer()
)
type patchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value,omitempty"`
}
var parameters ServerParameters
type ServerParameters struct {
port int // webhook server port
@ -38,10 +36,16 @@ type ServerParameters struct {
keyFile string // path to the x509 private key matching `CertFile`
}
var parameters ServerParameters
var config *rest.Config
var clientSet *kubernetes.Clientset
type patchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value,omitempty"`
}
func main() {
useKubeConfig := os.Getenv("USE_KUBECONFIG")
@ -90,10 +94,7 @@ func main() {
http.HandleFunc("/", HandleRoot)
http.HandleFunc("/mutate", HandleMutate)
err = http.ListenAndServeTLS(":" + strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil)
if err != nil {
panic(err.Error())
}
log.Fatal(http.ListenAndServeTLS(":" + strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil))
}
func HandleRoot(w http.ResponseWriter, r *http.Request){
@ -103,7 +104,7 @@ func HandleRoot(w http.ResponseWriter, r *http.Request){
func HandleMutate(w http.ResponseWriter, r *http.Request){
body, err := ioutil.ReadAll(r.Body)
err = ioutil.WriteFile("/tmp/request", body, 0644)
// err = ioutil.WriteFile("/tmp/request", body, 0644)
if err != nil {
panic(err.Error())
}
@ -125,6 +126,7 @@ func HandleMutate(w http.ResponseWriter, r *http.Request){
)
var pod apiv1.Pod
err = json.Unmarshal(admissionReviewReq.Request.Object.Raw, &pod)
if err != nil {
@ -132,6 +134,7 @@ func HandleMutate(w http.ResponseWriter, r *http.Request){
}
var patches []patchOperation
labels := pod.ObjectMeta.Labels
labels["example-webhook"] = "it-worked"
@ -161,5 +164,4 @@ func HandleMutate(w http.ResponseWriter, r *http.Request){
}
w.Write(bytes)
}

View File

@ -15,5 +15,4 @@ func test(){
}
fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
}

View File

@ -4,5 +4,5 @@ metadata:
name: example-webhook-tls
type: Opaque
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVLRENDQXhDZ0F3SUJBZ0lVZjNkS1BVY1FUTWNKc2lWRXpjUWo2dnFSVjc4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1VqRUxNQWtHQTFVRUJoTUNRVlV4RURBT0JnTlZCQWdUQjBWNFlXMXdiR1V4RWpBUUJnTlZCQWNUQ1UxbApiR0p2ZFhKdVpURVFNQTRHQTFVRUNoTUhSWGhoYlhCc1pURUxNQWtHQTFVRUN4TUNRMEV3SGhjTk1qRXdOREE1Ck1ETXdNVEF3V2hjTk5ERXdOREEwTURNd01UQXdXakJTTVFzd0NRWURWUVFHRXdKQlZURVFNQTRHQTFVRUNCTUgKUlhoaGJYQnNaVEVTTUJBR0ExVUVCeE1KVFdWc1ltOTFjbTVsTVJBd0RnWURWUVFLRXdkRmVHRnRjR3hsTVFzdwpDUVlEVlFRTEV3SkRRVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFMWEpSaXlWClVkTkVnREtzK1lTNjFsRnpkQm1QU2FXQ2hpSUxhNXZWUjlsTDBXMjRVTCtyNWliUnUraDJqTjJ6TVdMTmZPVDIKTWJwU05KY3dRUFpqVisyZTlKRUdhYThBWHdkQk1adkxiU1VvWUpQR1NKMWxVSmoyeXZ2dk42ZmY0ZU56OWljegp2RVdlSzNVMUFGdzk4TnZzb3pKcTBtbEl5MTVRU1o0NGJNSHJ6OTRYQTBCRGhZVWVmNUVSb2hSQ2Z4VndESmk1CnVDRDBEK0JLSFpRNlc0b2hNQ3kzeVR4QWk5dWNZc3haNTR0alZ3a0ZwSG1lREpTdDlFZWNWNkxzMTVidVlTcEEKZ1VYSVEvdkdzcG1pQUp4MnVteDFuc091bEtNUDkwQUdzOWNpcUdvZDUxSldtRG43b2JvdmJuNHVhbE05S2RtRgpnRXhPdnZuRWJjYXhFUFVDQXdFQUFhT0I5VENCOGpBT0JnTlZIUThCQWY4RUJBTUNCYUF3SFFZRFZSMGxCQll3CkZBWUlLd1lCQlFVSEF3RUdDQ3NHQVFVRkJ3TUNNQXdHQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZCc0cKcUFVTzAyUFBhelQwQzg2S1J2YVpGZjNGTUI4R0ExVWRJd1FZTUJhQUZKZFhWUEZGM0pxcXdhYVNIZEZxaXBGKwpMU2wxTUhNR0ExVWRFUVJzTUdxQ0QyVjRZVzF3YkdVdGQyVmlhRzl2YTRJcFpYaGhiWEJzWlMxM1pXSm9iMjlyCkxtUmxabUYxYkhRdWMzWmpMbU5zZFhOMFpYSXViRzlqWVd5Q0cyVjRZVzF3YkdVdGQyVmlhRzl2YXk1a1pXWmgKZFd4MExuTjJZNElKYkc5allXeG9iM04waHdSL0FBQUJNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNtUjdBdQozSHEwVGhrYWtHUEg3YkkwcmhpUTE5TStCMkdHT3VkbjVCNDdKWCs0VjA1bCsxUUd5NGR5eUpFZnp2VWZDMHRRCnUyTWs5amt0OTloRDlWb3NHanBSaGRFQ2ZhTVdoQVhoclZkQi9wcXdnOTh4amlrb1c4bXZFOGJlT3pIU1IxYVYKWnBuM01acGdlR1lkNkxxejdlb0JrNmp4djZVVk1DUGpETkVLN3dQNm40VlRtSFJNQmhHeFNxQ28rQWRDa1hRVgpRZUtQWm9yUlhlbEI4eW5LNVpLR01TU1JqL0h2cExUUUZTTnB3MzBTV0EvRjZJYmRtSEphUmp2M21lNUswbmU1Cjg1bE5vTFd4SUtJNGFOSUVkMitrUzcyaWV6bnRIOTBWZHhJTjBzOTgyZnFYa2diRm5ITCtiYk5MNlF3WDZHSFkKRWxReXl1WGdCOGVZY3dtRQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdGNsR0xKVlIwMFNBTXF6NWhMcldVWE4wR1k5SnBZS0dJZ3RybTlWSDJVdlJiYmhRCnY2dm1KdEc3NkhhTTNiTXhZczE4NVBZeHVsSTBsekJBOW1OWDdaNzBrUVpwcndCZkIwRXhtOHR0SlNoZ2s4WkkKbldWUW1QYksrKzgzcDkvaDQzUDJKek84Ulo0cmRUVUFYRDN3Mit5ak1tclNhVWpMWGxCSm5qaHN3ZXZQM2hjRApRRU9GaFI1L2tSR2lGRUovRlhBTW1MbTRJUFFQNEVvZGxEcGJpaUV3TExmSlBFQ0wyNXhpekZubmkyTlhDUVdrCmVaNE1sSzMwUjV4WG91elhsdTVoS2tDQlJjaEQrOGF5bWFJQW5IYTZiSFdldzY2VW93LzNRQWF6MXlLb2FoM24KVWxhWU9mdWh1aTl1Zmk1cVV6MHAyWVdBVEU2KytjUnR4ckVROVFJREFRQUJBb0lCQVFDVGcySFRlZFB0YVcvUwpMM1ZIRk1vblRGWFJDK3BLU1hHSkhOVlVuaXp3a3NxK2kwdlRUYTIwb0lzb0oxTkY4RXhLRGMra2lIZHY1NWRQCmZGT3EzSkNVZldHZWNhSys1TUU0Uk5uNXY0aXhGMlBQWnA2MFFtdTF4TWFReTl6UStDYjRpTGdkdGFpNG9aSkkKU1JzaXZ3eTltZmdRU0lpMzhOOCtpRTVFK3lxZDdOdkdwZWhObWVMSVZyQ0t5QjU3NzRQaUxHcUFLcTk0Zk1BMQplZVFwSHVDaHZHSDJDZUk0L0ZpeEROT2FwZm13Z3RtSUZVM0Z2TkNYaTBKb20zN0lWYUFNZ3VJc1ZvUHpRNlVyCkhOa3UyaGo4YWFmandCSjhGZDdFMWhjY0J3UFdKQ3VqYUN6aGNxUmR0YURFbDAxdHROcERsRi9nUXpJMW1MMDEKQjdJL1Myb2hBb0dCQU00Z1N0TTM3cDhwUVBEelY0dVVwamVuZ1dNZ2R1UW42aVFUQk5SSldKYW1VMi9yWnU2WQpVUDJtRVNXWkJuNFd4dldTSjl0dnhrKytsRHY2Z3VNWitGdnVIWGxGWGRzQmU5NW1xU3gzTG5HTCtmdGwxQjc2Cm94MkU5Rit6NURQVENDT2IyeGNhd1B0eEZ6Q2lIVXFJYTdsQ3Yybm81WHRnenA5VTNVNnlUUlo5QW9HQkFPSEYKVm1QK21PcVFvdVcydmFPZmRvcEQyQjdxNmYzMUhvb3p0TzJ6aEtodXpqTTcvTjRJNGRWRFUvYmw4U2dvMDA0dQpScHI2OUs1ZWlZc21HbzBGK2Nwdmo4Yis4RmtZQk1rUFRYb2o0VFpHODZkcTFZUHhreWtwRE5RVzRFU3lDTENRCmthSGVDcFppdE1PY09pbHhYSjc5MUgzSUVhTEljNnFrYkFJb245WFpBb0dBSEIvUDFjMzE0d1dQOU5CZkM0NTIKdDNWRmRDOER5ZEdnWXRldGV3R2U4cjh5OXp4WlNRakRWRGlLY21UVXUvT0RwaElSR2lIQUh6VlRxSE5mMUhqQQpxRnB1N3hNRjRWSHNnc1hqSTB3SHJEcDdHMUFqaHk2UGZ3R2JEa3ZQUVRyMEMxZkNwdjVoZ20xRnlyN3ozQzJNCjlUUWtSZUVmSHB4dzFOQ1JlYUZlWDBrQ2dZRUFnQ3BhaEtGL2hZbGVNREd4TGpYVVFXR0tTdUxvdXJad0E5eWUKbFdJWHFOWmVVRTk1bVVKSmtadUxDdG8yTUtvY2FvRnlxNEJUYnJsVU01NEo3SXk3NU9PNEp5dUtuY2s0empyVgpyTVM1a09wdVgxZ1NwYmg1NWgvYm5IcndEWTlUeDRnS1pHMThiU3JUbTBnUTdIM2lLby9HRlRHQ2NYcUJ6eGxRCkIxbXdndUVDZ1lCbGF5TGh1eVdmWUZCcEh6RGdxdGtSSFFCamd4RU1qbEUvVU5KQTBZaW9WanZRaHUzWEUybDgKNGpmenVBQXJvenlxMnFrd21ORWd2dWI5Qm8yMjAvNXppOXRLdmNSSU1wbXhsWTd1MUx3TnNtRzU5UmZ2K05iTgpqYnB1L2p6aEN4SlZ4SGxpRkhRWitncFgzbmtCazQ2bFVuVmRzbmRHaTJKOHllSmVlRmhEVkE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVLRENDQXhDZ0F3SUJBZ0lVZVM1ZWRPRHlWdWhhTVZHcStodGtQWXJrL0E0d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1VqRUxNQWtHQTFVRUJoTUNRVlV4RURBT0JnTlZCQWdUQjBWNFlXMXdiR1V4RWpBUUJnTlZCQWNUQ1UxbApiR0p2ZFhKdVpURVFNQTRHQTFVRUNoTUhSWGhoYlhCc1pURUxNQWtHQTFVRUN4TUNRMEV3SGhjTk1qRXdOREUwCk1EUTBPVEF3V2hjTk5ERXdOREE1TURRME9UQXdXakJTTVFzd0NRWURWUVFHRXdKQlZURVFNQTRHQTFVRUNCTUgKUlhoaGJYQnNaVEVTTUJBR0ExVUVCeE1KVFdWc1ltOTFjbTVsTVJBd0RnWURWUVFLRXdkRmVHRnRjR3hsTVFzdwpDUVlEVlFRTEV3SkRRVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFMVDB6NGE3Ckk5b1RVd2RhaWZmeGlLSkFCOHhoUklRNG16NHVSQTdSUk5DZFVOZTBsNEhSN1RUeUlGWnhHeFpUempVeVhGSWgKbklvamNkdEFXeEFwdVJCWGsvNlJub3ZiVG42UHVWbWJGa1lvblg2blErenNNSG5Tcm5jNFFMVERXbEc3MjdIMwo1ekZsUVRRS3RCZUoybmpWUnorOS9aWTBRL2QxWFZnb1VKcDV6RGZKTFJDVkoxZFVMM3FsWlYyeERvM2NkL2hBCjQyTEt3OTFNNTJTRE16aEJtczg1UXhqbnFNZHB0WWt2NVBSei9OWkN5TDlhSlV5SG5rcjhscENKeit6aUdHdEoKd2NSbGZWdWpQK0xGQ1RUS2ZGYi9ORnhpWWtZc2RJV0xlc0lXRytncnNQT2JWOEQwYUhKYXhtY1RXWUlZYWQ5QwpTQUJqcm9nNUM5NXAvZWNDQXdFQUFhT0I5VENCOGpBT0JnTlZIUThCQWY4RUJBTUNCYUF3SFFZRFZSMGxCQll3CkZBWUlLd1lCQlFVSEF3RUdDQ3NHQVFVRkJ3TUNNQXdHQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZHY3IKam5jTUR1S0wwKzdvTTlHUDNRUkh2TWd1TUI4R0ExVWRJd1FZTUJhQUZJSnh4VXIyUzlhd0ptM1Nqd3QvRCt1cApJWlFzTUhNR0ExVWRFUVJzTUdxQ0QyVjRZVzF3YkdVdGQyVmlhRzl2YTRJcFpYaGhiWEJzWlMxM1pXSm9iMjlyCkxtUmxabUYxYkhRdWMzWmpMbU5zZFhOMFpYSXViRzlqWVd5Q0cyVjRZVzF3YkdVdGQyVmlhRzl2YXk1a1pXWmgKZFd4MExuTjJZNElKYkc5allXeG9iM04waHdSL0FBQUJNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUEwcmd0YQp6SDVXU2JKZXlCY1RkdkRyR25VN3hVZ3lxZlh2aWkzV25ZRTQ0MkdqR2tzY0wxM0lUUFFoM3k0VDJVTTZxbTh2CldlbXYvTmYvcm1UeVRlSU4rUWtneHlBd2cvOThSMTcvNUs3YTVzamRiQ2Z5elFYNFMrUkxyQW9pT1pxUDZrelUKblRlV01kZGlPV0YwSEhJT2tKdnliTVhFSDVja3N5Y0NhSk5mRU4vdnhoL3FFZXc1N0R0aFl6ZFQ5cHovMHVrNQpDSkpIenMyWDFtMlJoa2hGM0hGR3FMdDhhVVJ4T0JoNEZ2WmxlUjZYbXNIM2pRa3pBT28yOXRtK3JoZEkxaXRzClY0Q1NDWjB1clJETjRrTWFZT2M5VS9pcU9WbmQyMzVEMC9GVHRZS1VaRWVDZXVNQThLTkZuUXFJMkYxTWNwUnAKWVhURUpzSXhKUThOUnZWKwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBdFBUUGhyc2oyaE5UQjFxSjkvR0lva0FIekdGRWhEaWJQaTVFRHRGRTBKMVExN1NYCmdkSHROUElnVm5FYkZsUE9OVEpjVWlHY2lpTngyMEJiRUNtNUVGZVQvcEdlaTl0T2ZvKzVXWnNXUmlpZGZxZEQKN093d2VkS3VkemhBdE1OYVVidmJzZmZuTVdWQk5BcTBGNG5hZU5WSFA3MzlsalJEOTNWZFdDaFFtbm5NTjhrdApFSlVuVjFRdmVxVmxYYkVPamR4MytFRGpZc3JEM1V6blpJTXpPRUdhenpsREdPZW94Mm0xaVMvazlIUDgxa0xJCnYxb2xUSWVlU3Z5V2tJblA3T0lZYTBuQnhHVjlXNk0vNHNVSk5NcDhWdjgwWEdKaVJpeDBoWXQ2d2hZYjZDdXcKODV0WHdQUm9jbHJHWnhOWmdoaHAzMEpJQUdPdWlEa0wzbW45NXdJREFRQUJBb0lCQURJcFZzbTdZS0hZRDRFUApXUVdSUDlYeU4vY3cwMlJ2cUtFaEJCNnpaZ2NLUk5tMnB2VUdzMkdrNk0vdGhKdTQyWVdua3kzMVFVYU5zc2NiClhPTHJIZkRveGc2Z1lUblZyam1wTDdFbUs1T0JPTDllTUpjaGxnSi9JM3ZLN1N6dXBqL1grbnVvQTcrT21QZUwKTEFjR1lMaDBMczc5cEtrWmplbXY4Qk03QWJVQUxQM3pnakJRdi9DOXBrdTJ1cUE1RytOM0F0R0pOcm0xTHRRNApLaGwxL0g4RGNPSUduNzZwUms1WUxtL2RFV3ZGb1VQcGRXakpyWFhZNXRvTERMelF5YS9PTGNzZkR6R0ZKQnljCk9RMEI0OG9ZUHJYN0J3WnBka2FjMFVTSWJtN0l0T1BsOTBIdjdPdDl0cVZYVERGMmNnQUs3UmtvU1htV2tYUDIKaURSU0gra0NnWUVBM0tBT29CWHBoSUVmWDU2SVk1aDV5Z3Nmb3dCd1l4azVxRjBjRWpjbVFmaGU1RDVQRDliMQpERkhiQVlFZW52dEVCWXhUK216ejhtTU84QVJDSnNtTmp2M0M4bzNXTE5rRVVuV3hXazJiRlQ3NDBQUUJpNFdFCndSTWNWL1NrT0F6NnlhdW9oMVBLMGFiWHAyR1JJM1NpOSs1aTExL0NyNWtyRE0wMUpoSGlidTBDZ1lFQTBmaDUKU29NYTVocENoYjloWTFyRnhmSnRtd2U4eFBUT3puVDVXWjAvakZPTFNvR0lyU0YrcHg0a0hrdDF2ZG9XTk1wZAoxQWFEN2F4U3gyYjA5aThMSjhXOG85YTBLSmNOS01tNm9vRURqbms4V0VJQm9oeUtrSldsU1NXRU1xc1Y4V0NJClAxY3kwL3JSL3pWUVJlc2QwNlFEbjMwOUJLdDYwYUpUd0hIS01hTUNnWUJIbTIrRHgvamw5OTdOOHkrRFc5N1QKays2dHdodTRIbHpYWjNrUDlIUm5Yd3kxZWYvQlBWeUZwaCsyQ2tsOUFrS2VwbUF2WEtPRTNWL2d5UkVMYzhtTgpTcEcybGhDWXQ4c3VWR0srMDRkdFN1WUpNOWs0aHBxQzdBZjhDRHd3c1EzSTNQMHpCeUJDRWF2VytOVFp0Q2FjCjMvT1d3YzczblhnYWpKUWVpaGw3TlFLQmdRQ1NJWGJ3dDd3Qnh1YmpSS1dYeXpYM3BOaEpYQ0l4aFJ0bExwM1gKazR3RnNxTXZrR1U1OFNTL1ZFZlkyYld4RXRYL21aT2htNE0zNTRXWkIzdVcxbmpTRGxsU1FYd1MvOFdGekpmYQp2eVZsZzlUT3ErbU5GSVlQU0ViSFdKZmYxNWdtN0lNR2FqNlNyMjUxU25wNm5yNmNhL3FsaGpqd1JoUHRVQ2N2CnVVSDZOd0tCZ0R0cE54ZlV1QlhvVkswczJkeGVIODBmVXNQWm1yMDM1ZUFJeWJyazJRZjN1cXRtWDEwU2V0blgKeUw2UlluNHBCOU52U2NRR0VxK2M1MW5CdHpQV2IvSHlxWmRLVWtGUEFvaDc1b3hKS0YrUlErT1B0eXp0MkEyWApsTHJjYkRxN0J5SkF5Nml4S3ZwU0tJcUtlZjdvempHQ2pHTDF0RlNOZmd6NTA4VjRBK2NjCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

View File

@ -5,7 +5,7 @@ metadata:
webhooks:
- name: example-webhook.default.svc.cluster.local
admissionReviewVersions:
- "v1beta"
- "v1beta1"
sideEffects: "None"
timeoutSeconds: 30
objectSelector:

View File

@ -16,7 +16,7 @@ webhooks:
name: example-webhook
namespace: default
path: "/mutate"
caBundle: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURtRENDQW9DZ0F3SUJBZ0lVWGJCWkhMaXFrL0VtcUo0MTBNZjFTNDBNUXVnd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1VqRUxNQWtHQTFVRUJoTUNRVlV4RURBT0JnTlZCQWdUQjBWNFlXMXdiR1V4RWpBUUJnTlZCQWNUQ1UxbApiR0p2ZFhKdVpURVFNQTRHQTFVRUNoTUhSWGhoYlhCc1pURUxNQWtHQTFVRUN4TUNRMEV3SGhjTk1qRXdOREE1Ck1ETXdNREF3V2hjTk1qWXdOREE0TURNd01EQXdXakJTTVFzd0NRWURWUVFHRXdKQlZURVFNQTRHQTFVRUNCTUgKUlhoaGJYQnNaVEVTTUJBR0ExVUVCeE1KVFdWc1ltOTFjbTVsTVJBd0RnWURWUVFLRXdkRmVHRnRjR3hsTVFzdwpDUVlEVlFRTEV3SkRRVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFQVmp2dDlmClJqWU9jRzlJNzBCZzFQcDBCMG0vTWxoREpsbmUxdnJUelJBTEpQK3ZIK0h0RzBIV0VBY3JhVU81MFB1Z3RHekcKekdGa3IzNDZYK2pRbmtWRmQvSnZHTG5WN1hzWFRJblVkNUJ4UnQrbWVjaVE5Y2t6SWl0bVQ5UElvMElTVlVaRgp4SWtpYXJES0dpK3FjQlg0NUNvaWNwQUVOLzNNOXBJanJOdTVBVDI1dUkrbHJUNXdvT1g1QmFVRWpqaCtHdlZtCmNlNzJEMkJhU2lPUDYwZTJlY3ZtU2FQdEZ2bjk3WDI5RkpYTkhoUElNUFlQR1ZUZ0hQSjdXdHBISjdzWGZhUHMKNW9pZzJPUXFLeEFaaXBRYnRob1orb0pVQk51aDBTMXZFUnlPRnV3L2VOSnpuNERRcWxBSmNCbmJlUDA4S2dQUwo4VGxIa0ZXdjFXMVdPdzhDQXdFQUFhTm1NR1F3RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJCk1BWUJBZjhDQVFJd0hRWURWUjBPQkJZRUZKZFhWUEZGM0pxcXdhYVNIZEZxaXBGK0xTbDFNQjhHQTFVZEl3UVkKTUJhQUZKZFhWUEZGM0pxcXdhYVNIZEZxaXBGK0xTbDFNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUURjRnVPOApLajJYSWJLdnFPeFdUNWQ1V2FRa21TTVV4VlgrT3FEYmY3MWNqNGhYeTNpQzQ3UW80UTlQR2JnSVV3RjlxSzhVCmRHdXhpYzRnWHJXY0dFSzZzNlVLVU5xWUIySTFXV0VZdW5jekw1WnZrUnpOWmlQUEVneTJkTmxRQ3FkZlF4SVIKWThKUExlTkF6MmZteDZHNTFab0RVSzhHSmtLVnlOYnlsTndSL0JxMHJVU1NYbHhvVE5WWGFDVk93UE9RMGxjRgp2TDdidWVWVzd3RW9RbEhFU1k3Q0NHQkl6bEhlcVNtZzdVNGd0Nk5tWE9yS2dELzhzalk1SUR5L2UyeDR5MFR2CjduSXF4UUNWb0NZQmRrNWNOU2IvZWJVUEdBcHFVS3R1WEJzMlpjRklob0ZOd09sem1hYmF2cVEvNFpEVVNGS3AKZ1dQZGhXWVByS04vamZtbgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
caBundle: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURtRENDQW9DZ0F3SUJBZ0lVUmE5YzR5NXVmUXNEWHFrZFo1cFhmOEFGcjNBd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1VqRUxNQWtHQTFVRUJoTUNRVlV4RURBT0JnTlZCQWdUQjBWNFlXMXdiR1V4RWpBUUJnTlZCQWNUQ1UxbApiR0p2ZFhKdVpURVFNQTRHQTFVRUNoTUhSWGhoYlhCc1pURUxNQWtHQTFVRUN4TUNRMEV3SGhjTk1qRXdOREUwCk1EUTBOekF3V2hjTk1qWXdOREV6TURRME56QXdXakJTTVFzd0NRWURWUVFHRXdKQlZURVFNQTRHQTFVRUNCTUgKUlhoaGJYQnNaVEVTTUJBR0ExVUVCeE1KVFdWc1ltOTFjbTVsTVJBd0RnWURWUVFLRXdkRmVHRnRjR3hsTVFzdwpDUVlEVlFRTEV3SkRRVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFMR1Q2NW9SClVWcTdDM2RKNkZYSXQwOVdFVkN0MUZuWDRZL3Vtc0wySGpudkdNdGdsU096a0p5cjVTYk5uRytZVzQ4UmhzVEQKZEMxTzFmbWFTWmpRYUNjQ2ZJRFZSTDFyVDFxNis0Smo1QTJnN1VPOS9NbThySnlFeFFMaXVJTVJoc1lUaFR6OQpmTDZucXBKWDZaelpPRFhIcUR0SU1wM2tkdGJ1dGhZRW01WW5RQjd3dTRPUnZJbmtkQk0wNWVHZGw3MFkwVHF1CmlZY3ZBL0MzRndUZjErOTBvTHdIdDcyakw3THBBL0pZSGwvWHNuMVhMd1dic3J0ZUZEVUtsWFl2c1lhKytrSVQKbnloeTF3MkZTeWNtSUdDU2hPdjJsVm1sbVVOUWI4b1lZaDNzTUtEZnhZMmwwak5mVnRibituZ0p6bzFqcklYSAptcTJkdzRiWC9WV3F1ZnNDQXdFQUFhTm1NR1F3RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJCk1BWUJBZjhDQVFJd0hRWURWUjBPQkJZRUZJSnh4VXIyUzlhd0ptM1Nqd3QvRCt1cElaUXNNQjhHQTFVZEl3UVkKTUJhQUZJSnh4VXIyUzlhd0ptM1Nqd3QvRCt1cElaUXNNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNWdDFaOQo4aWMzNVloL3JITktiMGtOZmFPTUNWaWQzamZoNUR0V2tIVG0rVlRkMk1oUDRHb1lGNXNYSmhMN280dzRFTXV2ClNJTGlPMDJjRnVON0NLVno2NUNLQXQwNkI5ekxOb1NUWVlzbWVGUERnME0xUWMreW1FeGlWYU5CelZtRUdHbHMKNXdyUHhXMzE1L1h4VWRnc25kcWRQUmFQM0NBZGM5dEl0Q1BSL0ZoRys0ZHlvd0NiYmZ3NGhiekhDRmRyenJ1cwpLc1Z6NFFWekZkeWhiUFlFQ0hlYVp0UUxzalNQVng4U1kwZWtPcWZyTkZxcHMwRzNEL3pMSmFGVE8xRTVwUkkvClAwTk9JKzRCcnVoQXRZY2d0djhVWTNHc3VQNzE2QmxwY2taZ3FMTm5Zci8vTllZY0NGcEs1enhmaXdYc3VXNDEKWHhuY1VJUG9BSXlXY1cyWQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
rules:
- operations: [ "CREATE" ]
apiGroups: [""]