mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-10 12:32:03 +00:00
update to inject only the list of excluded resources.
This commit is contained in:
parent
e257522889
commit
6b03166bed
@ -70,7 +70,7 @@ func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselec
|
|||||||
cloudConfig,
|
cloudConfig,
|
||||||
discoveryRESTMapper,
|
discoveryRESTMapper,
|
||||||
quotainstall.NewQuotaConfigurationForAdmission(),
|
quotainstall.NewQuotaConfigurationForAdmission(),
|
||||||
exclusion.NewFilter(),
|
exclusion.Excluded(),
|
||||||
)
|
)
|
||||||
|
|
||||||
admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error {
|
admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error {
|
||||||
|
@ -1,42 +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 exclusion
|
|
||||||
|
|
||||||
import (
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
|
||||||
"k8s.io/apiserver/pkg/admission"
|
|
||||||
"k8s.io/apiserver/pkg/admission/resourcefilter"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewFilter creates a resource filter with the built-in exclusion list.
|
|
||||||
func NewFilter() resourcefilter.Interface {
|
|
||||||
return &filter{excluded: sets.New[schema.GroupResource](excluded...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
type filter struct {
|
|
||||||
excluded sets.Set[schema.GroupResource]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *filter) ShouldHandle(a admission.Attributes) bool {
|
|
||||||
gvr := a.GetResource()
|
|
||||||
// ignore the version for the decision-making
|
|
||||||
// because putting different versions into different category
|
|
||||||
// is almost always a mistake.
|
|
||||||
gr := gvr.GroupResource()
|
|
||||||
return !f.excluded.Has(gr)
|
|
||||||
}
|
|
@ -18,9 +18,9 @@ package admission
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/admission/initializer"
|
"k8s.io/apiserver/pkg/admission/initializer"
|
||||||
"k8s.io/apiserver/pkg/admission/resourcefilter"
|
|
||||||
quota "k8s.io/apiserver/pkg/quota/v1"
|
quota "k8s.io/apiserver/pkg/quota/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,10 +33,10 @@ type WantsCloudConfig interface {
|
|||||||
|
|
||||||
// PluginInitializer is used for initialization of the Kubernetes specific admission plugins.
|
// PluginInitializer is used for initialization of the Kubernetes specific admission plugins.
|
||||||
type PluginInitializer struct {
|
type PluginInitializer struct {
|
||||||
cloudConfig []byte
|
cloudConfig []byte
|
||||||
restMapper meta.RESTMapper
|
restMapper meta.RESTMapper
|
||||||
quotaConfiguration quota.Configuration
|
quotaConfiguration quota.Configuration
|
||||||
resourceFilter resourcefilter.Interface
|
excludedAdmissionResources []schema.GroupResource
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ admission.PluginInitializer = &PluginInitializer{}
|
var _ admission.PluginInitializer = &PluginInitializer{}
|
||||||
@ -48,13 +48,13 @@ func NewPluginInitializer(
|
|||||||
cloudConfig []byte,
|
cloudConfig []byte,
|
||||||
restMapper meta.RESTMapper,
|
restMapper meta.RESTMapper,
|
||||||
quotaConfiguration quota.Configuration,
|
quotaConfiguration quota.Configuration,
|
||||||
resourceFilter resourcefilter.Interface,
|
excludedAdmissionResources []schema.GroupResource,
|
||||||
) *PluginInitializer {
|
) *PluginInitializer {
|
||||||
return &PluginInitializer{
|
return &PluginInitializer{
|
||||||
cloudConfig: cloudConfig,
|
cloudConfig: cloudConfig,
|
||||||
restMapper: restMapper,
|
restMapper: restMapper,
|
||||||
quotaConfiguration: quotaConfiguration,
|
quotaConfiguration: quotaConfiguration,
|
||||||
resourceFilter: resourceFilter,
|
excludedAdmissionResources: excludedAdmissionResources,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) {
|
|||||||
wants.SetQuotaConfiguration(i.quotaConfiguration)
|
wants.SetQuotaConfiguration(i.quotaConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
if wants, ok := plugin.(initializer.WantsResourceFilter); ok {
|
if wants, ok := plugin.(initializer.WantsExcludedAdmissionResources); ok {
|
||||||
wants.SetResourceFilter(i.resourceFilter)
|
wants.SetExcludedAdmissionResources(i.excludedAdmissionResources)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ package initializer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/admission/resourcefilter"
|
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
quota "k8s.io/apiserver/pkg/quota/v1"
|
quota "k8s.io/apiserver/pkg/quota/v1"
|
||||||
@ -91,9 +91,9 @@ type WantsSchemaResolver interface {
|
|||||||
admission.InitializationValidator
|
admission.InitializationValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
// WantsResourceFilter defines a function which sets the ResourceFilter for
|
// WantsExcludedAdmissionResources defines a function which sets the ExcludedAdmissionResources
|
||||||
// an admission plugin that needs it.
|
// for an admission plugin that needs it.
|
||||||
type WantsResourceFilter interface {
|
type WantsExcludedAdmissionResources interface {
|
||||||
SetResourceFilter(filter resourcefilter.Interface)
|
SetExcludedAdmissionResources(excludedAdmissionResources []schema.GroupResource)
|
||||||
admission.InitializationValidator
|
admission.InitializationValidator
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,14 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/admission/initializer"
|
"k8s.io/apiserver/pkg/admission/initializer"
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/policy/matching"
|
"k8s.io/apiserver/pkg/admission/plugin/policy/matching"
|
||||||
"k8s.io/apiserver/pkg/admission/resourcefilter"
|
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/informers"
|
"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 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]
|
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
|
// AdmissionPolicyManager is an abstract admission plugin with all the
|
||||||
// infrastructure to define Admit or Validate on-top.
|
// infrastructure to define Admit or Validate on-top.
|
||||||
type Plugin[H any] struct {
|
type Plugin[H any] struct {
|
||||||
@ -49,14 +60,14 @@ type Plugin[H any] struct {
|
|||||||
dispatcher Dispatcher[H]
|
dispatcher Dispatcher[H]
|
||||||
matcher *matching.Matcher
|
matcher *matching.Matcher
|
||||||
|
|
||||||
informerFactory informers.SharedInformerFactory
|
informerFactory informers.SharedInformerFactory
|
||||||
client kubernetes.Interface
|
client kubernetes.Interface
|
||||||
restMapper meta.RESTMapper
|
restMapper meta.RESTMapper
|
||||||
dynamicClient dynamic.Interface
|
dynamicClient dynamic.Interface
|
||||||
resourceFilter resourcefilter.Interface // optional
|
excludedResources sets.Set[schema.GroupResource]
|
||||||
stopCh <-chan struct{}
|
stopCh <-chan struct{}
|
||||||
authorizer authorizer.Authorizer
|
authorizer authorizer.Authorizer
|
||||||
enabled bool
|
enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -66,7 +77,7 @@ var (
|
|||||||
_ initializer.WantsDynamicClient = &Plugin[any]{}
|
_ initializer.WantsDynamicClient = &Plugin[any]{}
|
||||||
_ initializer.WantsDrainedNotification = &Plugin[any]{}
|
_ initializer.WantsDrainedNotification = &Plugin[any]{}
|
||||||
_ initializer.WantsAuthorizer = &Plugin[any]{}
|
_ initializer.WantsAuthorizer = &Plugin[any]{}
|
||||||
_ initializer.WantsResourceFilter = &Plugin[any]{}
|
_ initializer.WantsExcludedAdmissionResources = &Plugin[any]{}
|
||||||
_ admission.InitializationValidator = &Plugin[any]{}
|
_ admission.InitializationValidator = &Plugin[any]{}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -79,6 +90,9 @@ func NewPlugin[H any](
|
|||||||
Handler: handler,
|
Handler: handler,
|
||||||
sourceFactory: sourceFactory,
|
sourceFactory: sourceFactory,
|
||||||
dispatcherFactory: dispatcherFactory,
|
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
|
c.enabled = enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Plugin[H]) SetResourceFilter(filter resourcefilter.Interface) {
|
func (c *Plugin[H]) SetExcludedAdmissionResources(excludedResources []schema.GroupResource) {
|
||||||
c.resourceFilter = filter
|
c.excludedResources.Insert(excludedResources...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateInitialization - once clientset and informer factory are provided, creates and starts the admission controller
|
// 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) {
|
) (err error) {
|
||||||
if !c.enabled {
|
if !c.enabled {
|
||||||
return nil
|
return nil
|
||||||
} else if isPolicyResource(a) || (c.resourceFilter != nil && !c.resourceFilter.ShouldHandle(a)) {
|
} else if c.shouldIgnoreResource(a) {
|
||||||
return nil
|
return nil
|
||||||
} else if !c.WaitForReady() {
|
} else if !c.WaitForReady() {
|
||||||
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
|
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())
|
return c.dispatcher.Dispatch(ctx, a, o, c.source.Hooks())
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPolicyResource(attr admission.Attributes) bool {
|
func (c *Plugin[H]) shouldIgnoreResource(attr admission.Attributes) bool {
|
||||||
gvk := attr.GetResource()
|
gvr := attr.GetResource()
|
||||||
if gvk.Group == "admissionregistration.k8s.io" {
|
// exclusion decision ignores the version.
|
||||||
if gvk.Resource == "validatingadmissionpolicies" || gvk.Resource == "validatingadmissionpolicybindings" {
|
gr := gvr.GroupResource()
|
||||||
return true
|
return c.excludedResources.Has(gr)
|
||||||
} else if gvk.Resource == "mutatingadmissionpolicies" || gvk.Resource == "mutatingadmissionpolicybindings" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ type Plugin struct {
|
|||||||
var _ admission.Interface = &Plugin{}
|
var _ admission.Interface = &Plugin{}
|
||||||
var _ admission.ValidationInterface = &Plugin{}
|
var _ admission.ValidationInterface = &Plugin{}
|
||||||
var _ initializer.WantsFeatures = &Plugin{}
|
var _ initializer.WantsFeatures = &Plugin{}
|
||||||
var _ initializer.WantsResourceFilter = &Plugin{}
|
var _ initializer.WantsExcludedAdmissionResources = &Plugin{}
|
||||||
|
|
||||||
func NewPlugin(_ io.Reader) *Plugin {
|
func NewPlugin(_ io.Reader) *Plugin {
|
||||||
handler := admission.NewHandler(admission.Connect, admission.Create, admission.Delete, admission.Update)
|
handler := admission.NewHandler(admission.Connect, admission.Create, admission.Delete, admission.Update)
|
||||||
|
@ -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
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user