sdk

package module
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 24, 2024 License: Apache-2.0 Imports: 8 Imported by: 16

README

Stable GoDoc

Don't forget to take a look at Kubewarden's official documentation. The docs cover step-by-step instructions about how to write policies.

Kubewarden Go Policy SDK

This module provides a SDK that can be used to write Kubewarden Policies using the Go programming language.

Due to current Go compiler limitations, Go policies must be built using TinyGo.

Known limitations of TinyGo

TinyGo doesn't have full support of the Go Standard Library. However, this shouldn't pose a limit to policy authors.

Validation

This SDK provides helper methods to accept and reject validation requests.

A validation policy consists of these steps:

  1. Extract the object to inspect from the incoming payload
  2. (Optional) Extract the settings object from the incoming payload.
  3. Validation code
  4. Communicate the outcome of the validation: accept/reject

The 4th step is done using helper functions provided by this SDK.

As for the 1st step, there are two approaches that can be used.

Perform "jq-like" searches

The policy receives as input a payload parameter of type []byte. This contains the JSON document described here.

Policy authors can leverage the github.com/tidwall/gjson package to search for data inside of this JSON document.

For example, assume you want to validate the labels that are inside of a Kubernetes object. This can be done with this snippet:

data := gjson.GetBytes(
  payload,
  "request.object.metadata.labels")

labels := mapset.NewThreadUnsafeSet()
denied_labels_violations := []string{}
constrained_labels_violations := []string{}

data.ForEach(func(key, value gjson.Result) bool {
  label := key.String()
  labelValue := value.String()
  // do something with label and labelValue

  return true
})

This "jq-like" approach can be pretty handy when the policy has to look deep inside of a Kubernetes object. This is especially helpful when dealing with inner objects that are optional.

Use native Go types

The majority of policies target a specific type of Kubernetes resource, like Pod, Ingress, Service and similar. Because of that, another possible approach is to unmarshal the incoming object into a native Go type.

TinyGo doesn't yet support the full Go Standard Library, plus it has limited support of Go reflection. Because of that, it is not possible to import the official Kubernetes Go library from upstream (e.g.: k8s.io/api/core/v1). Importing these official Kubernetes types will result in a compilation failure.

Moreover, Kubewarden provides TinyGo friendly Go types for all the Kubernetes types inside of the github.com/kubewarden/k8s-objects package.

Using this SDK requires TinyGo 0.28.1 or later.

Warning Using an older version of TinyGo will result in runtime errors due to the limited support for Go reflection.

Example

This snippet shows how to implement a validation function that uses the "native Go types" approach:

// 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(400))
}

// Access the **raw** JSON that describes the object
ingressJSON := validationRequest.Request.Object

// Try to create an Ingress instance using the RAW JSON we got from the
// ValidationRequest.
// This policy works only against Ingress objects, if the creation fails
// we reject the request and provide a meaningful error.
ingress := &networkingv1.Ingress{}
if err := json.Unmarshal([]byte(ingressJSON), ingress); err != nil {
	return kubewarden.RejectRequest(
		kubewarden.Message(
		fmt.Sprintf("Cannot decode Ingress object: %s", err.Error())),
		kubewarden.Code(400))
}

// the validation logic

Note: the github.com/kubewarden/k8s-objects package is organized in the same way as the official k8s.io one.

Mutating policy

Mutation policies works exactly like the validation ones. The only difference is that, when a request has to be accepted AND mutated, the policy must return the input object with all the required changes applied.

Mutation policies can be done by leveraging the Kubernetes Go types defined inside of the github.com/kubewarden/k8s-objects package and the helper methods provided by this SDK.

The following example defines a mutating policy that always changes the name of Ingress objects:

import (
    "encoding/json"
	"fmt"

	networkingv1 "github.com/kubewarden/k8s-objects/api/networking/v1"
	kubewarden "github.com/kubewarden/policy-sdk-go"

)

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(400))
  }

  // Access the **raw** JSON that describes the object
  ingressJSON := validationRequest.Request.Object

  // Try to create a Ingress instance using the RAW JSON we got from the
  // ValidationRequest.
  // This policy works only against Ingress objects, if the creation fails
  // we reject the request and provide a meaningful error.
  ingress := &networkingv1.Ingress{}
  if err := json.Unmarshal([]byte(ingressJSON), ingress); err != nil {
    return kubewarden.RejectRequest(
      kubewarden.Message(
      fmt.Sprintf("Cannot decode Ingress object: %s", err.Error())),
      kubewarden.Code(400))
  }

  ingress.Metadata.Name = fmt.Sprintf("%s-changed", ingress.Metadata.Name)

  return kubewarden.MutateRequest(ingress)
}

Logging

Policies can generate log messages that are then propagated to the host environment (eg: kwctl, policy-server).

This Go module provides logging capabilities that integrate with the onelog project.

This logging solution has been chosen because:

  • It works also with WebAssembly binaries. Other popular logging solutions cannot even be built to WebAssembly.
  • It provides good performance
  • It supports structured logging.

Usage

The instructions provided by the official onelog project apply also to Kubewarden policies.

The onelog.Logger instance must be configured to use a KubewardenLogWriter object.

	kl := kubewarden.KubewardenLogWriter{}
	logger := onelog.New(
		&kl,
		onelog.ALL, // shortcut for onelog.DEBUG|onelog.INFO|onelog.WARN|onelog.ERROR|onelog.FATAL,
	)
	logger.Info("info message from tinygo")
	logger.DebugWithFields("i'm not sure what's going on", func(e onelog.Entry) {
		e.String("string", "foobar")
		e.Int("int", 12345)
		e.Int64("int64", 12345)
		e.Float("float64", 0.15)
		e.Bool("bool", true)
		e.Err("err", errors.New("someError"))
		e.ObjectFunc("user", func(e onelog.Entry) {
			e.String("name", "somename")
		})
	})

Host capabilities

The policy executor exposes additional capabilities that can be leveraged by the guest.

These capabilities are exposed to the Go policies via this SDK, through the Host type defined inside of github.com/kubewarden/policy-sdk-go/capabilities.

Get OCI manifest digest

The policy can request the digest of an OCI manifest. This can be used to get the immutable reference of a container Image or anything that is stored inside of a container registry (e.g. Kubewarden Policies, Helm charts,...).

host := capabilities.NewHost()
digest, err := host.GetOCIManifestDigest("busybox:latest")

Hostname DNS lookup

The policy can lookup the addresses for a given hostname by using the DNS resolvers of the host that is evaluating the policy.

host := capabilities.NewHost()
ips, err := host.LookupHost("kubewarden.io")

Sigstore verification

The policy can ask the host to perform verification operations against objects stored inside of container registries (e.g. container image, kubewarden policy, helm chart,...) leveraging the Sigstore primitives.

Currently this SDK exposes helper function that can perform verification using public keys and using the Sigstore keyless mechanism.

Testing

GoDoc

The kubewarden/policy-sdk-go/testing module provides some test helpers that simplify the process of writing unit tests.

Host capabilities

The Go unit tests of a policy are not run inside of a WebAssembly environment, they are instead built into a native executable using the official Go compiler.

Because of that, at test time the host capabilities have to be mocked. This is also useful to write ad-hoc tests that can handle different kind of responses coming from the host.

The Host type described above relies on an internal waPC client that interacts with the host. At test time, the client is an instance of MockWapcClient.

Developers can create MockWapcClient instances using these two helper methods:

  • NewSuccessfulMockWapcClient: the client never fails, and always return the response payload provided by the user.
  • NewFailingMockWapcClient: the client always fails with the error provided by the user.

Project template

We provide a GitHub repository template that can be used to quickly scaffold a new Kubewarden policy writing Go.

This can be found here.

Documentation

Overview

This package provides helper functions and structs for writing https://kubewarden.io policies using the Go programming language.

Index

Constants

View Source
const (
	// NoMessage can be used when building a response that doesn't have any
	// message to be shown to the user
	NoMessage Message = ""

	// NoCode can be used when building a response that doesn't have any
	// error code to be shown to the user
	NoCode Code = 0
)

Variables

This section is empty.

Functions

func AcceptRequest

func AcceptRequest() ([]byte, error)

AcceptRequest can be used inside of the `validate` function to accept the incoming request

func AcceptSettings added in v0.0.3

func AcceptSettings() ([]byte, error)

AcceptSettings can be used inside of the `validate_settings` function to mark the user provided settings as valid

func ExtractPodSpecFromObject added in v0.2.4

func ExtractPodSpecFromObject(object protocol.ValidationRequest) (corev1.PodSpec, error)

Extract PodSpec from high level objects. This method can be used to evaluate high level objects instead of just Pods. For example, it can be used to reject Deployments or StatefulSets that violate a policy instead of the Pods created by them. Objects supported are: Deployment, ReplicaSet, StatefulSet, DaemonSet, ReplicationController, Job, CronJob, Pod It returns an error if the object is not one of those. If it is a supported object it returns the PodSpec if present, otherwise returns an empty PodSpec. * `object`: the request to validate

func MutatePodSpecFromRequest added in v0.2.4

func MutatePodSpecFromRequest(validationRequest protocol.ValidationRequest, podSepc corev1.PodSpec) ([]byte, error)

Update the pod spec from the resource defined in the original object and create an acceptance response. * `validation_request` - the original admission request * `pod_spec` - new PodSpec to be set in the response

func MutateRequest added in v0.2.0

func MutateRequest(newObject interface{}) ([]byte, error)

Accept the request and mutate the final object to match the one provided via the `newObject` param

func RejectRequest

func RejectRequest(message Message, code Code) ([]byte, error)

RejectRequest can be used inside of the `validate` function to reject the incoming request * `message`: optional message to show to the user * `code`: optional error code to show to the user

func RejectSettings added in v0.0.3

func RejectSettings(message Message) ([]byte, error)

RejectSettings can be used inside of the `validate_settings` function to mark the user provided settings as invalid * `message`: optional message to show to the user

Types

type Code

type Code uint16

Code is the optional error code associated with validation responses

type KubewardenLogWriter added in v0.1.2

type KubewardenLogWriter struct {
	// contains filtered or unexported fields
}

KubewardenLogWriter is a simple log collector that can be used with a `onelog.Logger` instance.

KubewardenLogWriter will send the logs from the WebAssembly guest (the policy) to the WebAssembly host (kwct, policy-server).

KubewardenLogWriter will write the log events to the standard output when the binary is NOT built for the WebAssembly target. This is useful for running native unit tests of policies.

func (*KubewardenLogWriter) Write added in v0.1.2

func (k *KubewardenLogWriter) Write(p []byte) (n int, err error)

type Message

type Message string

Message is the optional string used to build validation responses

Directories

Path Synopsis
pkg
capabilities
This package provides access to the structs and functions offered by the Kubewarden host.
This package provides access to the structs and functions offered by the Kubewarden host.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL