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. 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 Build and run the controller
``` ```
# get dev environment: webhook # get dev environment: webhook
cd sourcecode cd sourcecode
docker build --target dev-env . -t webhook docker build . -t webhook
docker run -it --rm -p 80:80 --entrypoint bash -v ${HOME}/.kube/:/root/.kube/ -v ${PWD}:/app 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 go mod init example-webhook
``` ```
Source code:
New file : `main.go`
``` ```
package main 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 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: 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 # start our web server exposing TLS endpoint
err = http.ListenAndServeTLS(":" + strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil) log.Fatal(http.ListenAndServeTLS(":" + strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil))
if err != nil {
panic(err.Error())
}
``` ```
@ -318,9 +322,37 @@ if err != nil {
<hr/> <hr/>
Let's built what we have and deploy it to our kubernetes cluster 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 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 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", ```
admissionReviewReq.Request.Kind, //dependencies
admissionReviewReq.Request.Operation, "k8s.io/api/admission/v1beta1"
admissionReviewReq.Request.Name, "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 # Mutation
@ -385,12 +433,14 @@ err = json.Unmarshal(admissionReviewReq.Request.Object.Raw, &pod)
if err != nil { if err != nil {
fmt.Errorf("could not unmarshal pod on admission request: %v", err) 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. 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 { type patchOperation struct {
Op string `json:"op"` Op string `json:"op"`
Path string `json:"path"` 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 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 # 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 docker push aimvector/example-webhook:v1
``` ```
# Delete all pods # Delete all pods to get latest image
``` ```
kubectl delete pods --all kubectl delete pods --all
@ -457,5 +524,5 @@ kubectl -n default apply -f ./demo-pod.yaml
See the injected label 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 FROM golang:1.15-alpine as dev-env
RUN apk update && apk upgrade && \
apk add --no-cache bash
WORKDIR /app WORKDIR /app
FROM dev-env as build-env FROM dev-env as build-env

View File

@ -3,7 +3,6 @@ module example-webhook
go 1.15 go 1.15
require ( require (
k8s.io/api v0.21.0
k8s.io/apimachinery v0.21.0 k8s.io/apimachinery v0.21.0
k8s.io/client-go 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/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 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag=
k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= 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/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.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=

View File

@ -2,29 +2,43 @@ package main
import ( import (
"net/http" "net/http"
"log"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/runtime/serializer"
"flag"
"strconv"
"os" "os"
"fmt" "fmt"
"path/filepath" "path/filepath"
"io/ioutil"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir" "k8s.io/client-go/util/homedir"
apiv1 "k8s.io/api/core/v1" "flag"
"strconv"
"io/ioutil"
"k8s.io/api/admission/v1beta1" "k8s.io/api/admission/v1beta1"
"encoding/json"
"errors" "errors"
apiv1 "k8s.io/api/core/v1"
"encoding/json"
) )
var ( var (
universalDeserializer = serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer() universalDeserializer = serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer()
) )
var parameters ServerParameters
type ServerParameters struct {
port int // webhook server port
certFile string // path to the x509 certificate for https
keyFile string // path to the x509 private key matching `CertFile`
}
var config *rest.Config
var clientSet *kubernetes.Clientset
type patchOperation struct { type patchOperation struct {
Op string `json:"op"` Op string `json:"op"`
Path string `json:"path"` Path string `json:"path"`
@ -32,20 +46,10 @@ type patchOperation struct {
} }
type ServerParameters struct {
port int // webhook server port
certFile string // path to the x509 certificate for https
keyFile string // path to the x509 private key matching `CertFile`
}
var parameters ServerParameters
var config *rest.Config
var clientSet *kubernetes.Clientset
func main() { func main() {
useKubeConfig := os.Getenv("USE_KUBECONFIG") useKubeConfig := os.Getenv("USE_KUBECONFIG")
kubeConfigFilePath := os.Getenv("KUBECONFIG") kubeConfigFilePath := os.Getenv("KUBECONFIG")
flag.IntVar(&parameters.port, "port", 8443, "Webhook server port.") flag.IntVar(&parameters.port, "port", 8443, "Webhook server port.")
flag.StringVar(&parameters.certFile, "tlsCertFile", "/etc/webhook/certs/tls.crt", "File containing the x509 Certificate for HTTPS.") flag.StringVar(&parameters.certFile, "tlsCertFile", "/etc/webhook/certs/tls.crt", "File containing the x509 Certificate for HTTPS.")
@ -89,11 +93,8 @@ func main() {
test() test()
http.HandleFunc("/", HandleRoot) http.HandleFunc("/", HandleRoot)
http.HandleFunc("/mutate", HandleMutate) http.HandleFunc("/mutate", HandleMutate)
err = http.ListenAndServeTLS(":" + strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil) log.Fatal(http.ListenAndServeTLS(":" + strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil))
if err != nil {
panic(err.Error())
}
} }
func HandleRoot(w http.ResponseWriter, r *http.Request){ func HandleRoot(w http.ResponseWriter, r *http.Request){
@ -101,9 +102,9 @@ func HandleRoot(w http.ResponseWriter, r *http.Request){
} }
func HandleMutate(w http.ResponseWriter, r *http.Request){ func HandleMutate(w http.ResponseWriter, r *http.Request){
body, err := ioutil.ReadAll(r.Body) body, err := ioutil.ReadAll(r.Body)
err = ioutil.WriteFile("/tmp/request", body, 0644) // err = ioutil.WriteFile("/tmp/request", body, 0644)
if err != nil { if err != nil {
panic(err.Error()) panic(err.Error())
} }
@ -125,21 +126,23 @@ func HandleMutate(w http.ResponseWriter, r *http.Request){
) )
var pod apiv1.Pod var pod apiv1.Pod
err = json.Unmarshal(admissionReviewReq.Request.Object.Raw, &pod)
err = json.Unmarshal(admissionReviewReq.Request.Object.Raw, &pod)
if err != nil { if err != nil {
fmt.Errorf("could not unmarshal pod on admission request: %v", err) fmt.Errorf("could not unmarshal pod on admission request: %v", err)
} }
var patches []patchOperation var patches []patchOperation
labels := pod.ObjectMeta.Labels labels := pod.ObjectMeta.Labels
labels["example-webhook"] = "it-worked" labels["example-webhook"] = "it-worked"
patches = append(patches, patchOperation{ patches = append(patches, patchOperation{
Op: "add", Op: "add",
Path: "/metadata/labels", Path: "/metadata/labels",
Value: labels, Value: labels,
}) })
patchBytes, err := json.Marshal(patches) patchBytes, err := json.Marshal(patches)
if err != nil { if err != nil {
@ -161,5 +164,4 @@ func HandleMutate(w http.ResponseWriter, r *http.Request){
} }
w.Write(bytes) w.Write(bytes)
} }

View File

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

View File

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

View File

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

View File

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