From a41a536dbdb72877fa48f85272e479eb628e68f8 Mon Sep 17 00:00:00 2001 From: Alexander Zielenski <351783+alexzielenski@users.noreply.github.com> Date: Wed, 12 Oct 2022 10:21:31 -0700 Subject: [PATCH] add cel admission plugin and initializer --- .../pkg/admission/plugin/cel/admission.go | 103 ++++++++++++++++++ .../pkg/admission/plugin/cel/initializer.go | 55 ++++++++++ 2 files changed, 158 insertions(+) create mode 100644 staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/admission.go create mode 100644 staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/initializer.go diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/admission.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/admission.go new file mode 100644 index 00000000000..50f679c857e --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/admission.go @@ -0,0 +1,103 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cel + +import ( + "context" + "errors" + "fmt" + "io" + "time" + + "k8s.io/apiserver/pkg/admission" + "k8s.io/client-go/tools/cache" +) + +//////////////////////////////////////////////////////////////////////////////// +// Plugin Definition +//////////////////////////////////////////////////////////////////////////////// + +// Definition for CEL admission plugin. This is the entry point into the +// CEL admission control system. +// +// Each plugin is asked to validate every object update. + +const ( + // PluginName indicates the name of admission plug-in + PluginName = "CEL" +) + +// Register registers a plugin +func Register(plugins *admission.Plugins) { + plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) { + return NewPlugin() + }) +} + +//////////////////////////////////////////////////////////////////////////////// +// Plugin Initialization & Dependency Injection +//////////////////////////////////////////////////////////////////////////////// + +type celAdmissionPlugin struct { + evaluator CELPolicyEvaluator +} + +var _ WantsCELPolicyEvaluator = &celAdmissionPlugin{} +var _ admission.ValidationInterface = &celAdmissionPlugin{} + +func NewPlugin() (*celAdmissionPlugin, error) { + result := &celAdmissionPlugin{} + return result, nil +} + +func (c *celAdmissionPlugin) SetCELPolicyEvaluator(evaluator CELPolicyEvaluator) { + c.evaluator = evaluator +} + +// Once clientset and informer factory are provided, creates and starts the +// admission controller +func (c *celAdmissionPlugin) ValidateInitialization() error { + if c.evaluator != nil { + return nil + } + + return errors.New("CELPolicyEvaluator not injected") +} + +//////////////////////////////////////////////////////////////////////////////// +// admission.ValidationInterface +//////////////////////////////////////////////////////////////////////////////// + +func (c *celAdmissionPlugin) Handles(operation admission.Operation) bool { + return true +} + +func (c *celAdmissionPlugin) Validate( + ctx context.Context, + a admission.Attributes, + o admission.ObjectInterfaces, +) (err error) { + + deadlined, cancel := context.WithTimeout(ctx, 2*time.Second) + defer cancel() + + if !cache.WaitForNamedCacheSync("cel-admission-plugin", deadlined.Done(), c.evaluator.HasSynced) { + return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request")) + } + + return c.evaluator.Validate(ctx, a, o) +} diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/initializer.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/initializer.go new file mode 100644 index 00000000000..18fa3e119d0 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/initializer.go @@ -0,0 +1,55 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cel + +import ( + "context" + + "k8s.io/apiserver/pkg/admission" +) + +type CELPolicyEvaluator interface { + Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error + HasSynced() bool +} + +// NewPluginInitializer creates a plugin initializer which dependency injects a +// singleton cel admission controller into the plugins which desire it +func NewPluginInitializer(validator CELPolicyEvaluator) *PluginInitializer { + return &PluginInitializer{validator: validator} +} + +// WantsCELPolicyEvaluator gives the ability to have the shared +// CEL Admission Controller dependency injected at initialization-time. +type WantsCELPolicyEvaluator interface { + SetCELPolicyEvaluator(CELPolicyEvaluator) +} + +// PluginInitializer is used for initialization of the webhook admission plugin. +type PluginInitializer struct { + validator CELPolicyEvaluator +} + +var _ admission.PluginInitializer = &PluginInitializer{} + +// Initialize checks the initialization interfaces implemented by each plugin +// and provide the appropriate initialization data +func (i *PluginInitializer) Initialize(plugin admission.Interface) { + if wants, ok := plugin.(WantsCELPolicyEvaluator); ok { + wants.SetCELPolicyEvaluator(i.validator) + } +}