Enable ability to flip configuration of allownomutate
This commit is contained in:
parent
80ef925ff4
commit
8094816911
@ -37,7 +37,7 @@ func strictTransport(w http.ResponseWriter) {
|
|||||||
w.Header().Add("Strict-Transport-Security", "max-age=63072000")
|
w.Header().Add("Strict-Transport-Security", "max-age=63072000")
|
||||||
}
|
}
|
||||||
|
|
||||||
func httpServer(cfg *config.Config) {
|
func httpServer() {
|
||||||
var serverCertificate tls.Certificate
|
var serverCertificate tls.Certificate
|
||||||
if config.DefaultConfig().WebServerCertificate == "" || cfg.WebServerKey == "" {
|
if config.DefaultConfig().WebServerCertificate == "" || cfg.WebServerKey == "" {
|
||||||
log.Printf("[INFO] No webserver certificate configured, automatically generating self signed certificate.")
|
log.Printf("[INFO] No webserver certificate configured, automatically generating self signed certificate.")
|
||||||
@ -73,11 +73,7 @@ func httpServer(cfg *config.Config) {
|
|||||||
|
|
||||||
ah := &admissionHandler{
|
ah := &admissionHandler{
|
||||||
decoder: serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer(),
|
decoder: serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer(),
|
||||||
config: cfg,
|
config: &cfg,
|
||||||
}
|
|
||||||
|
|
||||||
wh := &webHandler{
|
|
||||||
config: cfg,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pod admission
|
// pod admission
|
||||||
@ -87,18 +83,14 @@ func httpServer(cfg *config.Config) {
|
|||||||
// pod mutation
|
// pod mutation
|
||||||
path.HandleFunc("/api/v1/mutate/pod", ah.ahServe(operations.PodsMutation()))
|
path.HandleFunc("/api/v1/mutate/pod", ah.ahServe(operations.PodsMutation()))
|
||||||
// web root
|
// web root
|
||||||
path.HandleFunc("/", wh.webServe())
|
path.HandleFunc("/", webServe())
|
||||||
|
|
||||||
if err := connection.ListenAndServeTLS("", ""); err != nil {
|
if err := connection.ListenAndServeTLS("", ""); err != nil {
|
||||||
log.Fatalf("[ERROR] %s\n", err)
|
log.Fatalf("[ERROR] %s\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type webHandler struct {
|
func webServe() http.HandlerFunc {
|
||||||
config *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *webHandler) webServe() http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
httpAccessLog(r)
|
httpAccessLog(r)
|
||||||
crossSiteOrigin(w)
|
crossSiteOrigin(w)
|
||||||
@ -112,7 +104,7 @@ func (h *webHandler) webServe() http.HandlerFunc {
|
|||||||
case r.URL.Path == "/healthcheck":
|
case r.URL.Path == "/healthcheck":
|
||||||
tmpltHealthCheck(w)
|
tmpltHealthCheck(w)
|
||||||
case r.URL.Path == "/":
|
case r.URL.Path == "/":
|
||||||
tmpltWebRoot(w, r.URL.Query(), *h.config)
|
tmpltWebRoot(w, r.URL.Query())
|
||||||
default:
|
default:
|
||||||
msg := fmt.Sprintf("Unable to locate requested path: '%s'", r.URL.Path)
|
msg := fmt.Sprintf("Unable to locate requested path: '%s'", r.URL.Path)
|
||||||
log.Printf("[DEBUG] %s", msg)
|
log.Printf("[DEBUG] %s", msg)
|
||||||
@ -170,7 +162,7 @@ func (h *admissionHandler) ahServe(hook operations.Hook) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := hook.Execute(review.Request, h.config)
|
result, err := hook.Execute(review.Request, &cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := err.Error()
|
msg := err.Error()
|
||||||
log.Printf("[ERROR] Internal Server Error: %s", msg)
|
log.Printf("[ERROR] Internal Server Error: %s", msg)
|
||||||
|
@ -7,8 +7,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"mutating-webhook/internal/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const cT string = "Content-Type"
|
const cT string = "Content-Type"
|
||||||
@ -56,7 +54,7 @@ func tmpltHealthCheck(w http.ResponseWriter) {
|
|||||||
w.Write(output) //nolint:errcheck
|
w.Write(output) //nolint:errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
func tmpltWebRoot(w http.ResponseWriter, urlPrams url.Values, cfg config.Config) {
|
func tmpltWebRoot(w http.ResponseWriter, urlPrams url.Values) {
|
||||||
o := struct {
|
o := struct {
|
||||||
Application string `json:"application" yaml:"application"`
|
Application string `json:"application" yaml:"application"`
|
||||||
Description string `json:"description" yaml:"description"`
|
Description string `json:"description" yaml:"description"`
|
||||||
|
@ -10,6 +10,9 @@ import (
|
|||||||
"mutating-webhook/internal/config"
|
"mutating-webhook/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// global configuration
|
||||||
|
var cfg config.Config
|
||||||
|
|
||||||
func forever() {
|
func forever() {
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||||
@ -24,9 +27,9 @@ func main() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// initialize application configuration
|
// initialize application configuration
|
||||||
cfg := config.Init()
|
cfg = config.Init()
|
||||||
|
|
||||||
go httpServer(cfg)
|
go httpServer()
|
||||||
|
|
||||||
forever()
|
forever()
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,8 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig initializes the config variable for use with a prepared set of defaults.
|
// DefaultConfig initializes the config variable for use with a prepared set of defaults.
|
||||||
func DefaultConfig() *Config {
|
func DefaultConfig() Config {
|
||||||
return &Config{
|
return Config{
|
||||||
Log: &logutils.LevelFilter{
|
Log: &logutils.LevelFilter{
|
||||||
Levels: []logutils.LogLevel{"TRACE", "DEBUG", "INFO", "WARNING", "ERROR"},
|
Levels: []logutils.LogLevel{"TRACE", "DEBUG", "INFO", "WARNING", "ERROR"},
|
||||||
Writer: os.Stderr,
|
Writer: os.Stderr,
|
||||||
@ -50,7 +50,7 @@ func DefaultConfig() *Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) setLogLevel() {
|
func setLogLevel(cfg Config) {
|
||||||
switch {
|
switch {
|
||||||
case cfg.LogLevel <= 20:
|
case cfg.LogLevel <= 20:
|
||||||
cfg.Log.SetMinLevel(logutils.LogLevel("ERROR"))
|
cfg.Log.SetMinLevel(logutils.LogLevel("ERROR"))
|
||||||
@ -66,7 +66,7 @@ func (cfg *Config) setLogLevel() {
|
|||||||
log.SetOutput(cfg.Log)
|
log.SetOutput(cfg.Log)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) printRunningConfig(cfgInfo []StructInfo) {
|
func printRunningConfig(cfg *Config, cfgInfo []StructInfo) {
|
||||||
log.Printf("[DEBUG] Current Running Configuration Values:")
|
log.Printf("[DEBUG] Current Running Configuration Values:")
|
||||||
for _, info := range cfgInfo {
|
for _, info := range cfgInfo {
|
||||||
switch info.Type.String() {
|
switch info.Type.String() {
|
||||||
|
@ -19,10 +19,10 @@ func getOSEnv(env, def string) string {
|
|||||||
// Init initializes the application configuration by reading default values from the struct's tags
|
// Init initializes the application configuration by reading default values from the struct's tags
|
||||||
// and environment variables. Tags processed by this process are as follows:
|
// and environment variables. Tags processed by this process are as follows:
|
||||||
// `ignored:"true" env:"ENVIRONMENT_VARIABLE" default:"default value"`
|
// `ignored:"true" env:"ENVIRONMENT_VARIABLE" default:"default value"`
|
||||||
func Init() *Config {
|
func Init() Config {
|
||||||
cfg := DefaultConfig()
|
cfg := DefaultConfig()
|
||||||
|
|
||||||
cfgInfo, err := getStructInfo(cfg)
|
cfgInfo, err := getStructInfo(&cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("[FATAL] %v", err)
|
log.Fatalf("[FATAL] %v", err)
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ func Init() *Config {
|
|||||||
if info.DefaultValue != nil {
|
if info.DefaultValue != nil {
|
||||||
dv = info.DefaultValue.(string)
|
dv = info.DefaultValue.(string)
|
||||||
}
|
}
|
||||||
p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*string)
|
p := reflect.ValueOf(&cfg).Elem().FieldByName(info.Name).Addr().Interface().(*string)
|
||||||
flag.StringVar(p, info.Name, dv, "("+info.Key+")")
|
flag.StringVar(p, info.Name, dv, "("+info.Key+")")
|
||||||
|
|
||||||
case "bool":
|
case "bool":
|
||||||
@ -42,7 +42,7 @@ func Init() *Config {
|
|||||||
if info.DefaultValue != nil {
|
if info.DefaultValue != nil {
|
||||||
dv = info.DefaultValue.(bool)
|
dv = info.DefaultValue.(bool)
|
||||||
}
|
}
|
||||||
p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*bool)
|
p := reflect.ValueOf(&cfg).Elem().FieldByName(info.Name).Addr().Interface().(*bool)
|
||||||
flag.BoolVar(p, info.Name, dv, "("+info.Key+")")
|
flag.BoolVar(p, info.Name, dv, "("+info.Key+")")
|
||||||
|
|
||||||
case "int":
|
case "int":
|
||||||
@ -50,14 +50,14 @@ func Init() *Config {
|
|||||||
if info.DefaultValue != nil {
|
if info.DefaultValue != nil {
|
||||||
dv = int(info.DefaultValue.(int64))
|
dv = int(info.DefaultValue.(int64))
|
||||||
}
|
}
|
||||||
p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*int)
|
p := reflect.ValueOf(&cfg).Elem().FieldByName(info.Name).Addr().Interface().(*int)
|
||||||
flag.IntVar(p, info.Name, dv, "("+info.Key+")")
|
flag.IntVar(p, info.Name, dv, "("+info.Key+")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// set logging level
|
// set logging level
|
||||||
cfg.setLogLevel()
|
setLogLevel(cfg)
|
||||||
|
|
||||||
// timezone & format configuration
|
// timezone & format configuration
|
||||||
cfg.TZoneUTC, _ = time.LoadLocation("UTC")
|
cfg.TZoneUTC, _ = time.LoadLocation("UTC")
|
||||||
@ -71,7 +71,7 @@ func Init() *Config {
|
|||||||
time.Now().Format(cfg.TimeFormat)
|
time.Now().Format(cfg.TimeFormat)
|
||||||
|
|
||||||
// print running config
|
// print running config
|
||||||
cfg.printRunningConfig(cfgInfo)
|
printRunningConfig(&cfg, cfgInfo)
|
||||||
|
|
||||||
// read config file
|
// read config file
|
||||||
configFileData, err := getConfigFileData(cfg.ConfigFile)
|
configFileData, err := getConfigFileData(cfg.ConfigFile)
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
package operations
|
package operations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mutating-webhook/internal/config"
|
|
||||||
|
|
||||||
admission "k8s.io/api/admission/v1"
|
admission "k8s.io/api/admission/v1"
|
||||||
|
|
||||||
|
"mutating-webhook/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DeploymentsValidation() Hook {
|
func DeploymentsValidation() Hook {
|
||||||
return Hook{
|
return Hook{
|
||||||
// default allow
|
// default allow
|
||||||
Create: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Create: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
Delete: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Delete: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
Update: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Update: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
Connect: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Connect: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ package operations
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"mutating-webhook/internal/config"
|
|
||||||
|
|
||||||
admission "k8s.io/api/admission/v1"
|
admission "k8s.io/api/admission/v1"
|
||||||
|
|
||||||
|
"mutating-webhook/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Result contains the result of an admission request
|
// Result contains the result of an admission request
|
||||||
@ -18,7 +18,7 @@ type Result struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AdmitFunc defines how to process an admission request
|
// AdmitFunc defines how to process an admission request
|
||||||
type AdmitFunc func(request *admission.AdmissionRequest, cfg config.Config) (*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.
|
// Hook represents the set of functions for each operation in an admission webhook.
|
||||||
type Hook struct {
|
type Hook struct {
|
||||||
@ -32,19 +32,19 @@ type Hook struct {
|
|||||||
func (h *Hook) Execute(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
func (h *Hook) Execute(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
switch r.Operation {
|
switch r.Operation {
|
||||||
case admission.Create:
|
case admission.Create:
|
||||||
return wrapperExecution(h.Create, r, *cfg)
|
return wrapperExecution(h.Create, r, cfg)
|
||||||
case admission.Update:
|
case admission.Update:
|
||||||
return wrapperExecution(h.Update, r, *cfg)
|
return wrapperExecution(h.Update, r, cfg)
|
||||||
case admission.Delete:
|
case admission.Delete:
|
||||||
return wrapperExecution(h.Delete, r, *cfg)
|
return wrapperExecution(h.Delete, r, cfg)
|
||||||
case admission.Connect:
|
case admission.Connect:
|
||||||
return wrapperExecution(h.Connect, r, *cfg)
|
return wrapperExecution(h.Connect, r, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Result{Msg: fmt.Sprintf("Invalid operation: %s", r.Operation)}, nil
|
return &Result{Msg: fmt.Sprintf("Invalid operation: %s", r.Operation)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapperExecution(fn AdmitFunc, r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
func wrapperExecution(fn AdmitFunc, r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
return nil, fmt.Errorf("operation %s is not registered", r.Operation)
|
return nil, fmt.Errorf("operation %s is not registered", r.Operation)
|
||||||
}
|
}
|
||||||
|
@ -3,30 +3,30 @@ package operations
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"mutating-webhook/internal/config"
|
|
||||||
|
|
||||||
admission "k8s.io/api/admission/v1"
|
admission "k8s.io/api/admission/v1"
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
"mutating-webhook/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PodsMutation() Hook {
|
func PodsMutation() Hook {
|
||||||
return Hook{
|
return Hook{
|
||||||
Create: podMutationCreate(),
|
Create: podMutationCreate(),
|
||||||
// default allow
|
// default allow
|
||||||
Delete: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Delete: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
Update: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Update: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
Connect: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Connect: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func podMutationCreate() AdmitFunc {
|
func podMutationCreate() AdmitFunc {
|
||||||
return func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
return func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
var operations []PatchOperation
|
var operations []PatchOperation
|
||||||
pod, err := parsePod(r.Object.Raw)
|
pod, err := parsePod(r.Object.Raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4,31 +4,31 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"mutating-webhook/internal/config"
|
|
||||||
|
|
||||||
admission "k8s.io/api/admission/v1"
|
admission "k8s.io/api/admission/v1"
|
||||||
|
|
||||||
|
"mutating-webhook/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PodsValidation() Hook {
|
func PodsValidation() Hook {
|
||||||
return Hook{
|
return Hook{
|
||||||
// default allow
|
// default allow
|
||||||
Create: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Create: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
Delete: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Delete: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
Update: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Update: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
Connect: func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
Connect: func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
return &Result{Allowed: true}, nil
|
return &Result{Allowed: true}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func podValidationCreate() AdmitFunc {
|
func podValidationCreate() AdmitFunc {
|
||||||
return func(r *admission.AdmissionRequest, cfg config.Config) (*Result, error) {
|
return func(r *admission.AdmissionRequest, cfg *config.Config) (*Result, error) {
|
||||||
pod, err := parsePod(r.Object.Raw)
|
pod, err := parsePod(r.Object.Raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Result{Msg: err.Error()}, nil
|
return &Result{Msg: err.Error()}, nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user