diff --git a/services/apiserver.go b/services/apiserver.go index ea37ac07d95b86e1fb6bf3f05048d659061a6ca9..36cf5f4d43181406cdf1372697b3de07cb044ae5 100644 --- a/services/apiserver.go +++ b/services/apiserver.go @@ -270,16 +270,64 @@ func buildConfig(c *Cluster) (config *server.Config, clients *k8s.Clients, err e AuthorizationModes: []string{modes.ModeNode, modes.ModeRBAC}, VersionedInformerFactory: clients.Informer, } - authz, resolver, err := authzConfig.New() + authz, ruleResolver, err := authzConfig.New() if err != nil { err = fmt.Errorf("could not seutp apiserver authorizations: %w", err) return } - config.RuleResolver = resolver + config.RuleResolver = ruleResolver config.Authorization = server.AuthorizationInfo{ 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 config.AggregatedDiscoveryGroupManager = aggregated.NewResourceManager("apis") @@ -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) } - // 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{ GenericConfig: &generic, ExtraConfig: controlplane.ExtraConfig{