From d8756b17e574b4b70c82ac6e1bc3ff1424a7f9c6 Mon Sep 17 00:00:00 2001
From: kaiyou <dev@kaiyou.fr>
Date: Sat, 27 Jul 2024 14:04:16 +0200
Subject: [PATCH] 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
---
 services/apiserver.go | 98 ++++++++++++++++++++++---------------------
 1 file changed, 50 insertions(+), 48 deletions(-)

diff --git a/services/apiserver.go b/services/apiserver.go
index ea37ac0..36cf5f4 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{
-- 
GitLab