Skip to content
Snippets Groups Projects
Commit d8756b17 authored by kaiyou's avatar kaiyou
Browse files

Move the admission plugin initialization to the generic config

Previously the plugins initialization was done for the apiserver
config only, which enabled admission for core resources handled by
the apiserver, but the extensions server lacked the admission chain
and did not apply webhooks to CRDs
parent b60c891c
No related branches found
No related tags found
No related merge requests found
Pipeline #32612 failed
...@@ -270,16 +270,64 @@ func buildConfig(c *Cluster) (config *server.Config, clients *k8s.Clients, err e ...@@ -270,16 +270,64 @@ func buildConfig(c *Cluster) (config *server.Config, clients *k8s.Clients, err e
AuthorizationModes: []string{modes.ModeNode, modes.ModeRBAC}, AuthorizationModes: []string{modes.ModeNode, modes.ModeRBAC},
VersionedInformerFactory: clients.Informer, VersionedInformerFactory: clients.Informer,
} }
authz, resolver, err := authzConfig.New() authz, ruleResolver, err := authzConfig.New()
if err != nil { if err != nil {
err = fmt.Errorf("could not seutp apiserver authorizations: %w", err) err = fmt.Errorf("could not seutp apiserver authorizations: %w", err)
return return
} }
config.RuleResolver = resolver config.RuleResolver = ruleResolver
config.Authorization = server.AuthorizationInfo{ config.Authorization = server.AuthorizationInfo{
Authorizer: authz, Authorizer: authz,
} }
// Setup admission controllers
// Vanilla code for this is pretty complex, since it uses dynamic plugins, which might load configurations from files instead
// of structs, so we just copy the relevant parts here
//
// Start, by registering admission plugins
// Full list of plugins is avaiable at: https://github.com/kubernetes/kubernetes/blob/v1.27.4/pkg/kubeapiserver/options/plugins.go
plugins := admission.NewPlugins()
lifecycle.Register(plugins)
mutating.Register(plugins)
validatingadmissionpolicy.Register(plugins)
validating.Register(plugins)
resize.Register(plugins)
resourcequota.Register(plugins)
nodetaint.Register(plugins)
podsecurity.Register(plugins)
saplugin.Register(plugins)
// Prepare the plugins configuration
// The plugins config is an instance that just returns nil for every plugin,
// we ignore errors since it never fails to load config, since it does not parse.. any config at all
pluginsConfig, _ := admission.ReadAdmissionConfiguration([]string{}, "", nil)
// Since we do not load configuration from files, the only plugin config we pass is from the plugin initialized chain
// It is a chain of functions that alter the plugin object to initialize it. We build the initialize chain from two sources,
// the admission initializer packager, which sets clients settings mostly, and helpers from kubeapiserver, which setup the
// loopback configuration and informers
genericInitializer := initializer.New(clients.Client, clients.DynClient, clients.Informer, authz, feature.DefaultFeatureGate, config.DrainedNotify())
initializersChain := admission.PluginInitializers{genericInitializer}
admissionConfig := kubeadmission.Config{
ExternalInformers: clients.Informer,
LoopbackClientConfig: config.LoopbackClientConfig,
}
schemaResolver := resolver.NewDefinitionsSchemaResolver(scheme.Scheme, config.OpenAPIConfig.GetDefinitions)
heperInitializers, pluginsPostStartHook, err := admissionConfig.New(nil, nil, clients.ServiceResolver(), nil, schemaResolver)
if err != nil {
err = fmt.Errorf("could not prepare the admission config: %w", err)
return
}
err = config.AddPostStartHook("initialize-plugins", pluginsPostStartHook)
if err != nil {
err = fmt.Errorf("could not initialize plugins: %w", err)
return
}
initializersChain = append(initializersChain, heperInitializers...)
// Actually build the admission chain
// The plugins config is an instance that just returns nil for every plugin, the decorators instance does nothing
// since it iterates over an empty list of decorators
admissionChain, err := plugins.NewFromPlugins(plugins.Registered(), pluginsConfig, initializersChain, admission.Decorators{})
config.AdmissionControl = admissionChain
// Setup the resource discovery manager, which is especially useful for the aggregation layer // Setup the resource discovery manager, which is especially useful for the aggregation layer
config.AggregatedDiscoveryGroupManager = aggregated.NewResourceManager("apis") config.AggregatedDiscoveryGroupManager = aggregated.NewResourceManager("apis")
...@@ -335,52 +383,6 @@ func buildApiConfig(c *Cluster, config server.Config, clients *k8s.Clients) (*co ...@@ -335,52 +383,6 @@ func buildApiConfig(c *Cluster, config server.Config, clients *k8s.Clients) (*co
return nil, fmt.Errorf("could not initilize service account signer: %w", err) return nil, fmt.Errorf("could not initilize service account signer: %w", err)
} }
// Setup admission controllers
// Vanilla code for this is pretty complex, since it uses dynamic plugins, which might load configurations from files instead
// of structs, so we just copy the relevant parts here
//
// Start, by registering admission plugins
// Full list of plugins is avaiable at: https://github.com/kubernetes/kubernetes/blob/v1.27.4/pkg/kubeapiserver/options/plugins.go
plugins := admission.NewPlugins()
lifecycle.Register(plugins)
mutating.Register(plugins)
validatingadmissionpolicy.Register(plugins)
validating.Register(plugins)
resize.Register(plugins)
resourcequota.Register(plugins)
nodetaint.Register(plugins)
podsecurity.Register(plugins)
saplugin.Register(plugins)
// Prepare the plugins configuration
// The plugins config is an instance that just returns nil for every plugin,
// we ignore errors since it never fails to load config, since it does not parse.. any config at all
pluginsConfig, _ := admission.ReadAdmissionConfiguration([]string{}, "", nil)
// Since we do not load configuration from files, the only plugin config we pass is from the plugin initialized chain
// It is a chain of functions that alter the plugin object to initialize it. We build the initialize chain from two sources,
// the admission initializer packager, which sets clients settings mostly, and helpers from kubeapiserver, which setup the
// loopback configuration and informers
genericInitializer := initializer.New(clients.Client, clients.DynClient, clients.Informer, generic.Authorization.Authorizer, feature.DefaultFeatureGate, generic.DrainedNotify())
initializersChain := admission.PluginInitializers{genericInitializer}
admissionConfig := kubeadmission.Config{
ExternalInformers: clients.Informer,
LoopbackClientConfig: config.LoopbackClientConfig,
}
schemaResolver := resolver.NewDefinitionsSchemaResolver(scheme.Scheme, generic.OpenAPIConfig.GetDefinitions)
heperInitializers, pluginsPostStartHook, err := admissionConfig.New(nil, nil, clients.ServiceResolver(), nil, schemaResolver)
if err != nil {
return nil, fmt.Errorf("could not prepare the admission config: %w", err)
}
err = config.AddPostStartHook("initialize-plugins", pluginsPostStartHook)
if err != nil {
return nil, fmt.Errorf("could not initialize plugins: %w", err)
}
initializersChain = append(initializersChain, heperInitializers...)
// Actually build the admission chain
// The plugins config is an instance that just returns nil for every plugin, the decorators instance does nothing
// since it iterates over an empty list of decorators
admissionChain, err := plugins.NewFromPlugins(plugins.Registered(), pluginsConfig, initializersChain, admission.Decorators{})
generic.AdmissionControl = admissionChain
return &controlplane.Config{ return &controlplane.Config{
GenericConfig: &generic, GenericConfig: &generic,
ExtraConfig: controlplane.ExtraConfig{ ExtraConfig: controlplane.ExtraConfig{
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment