Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagetext
titleMutating Webhook
package main

import (
        "encoding/json"
        "errors"
        "flag"
        "fmt"
        "io/ioutil"
        "k8s.io/api/admission/v1beta1"
        v1 "k8s.io/api/core/v1"
        "k8s.io/apimachinery/pkg/runtime"
        "k8s.io/apimachinery/pkg/runtime/serializer"
        "log"
        "net/http"
        "strconv"
)

type ServerParameters struct {
        port     int    // webhook server port
        certFile string // path to the x509 cert
        keyFile  string // path to the x509 private key
}

type patchOperation struct {
        Op    string      `json:"op"`
        Path  string      `json:"path"`
        Value interface{} `json:"value,omitempty"`
}

var parameters ServerParameters
var (
        universalDeserializer = serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer()
)

func main() {
        flag.IntVar(¶meters&parameters.port, "port", 8443, "Webhook server port.")
        flag.StringVar(¶meters&parameters.certFile, "tlsCertFile", "/certs/tls.crt", "File containing the x509 certificate")
        flag.StringVar(¶meters&parameters.keyFile, "tlsKeyFile", "/certs/tls.key", "File containing the x509 private key")
        flag.Parse()

        http.HandleFunc("/inject-sidecar", HandleSideCarInjection)
        log.Fatal(http.ListenAndServeTLS(":"+strconv.Itoa(parameters.port), parameters.certFile, parameters.keyFile, nil))
}

func HandleSideCarInjection(w http.ResponseWriter, r *http.Request) {

        body, err := ioutil.ReadAll(r.Body)
        err = ioutil.WriteFile("/tmp/request", body, 0644)
        if err != nil {
                panic(err.Error())
        }

        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 empty")
        }

        fmt.Printf("Received Admission Review Request - Type: %v \t Event: %v \t Name: %v \n",
                admissionReviewReq.Request.Kind,
                admissionReviewReq.Request.Operation,
                admissionReviewReq.Request.Name,
        )

        var pod v1.Pod

        err = json.Unmarshal(admissionReviewReq.Request.Object.Raw, &pod)

        if err != nil {
                fmt.Errorf("Could not unmarshal pod from admission request: %v", err)
        }

        var patches []patchOperation

        labels := pod.ObjectMeta.Labels
        labels["sidecar-injection-webhook"] = "jwt-proxy"

        patches = append(patches, patchOperation{
                Op:    "add",
                Path:  "/metadata/labels",
                Value: labels,
        })

        var containers []v1.Container
        containers = append(containers, pod.Spec.Containers...)
        container := v1.Container{
                Name:            "jwt-proxy",
                Image:           "ktimoney/rapps-jwt",
                ImagePullPolicy: v1.PullIfNotPresent,
                Ports: []v1.ContainerPort{
                        {
                                Name:          "http",
                                Protocol:      v1.ProtocolTCP,
                                ContainerPort: 8888,
                        },
                },
                VolumeMounts: []v1.VolumeMount{
                        {
                                Name:      "certsdir",
                                MountPath: "/certs",
                                ReadOnly:  true,
                        },
                },
        }

        containers = append(containers, container)
        fmt.Println(containers)

        patches = append(patches, patchOperation{
                Op:    "add",
                Path:  "/spec/containers",
                Value: containers,
        })

        pathType := v1.HostPathDirectoryOrCreate
        pathTypePtr := &pathType
        var volumes []v1.Volume
        volumes = append(volumes, pod.Spec.Volumes...)
        volume := v1.Volume{
                Name: "certsdir",
                VolumeSource: v1.VolumeSource{
                        HostPath: &v1.HostPathVolumeSource{
                                Path: "/var/rapps/certs",
                                Type: pathTypePtr,
                        },
                },
        }
        volumes = append(volumes, volume)
        fmt.Println(volumes)

        patches = append(patches, patchOperation{
                Op:    "add",
                Path:  "/spec/volumes",
                Value: volumes,
        })
        fmt.Println(patches)

        patchBytes, err := json.Marshal(patches)

        if err != nil {
                fmt.Errorf("Error occurred when trying to marshal JSON patch: %v", err)
        }

        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("Error occurred when trying to marshal Aadmission Review response: %v", err)
        }

        w.Write(bytes)

}

...