Simplest Kubewarden policy written using Go.
To be compiled with TinyGo:
tinygo build -o policy.wasm -target=wasi -no-debug .For more details: https://github.com/kubewarden/go-policy-template
Simplest Kubewarden policy written using Go.
To be compiled with TinyGo:
tinygo build -o policy.wasm -target=wasi -no-debug .For more details: https://github.com/kubewarden/go-policy-template
| module github.com/kubewarden/demo | |
| go 1.22 | |
| toolchain go1.22.5 | |
| require ( | |
| github.com/francoispqt/onelog v0.0.0-20190306043706-8c2bb31b10a4 | |
| github.com/kubewarden/k8s-objects v1.29.0-kw1 | |
| github.com/kubewarden/policy-sdk-go v0.11.0 | |
| github.com/wapc/wapc-guest-tinygo v0.3.3 | |
| ) | |
| require ( | |
| github.com/francoispqt/gojay v0.0.0-20181220093123-f2cc13a668ca // indirect | |
| github.com/go-openapi/strfmt v0.21.3 // indirect | |
| ) | |
| replace github.com/go-openapi/strfmt => github.com/kubewarden/strfmt v0.1.3 |
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "strings" | |
| onelog "github.com/francoispqt/onelog" | |
| corev1 "github.com/kubewarden/k8s-objects/api/core/v1" | |
| kubewarden "github.com/kubewarden/policy-sdk-go" | |
| kubewarden_protocol "github.com/kubewarden/policy-sdk-go/protocol" | |
| wapc "github.com/wapc/wapc-guest-tinygo" | |
| ) | |
| const httpBadRequestStatusCode = 400 | |
| // This is not a good practice in general. Policy authors should avoid using global variables in the final code | |
| // | |
| //nolint:gochecknoglobals // Allowing global variables just to make the template code simple. | |
| var ( | |
| logWriter = kubewarden.KubewardenLogWriter{} | |
| logger = onelog.New( | |
| &logWriter, | |
| onelog.ALL, // shortcut for onelog.DEBUG|onelog.INFO|onelog.WARN|onelog.ERROR|onelog.FATAL | |
| ) | |
| ) | |
| func main() { | |
| wapc.RegisterFunctions(wapc.Functions{ | |
| "validate": validate, | |
| "validate_settings": validateSettings, | |
| }) | |
| } | |
| func validate(payload []byte) ([]byte, error) { | |
| // Create a ValidationRequest instance from the incoming payload | |
| validationRequest := kubewarden_protocol.ValidationRequest{} | |
| err := json.Unmarshal(payload, &validationRequest) | |
| if err != nil { | |
| return kubewarden.RejectRequest( | |
| kubewarden.Message(err.Error()), | |
| kubewarden.Code(httpBadRequestStatusCode)) | |
| } | |
| // Create a Settings instance from the ValidationRequest object | |
| settings, err := NewSettingsFromValidationReq(&validationRequest) | |
| if err != nil { | |
| return kubewarden.RejectRequest( | |
| kubewarden.Message(err.Error()), | |
| kubewarden.Code(httpBadRequestStatusCode)) | |
| } | |
| // Access the **raw** JSON that describes the object | |
| podJSON := validationRequest.Request.Object | |
| // Try to create a Pod instance using the RAW JSON we got from the | |
| // ValidationRequest. | |
| pod := &corev1.Pod{} | |
| if err = json.Unmarshal([]byte(podJSON), pod); err != nil { | |
| return kubewarden.RejectRequest( | |
| kubewarden.Message( | |
| fmt.Sprintf("Cannot decode Pod object: %s", err.Error())), | |
| kubewarden.Code(httpBadRequestStatusCode)) | |
| } | |
| logger.DebugWithFields("validating pod object", func(e onelog.Entry) { | |
| e.String("name", pod.Metadata.Name) | |
| e.String("namespace", pod.Metadata.Namespace) | |
| }) | |
| if settings.IsNameDenied(pod.Metadata.Name) { | |
| logger.InfoWithFields("rejecting pod object", func(e onelog.Entry) { | |
| e.String("name", pod.Metadata.Name) | |
| e.String("denied_names", strings.Join(settings.DeniedNames, ",")) | |
| }) | |
| return kubewarden.RejectRequest( | |
| kubewarden.Message( | |
| fmt.Sprintf("The '%s' name is on the deny list", pod.Metadata.Name)), | |
| kubewarden.NoCode) | |
| } | |
| return kubewarden.AcceptRequest() | |
| } | |
| // Settings is the structure that describes the policy settings. | |
| type Settings struct { | |
| DeniedNames []string `json:"denied_names"` | |
| } | |
| // No special checks have to be done. | |
| func (s *Settings) Valid() (bool, error) { | |
| return true, nil | |
| } | |
| func (s *Settings) IsNameDenied(name string) bool { | |
| for _, deniedName := range s.DeniedNames { | |
| if deniedName == name { | |
| return true | |
| } | |
| } | |
| return false | |
| } | |
| func NewSettingsFromValidationReq(validationReq *kubewarden_protocol.ValidationRequest) (Settings, error) { | |
| settings := Settings{} | |
| err := json.Unmarshal(validationReq.Settings, &settings) | |
| return settings, err | |
| } | |
| func validateSettings(payload []byte) ([]byte, error) { | |
| logger.Info("validating settings") | |
| settings := Settings{} | |
| err := json.Unmarshal(payload, &settings) | |
| if err != nil { | |
| return kubewarden.RejectSettings(kubewarden.Message(fmt.Sprintf("Provided settings are not valid: %v", err))) | |
| } | |
| valid, err := settings.Valid() | |
| if err != nil { | |
| return kubewarden.RejectSettings(kubewarden.Message(fmt.Sprintf("Provided settings are not valid: %v", err))) | |
| } | |
| if valid { | |
| return kubewarden.AcceptSettings() | |
| } | |
| logger.Warn("rejecting settings") | |
| return kubewarden.RejectSettings(kubewarden.Message("Provided settings are not valid")) | |
| } |