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