diff --git a/cmd/webhook/httpServer.go b/cmd/webhook/httpServer.go index 91da37e..5d6255a 100644 --- a/cmd/webhook/httpServer.go +++ b/cmd/webhook/httpServer.go @@ -1,7 +1,6 @@ package main import ( - "encoding/json" "fmt" "io" "log" @@ -10,6 +9,7 @@ import ( "time" "crypto/tls" + "encoding/json" "net/http" "mutating-webhook/internal/certificate" @@ -74,6 +74,7 @@ func httpServer(cfg *config.Config) { ah := &admissionHandler{ decoder: serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer(), + config: cfg, } // healthcheck @@ -124,6 +125,7 @@ func webHealthCheck(w http.ResponseWriter, r *http.Request) { type admissionHandler struct { decoder runtime.Decoder + config *config.Config } // Serve returns a http.HandlerFunc for an admission webhook @@ -171,7 +173,7 @@ func (h *admissionHandler) Serve(hook operations.Hook) http.HandlerFunc { return } - result, err := hook.Execute(review.Request) + result, err := hook.Execute(review.Request, h.config) if err != nil { msg := err.Error() log.Printf("[ERROR] Internal Server Error: %s", msg) diff --git a/cmd/webhook/httpServerTemplates.go b/cmd/webhook/httpServerTemplates.go index 596b9ea..0834563 100644 --- a/cmd/webhook/httpServerTemplates.go +++ b/cmd/webhook/httpServerTemplates.go @@ -1,8 +1,9 @@ package main import ( - "encoding/json" "log" + + "encoding/json" "net/http" ) diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 5e0b846..a4a188d 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -3,9 +3,10 @@ package main import ( "log" "os" - "os/signal" "syscall" + "os/signal" + "mutating-webhook/internal/config" ) diff --git a/internal/certificate/create-ca.go b/internal/certificate/create-ca.go index f5f169f..96b6941 100644 --- a/internal/certificate/create-ca.go +++ b/internal/certificate/create-ca.go @@ -2,14 +2,15 @@ package certificate import ( "bytes" + "strconv" + "time" + "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "math/big" - "strconv" - "time" ) func CreateCA() ([]byte, []byte, []byte, error) { diff --git a/internal/certificate/create-cert.go b/internal/certificate/create-cert.go index 5a3dd2a..14f6462 100644 --- a/internal/certificate/create-cert.go +++ b/internal/certificate/create-cert.go @@ -2,14 +2,15 @@ package certificate import ( "bytes" + "strconv" + "time" + "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "math/big" - "strconv" - "time" ) func CreateCert() ([]byte, []byte, []byte, error) { diff --git a/internal/certificate/create-server-cert.go b/internal/certificate/create-server-cert.go index e77dfdf..d533b3c 100644 --- a/internal/certificate/create-server-cert.go +++ b/internal/certificate/create-server-cert.go @@ -2,11 +2,12 @@ package certificate import ( "bytes" + "log" + "crypto/rand" "crypto/tls" "crypto/x509" "encoding/pem" - "log" ) func CreateServerCert() tls.Certificate { diff --git a/internal/config/config.go b/internal/config/config.go index e0fac50..f9633ad 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -29,6 +29,9 @@ type Config struct { WebServerReadTimeout int `env:"webserver_read_timeout" default:"5"` WebServerWriteTimeout int `env:"webserver_write_timeout" default:"1"` WebServerIdleTimeout int `env:"webserver_idle_timeout" default:"2"` + + // mutation configuration + AllowAdminNoMutate bool `env:"allow_admin_nomutate" default:"false"` } // DefaultConfig initializes the config variable for use with a prepared set of defaults. diff --git a/internal/operations/deploymentsValidation.go b/internal/operations/deploymentsValidation.go index 6ebebf7..240685e 100644 --- a/internal/operations/deploymentsValidation.go +++ b/internal/operations/deploymentsValidation.go @@ -1,22 +1,24 @@ package operations import ( + "mutating-webhook/internal/config" + admission "k8s.io/api/admission/v1" ) func DeploymentsValidation() Hook { return Hook{ // default allow - Create: func(r *admission.AdmissionRequest) (*Result, error) { + Create: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, - Delete: func(r *admission.AdmissionRequest) (*Result, error) { + Delete: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, - Update: func(r *admission.AdmissionRequest) (*Result, error) { + Update: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, - Connect: func(r *admission.AdmissionRequest) (*Result, error) { + Connect: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, } diff --git a/internal/operations/hook.go b/internal/operations/hook.go index 641e1a6..f46b565 100644 --- a/internal/operations/hook.go +++ b/internal/operations/hook.go @@ -5,6 +5,8 @@ package operations import ( "fmt" + "mutating-webhook/internal/config" + admission "k8s.io/api/admission/v1" ) @@ -16,7 +18,7 @@ type Result struct { } // AdmitFunc defines how to process an admission request -type AdmitFunc func(request *admission.AdmissionRequest) (*Result, error) +type AdmitFunc func(request *admission.AdmissionRequest, cfg config.Config) (*Result, error) // Hook represents the set of functions for each operation in an admission webhook. type Hook struct { @@ -27,25 +29,25 @@ type Hook struct { } // Execute evaluates the request and try to execute the function for operation specified in the request. -func (h *Hook) Execute(r *admission.AdmissionRequest) (*Result, error) { +func (h *Hook) Execute(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) { switch r.Operation { case admission.Create: - return wrapperExecution(h.Create, r) + return wrapperExecution(h.Create, r, *cfg) case admission.Update: - return wrapperExecution(h.Update, r) + return wrapperExecution(h.Update, r, *cfg) case admission.Delete: - return wrapperExecution(h.Delete, r) + return wrapperExecution(h.Delete, r, *cfg) case admission.Connect: - return wrapperExecution(h.Connect, r) + return wrapperExecution(h.Connect, r, *cfg) } return &Result{Msg: fmt.Sprintf("Invalid operation: %s", r.Operation)}, nil } -func wrapperExecution(fn AdmitFunc, r *admission.AdmissionRequest) (*Result, error) { +func wrapperExecution(fn AdmitFunc, r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { if fn == nil { return nil, fmt.Errorf("operation %s is not registered", r.Operation) } - return fn(r) + return fn(r, cfg) } diff --git a/internal/operations/podsMutation.go b/internal/operations/podsMutation.go index 0fb5d9d..c649b53 100644 --- a/internal/operations/podsMutation.go +++ b/internal/operations/podsMutation.go @@ -3,6 +3,8 @@ package operations import ( "fmt" + "mutating-webhook/internal/config" + admission "k8s.io/api/admission/v1" core "k8s.io/api/core/v1" ) @@ -11,20 +13,20 @@ func PodsMutation() Hook { return Hook{ Create: podMutationCreate(), // default allow - Delete: func(r *admission.AdmissionRequest) (*Result, error) { + Delete: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, - Update: func(r *admission.AdmissionRequest) (*Result, error) { + Update: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, - Connect: func(r *admission.AdmissionRequest) (*Result, error) { + Connect: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, } } func podMutationCreate() AdmitFunc { - return func(r *admission.AdmissionRequest) (*Result, error) { + return func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { var operations []PatchOperation pod, err := parsePod(r.Object.Raw) if err != nil { @@ -32,7 +34,7 @@ func podMutationCreate() AdmitFunc { } // if pod is administratively exempt - if func(pod *core.Pod) bool { + if cfg.AllowAdminNoMutate && func(pod *core.Pod) bool { for label, value := range pod.Annotations { if label == "AdminNoMutate" && value == "true" { return false diff --git a/internal/operations/podsValidation.go b/internal/operations/podsValidation.go index 72ca1a6..23b8541 100644 --- a/internal/operations/podsValidation.go +++ b/internal/operations/podsValidation.go @@ -4,6 +4,8 @@ import ( "log" "strings" + "mutating-webhook/internal/config" + admission "k8s.io/api/admission/v1" ) @@ -11,20 +13,20 @@ func PodsValidation() Hook { return Hook{ Create: podValidationCreate(), // default allow - Delete: func(r *admission.AdmissionRequest) (*Result, error) { + Delete: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, - Update: func(r *admission.AdmissionRequest) (*Result, error) { + Update: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, - Connect: func(r *admission.AdmissionRequest) (*Result, error) { + Connect: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { return &Result{Allowed: true}, nil }, } } func podValidationCreate() AdmitFunc { - return func(r *admission.AdmissionRequest) (*Result, error) { + return func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) { pod, err := parsePod(r.Object.Raw) if err != nil { return &Result{Msg: err.Error()}, nil