pkg/webhook
whaught d22642244e
Allow Unstructured callback from Validating Webhook (#1172)
* Add new callback pattern to pkg

* include the context

* typo

* Remove the empty instance of unstructured

* initialize the unstructured var

* Eliminate the unneeded pointer

* Pass a pointer to unstructured callback

* Create a validation specific context struct

* Move callback tests to own unit test case

* Switch from converting to decoding

* Update webhook/resourcesemantics/validation/validation.go

Co-Authored-By: Victor Agababov <vagababov@gmail.com>

* don't wrap context and include params

* split validation files

* include 2020 copyright

* include unit test for WithKubeClient

* Don't bother updating copyright date

* Inclue a unit test for panic

* Move dryRun to context

* Include context dry run unit test

* put the request operation in the context

* eliminate circular dep

* move kubeclient test out of context_test

* dont bother iterating callback map

* Callback takes a list of supported verbs

* Remove extra type

* Ensure Callback interface is public

* Alias Operation into validation

* alias Operation right in Webhook

* Update webhook/resourcesemantics/validation/validation_admit.go

Co-Authored-By: Victor Agababov <vagababov@gmail.com>

* Update webhook/resourcesemantics/validation/validation_admit_test.go

Co-Authored-By: Victor Agababov <vagababov@gmail.com>

* Update webhook/resourcesemantics/validation/validation_admit_test.go

Co-Authored-By: Victor Agababov <vagababov@gmail.com>

* Update webhook/resourcesemantics/validation/validation_admit.go

Co-Authored-By: Victor Agababov <vagababov@gmail.com>

* Update webhook/resourcesemantics/validation/validation_admit.go

Co-Authored-By: Victor Agababov <vagababov@gmail.com>

* Update webhook/resourcesemantics/validation/validation_admit_test.go

Co-Authored-By: Victor Agababov <vagababov@gmail.com>

* correct parens

* minor style fixes

* Rename Callback to Func

* Fix build error

* Switch callback to take a list with a factory

* keep descriptive names

* update comment

* Drop pointer, correct comments

* Add a unit test to disallow duplicate verbs

* fix comments, struct{} for set

* switch to variadic arg for NewCallback

Co-authored-by: Victor Agababov <vagababov@gmail.com>
2020-04-06 12:22:19 -07:00
..
certificates Drop the logic to create missing secrets. (#1154) 2020-03-16 11:36:31 -07:00
configmaps Start the webhook before informers sync. (#1180) 2020-03-30 18:14:50 -07:00
psbinding Fix a few simple linter warnings: unused code, govet warnings etc. (#1191) 2020-04-06 08:21:20 -07:00
resourcesemantics Allow Unstructured callback from Validating Webhook (#1172) 2020-04-06 12:22:19 -07:00
testing Allow Unstructured callback from Validating Webhook (#1172) 2020-04-06 12:22:19 -07:00
OWNERS Update OWNERS to use OWNERS_ALIASES (#422) 2019-05-29 20:04:33 -07:00
README.md Format markdown (#875) 2019-11-13 15:08:28 -08:00
admission.go Start the webhook before informers sync. (#1180) 2020-03-30 18:14:50 -07:00
admission_integration_test.go t.Fatal must not be called in a goroutine. (#1194) 2020-04-06 08:27:19 -07:00
context.go Streamline `webhook.New`. (#821) 2019-10-28 16:12:11 -07:00
conversion.go Fix some nits in the webhook code (#1150) 2020-03-10 10:36:29 -07:00
conversion_integration_test.go Conversion Webhook Framework (#993) 2020-02-03 08:59:29 -08:00
helper_test.go This refactors our core webhook logic to be reconciler-based. (#833) 2019-10-31 10:17:13 -07:00
stats_reporter.go Use new RecordBatch method to join metric reporting (#1029) 2020-02-03 16:27:30 -08:00
stats_reporter_test.go Avoid registering webhook metrics with init() (#826) 2019-10-28 22:02:11 -07:00
webhook.go Allow Unstructured callback from Validating Webhook (#1172) 2020-04-06 12:22:19 -07:00
webhook_integration_test.go Start the webhook before informers sync. (#1180) 2020-03-30 18:14:50 -07:00
webhook_test.go Fix a few simple linter warnings: unused code, govet warnings etc. (#1191) 2020-04-06 08:21:20 -07:00

README.md

Knative Webhooks

Knative provides infrastructure for authoring webhooks under knative.dev/pkg/webhook and has a few built-in helpers for certain common admission control scenarios. The built-in admission controllers are:

  1. Resource validation and defaulting (builds around apis.Validatable and apis.Defaultable under knative.dev/pkg/apis).
  2. ConfigMap validation, which builds around similar patterns from knative.dev/pkg/configmap (in particular the store concept)

To illustrate standing up the webhook, let's start with one of these built-in admission controllers and then talk about how you can write your own admission controller.

Standing up a Webhook from an Admission Controller

We provide facilities in knative.dev/pkg/injection/sharedmain to try and eliminate much of the boilerplate involved in standing up a webhook. For this example we will show how to stand up the webhook using the built-in admission controller for validating and defaulting resources.

The code to stand up such a webhook looks roughly like this:

// Create a function matching this signature to pass into sharedmain.
func NewResourceAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
	return resourcesemantics.NewAdmissionController(ctx,
		// Name of the resource webhook (created via yaml)
		fmt.Sprintf("resources.webhook.%s.knative.dev", system.Namespace()),

		// The path on which to serve the webhook.
		"/resource-validation",

		// The resources to validate and default.
		map[schema.GroupVersionKind]resourcesemantics.GenericCRD{
			// List the types to validate, this from knative.dev/sample-controller
			v1alpha1.SchemeGroupVersion.WithKind("AddressableService"): &v1alpha1.AddressableService{},
		},

		// A function that infuses the context passed to Validate/SetDefaults with custom metadata.
		func(ctx context.Context) context.Context {
			// Here is where you would infuse the context with state
			// (e.g. attach a store with configmap data, like knative.dev/serving attaches config-defaults)
			return ctx
		},

		// Whether to disallow unknown fields when parsing the resources' JSON.
		true,
	)
}

func main() {
	// Set up a signal context with our webhook options.
	ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{
		// The name of the Kubernetes service selecting over this deployment's pods.
		ServiceName: "webhook",

		// The port on which to serve.
		Port:        8443,

		// The name of the secret containing certificate data.
		SecretName:  "webhook-certs",
	})

	sharedmain.MainWithContext(ctx, "webhook",
		// The certificate controller will ensure that the named secret (above) has
		// the appropriate shape for our webhook's admission controllers.
		certificates.NewController,

		// This invokes the method defined above to instantiate the resource admission
		// controller.
		NewResourceAdmissionController,
	)
}

There is also a config map validation admission controller built in under knative.dev/pkg/webhook/configmaps.

Writing new Admission Controllers

To implement your own admission controller akin to the resource defaulting and validation controller above, you implement a knative.dev/pkg/controller.Reconciler as with any you would with any other type of controller, but the Reconciler that gets embedded in the *controller.Impl should also implement:

// AdmissionController provides the interface for different admission controllers
type AdmissionController interface {
	// Path returns the path that this particular admission controller serves on.
	Path() string

	// Admit is the callback which is invoked when an HTTPS request comes in on Path().
	Admit(context.Context, *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse
}

The Reconciler part is responsible for the mutating or validating webhook configuration. The AdmissionController part is responsible for guiding request dispatch (Path()) and handling admission requests (Admit()).