diff --git a/pkg/admission/initializer/interfaces.go b/pkg/admission/initializer/interfaces.go index 233d88006..21202bd79 100644 --- a/pkg/admission/initializer/interfaces.go +++ b/pkg/admission/initializer/interfaces.go @@ -18,8 +18,8 @@ package initializer import ( "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/admission/resourcefilter" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/cel/openapi/resolver" quota "k8s.io/apiserver/pkg/quota/v1" @@ -91,9 +91,9 @@ type WantsSchemaResolver interface { admission.InitializationValidator } -// WantsResourceFilter defines a function which sets the ResourceFilter for -// an admission plugin that needs it. -type WantsResourceFilter interface { - SetResourceFilter(filter resourcefilter.Interface) +// WantsExcludedAdmissionResources defines a function which sets the ExcludedAdmissionResources +// for an admission plugin that needs it. +type WantsExcludedAdmissionResources interface { + SetExcludedAdmissionResources(excludedAdmissionResources []schema.GroupResource) admission.InitializationValidator } diff --git a/pkg/admission/plugin/policy/generic/plugin.go b/pkg/admission/plugin/policy/generic/plugin.go index 3e6faa644..ed1c621bc 100644 --- a/pkg/admission/plugin/policy/generic/plugin.go +++ b/pkg/admission/plugin/policy/generic/plugin.go @@ -21,12 +21,14 @@ import ( "errors" "fmt" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/initializer" "k8s.io/apiserver/pkg/admission/plugin/policy/matching" - "k8s.io/apiserver/pkg/admission/resourcefilter" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/client-go/dynamic" "k8s.io/client-go/informers" @@ -37,6 +39,15 @@ import ( type sourceFactory[H any] func(informers.SharedInformerFactory, kubernetes.Interface, dynamic.Interface, meta.RESTMapper) Source[H] type dispatcherFactory[H any] func(authorizer.Authorizer, *matching.Matcher) Dispatcher[H] +// admissionResources is the list of resources related to CEL-based admission +// features. +var admissionResources = []schema.GroupResource{ + {Group: admissionregistrationv1.GroupName, Resource: "validatingadmissionpolicies"}, + {Group: admissionregistrationv1.GroupName, Resource: "validatingadmissionpolicybindings"}, + {Group: admissionregistrationv1.GroupName, Resource: "mutatingadmissionpolicies"}, + {Group: admissionregistrationv1.GroupName, Resource: "mutatingadmissionpolicybindings"}, +} + // AdmissionPolicyManager is an abstract admission plugin with all the // infrastructure to define Admit or Validate on-top. type Plugin[H any] struct { @@ -49,14 +60,14 @@ type Plugin[H any] struct { dispatcher Dispatcher[H] matcher *matching.Matcher - informerFactory informers.SharedInformerFactory - client kubernetes.Interface - restMapper meta.RESTMapper - dynamicClient dynamic.Interface - resourceFilter resourcefilter.Interface // optional - stopCh <-chan struct{} - authorizer authorizer.Authorizer - enabled bool + informerFactory informers.SharedInformerFactory + client kubernetes.Interface + restMapper meta.RESTMapper + dynamicClient dynamic.Interface + excludedResources sets.Set[schema.GroupResource] + stopCh <-chan struct{} + authorizer authorizer.Authorizer + enabled bool } var ( @@ -66,7 +77,7 @@ var ( _ initializer.WantsDynamicClient = &Plugin[any]{} _ initializer.WantsDrainedNotification = &Plugin[any]{} _ initializer.WantsAuthorizer = &Plugin[any]{} - _ initializer.WantsResourceFilter = &Plugin[any]{} + _ initializer.WantsExcludedAdmissionResources = &Plugin[any]{} _ admission.InitializationValidator = &Plugin[any]{} ) @@ -79,6 +90,9 @@ func NewPlugin[H any]( Handler: handler, sourceFactory: sourceFactory, dispatcherFactory: dispatcherFactory, + + // always exclude admission/mutating policies and bindings + excludedResources: sets.New(admissionResources...), } } @@ -114,8 +128,8 @@ func (c *Plugin[H]) SetEnabled(enabled bool) { c.enabled = enabled } -func (c *Plugin[H]) SetResourceFilter(filter resourcefilter.Interface) { - c.resourceFilter = filter +func (c *Plugin[H]) SetExcludedAdmissionResources(excludedResources []schema.GroupResource) { + c.excludedResources.Insert(excludedResources...) } // ValidateInitialization - once clientset and informer factory are provided, creates and starts the admission controller @@ -184,7 +198,7 @@ func (c *Plugin[H]) Dispatch( ) (err error) { if !c.enabled { return nil - } else if isPolicyResource(a) || (c.resourceFilter != nil && !c.resourceFilter.ShouldHandle(a)) { + } else if c.shouldIgnoreResource(a) { return nil } else if !c.WaitForReady() { return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request")) @@ -193,14 +207,9 @@ func (c *Plugin[H]) Dispatch( return c.dispatcher.Dispatch(ctx, a, o, c.source.Hooks()) } -func isPolicyResource(attr admission.Attributes) bool { - gvk := attr.GetResource() - if gvk.Group == "admissionregistration.k8s.io" { - if gvk.Resource == "validatingadmissionpolicies" || gvk.Resource == "validatingadmissionpolicybindings" { - return true - } else if gvk.Resource == "mutatingadmissionpolicies" || gvk.Resource == "mutatingadmissionpolicybindings" { - return true - } - } - return false +func (c *Plugin[H]) shouldIgnoreResource(attr admission.Attributes) bool { + gvr := attr.GetResource() + // exclusion decision ignores the version. + gr := gvr.GroupResource() + return c.excludedResources.Has(gr) } diff --git a/pkg/admission/plugin/policy/validating/plugin.go b/pkg/admission/plugin/policy/validating/plugin.go index 5880af4fe..2fae52d19 100644 --- a/pkg/admission/plugin/policy/validating/plugin.go +++ b/pkg/admission/plugin/policy/validating/plugin.go @@ -74,7 +74,7 @@ type Plugin struct { var _ admission.Interface = &Plugin{} var _ admission.ValidationInterface = &Plugin{} var _ initializer.WantsFeatures = &Plugin{} -var _ initializer.WantsResourceFilter = &Plugin{} +var _ initializer.WantsExcludedAdmissionResources = &Plugin{} func NewPlugin(_ io.Reader) *Plugin { handler := admission.NewHandler(admission.Connect, admission.Create, admission.Delete, admission.Update) diff --git a/pkg/admission/resourcefilter/interfaces.go b/pkg/admission/resourcefilter/interfaces.go deleted file mode 100644 index 23711b6df..000000000 --- a/pkg/admission/resourcefilter/interfaces.go +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2024 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 resourcefilter - -import ( - "k8s.io/apiserver/pkg/admission" -) - -// Interface is a resource filter that takes an Attributes and -// check if it should be handled or ignored by the admission plugin. -type Interface interface { - // ShouldHandle returns true if the admission plugin should handle the request, - // considering the given Attributes, or false otherwise. - ShouldHandle(admission.Attributes) bool -}