k8s.io/kubernetes@v1.29.3/pkg/controlplane/apiserver/config.go (about) 1 /* 2 Copyright 2023 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package apiserver 18 19 import ( 20 "fmt" 21 "time" 22 23 oteltrace "go.opentelemetry.io/otel/trace" 24 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/apimachinery/pkg/util/sets" 27 "k8s.io/apiserver/pkg/authorization/authorizer" 28 "k8s.io/apiserver/pkg/endpoints/discovery/aggregated" 29 openapinamer "k8s.io/apiserver/pkg/endpoints/openapi" 30 genericfeatures "k8s.io/apiserver/pkg/features" 31 "k8s.io/apiserver/pkg/reconcilers" 32 genericapiserver "k8s.io/apiserver/pkg/server" 33 "k8s.io/apiserver/pkg/server/egressselector" 34 "k8s.io/apiserver/pkg/server/filters" 35 serverstorage "k8s.io/apiserver/pkg/server/storage" 36 "k8s.io/apiserver/pkg/storageversion" 37 utilfeature "k8s.io/apiserver/pkg/util/feature" 38 "k8s.io/apiserver/pkg/util/openapi" 39 utilpeerproxy "k8s.io/apiserver/pkg/util/peerproxy" 40 clientgoinformers "k8s.io/client-go/informers" 41 clientgoclientset "k8s.io/client-go/kubernetes" 42 "k8s.io/client-go/transport" 43 "k8s.io/component-base/version" 44 "k8s.io/klog/v2" 45 openapicommon "k8s.io/kube-openapi/pkg/common" 46 47 "k8s.io/kubernetes/pkg/api/legacyscheme" 48 api "k8s.io/kubernetes/pkg/apis/core" 49 "k8s.io/kubernetes/pkg/controlplane" 50 controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver/options" 51 "k8s.io/kubernetes/pkg/kubeapiserver" 52 "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" 53 rbacrest "k8s.io/kubernetes/pkg/registry/rbac/rest" 54 ) 55 56 // BuildGenericConfig takes the master server options and produces the genericapiserver.Config associated with it 57 func BuildGenericConfig( 58 s controlplaneapiserver.CompletedOptions, 59 schemes []*runtime.Scheme, 60 getOpenAPIDefinitions func(ref openapicommon.ReferenceCallback) map[string]openapicommon.OpenAPIDefinition, 61 ) ( 62 genericConfig *genericapiserver.Config, 63 versionedInformers clientgoinformers.SharedInformerFactory, 64 storageFactory *serverstorage.DefaultStorageFactory, 65 66 lastErr error, 67 ) { 68 genericConfig = genericapiserver.NewConfig(legacyscheme.Codecs) 69 genericConfig.MergedResourceConfig = controlplane.DefaultAPIResourceConfigSource() 70 71 if lastErr = s.GenericServerRunOptions.ApplyTo(genericConfig); lastErr != nil { 72 return 73 } 74 75 if lastErr = s.SecureServing.ApplyTo(&genericConfig.SecureServing, &genericConfig.LoopbackClientConfig); lastErr != nil { 76 return 77 } 78 79 // Use protobufs for self-communication. 80 // Since not every generic apiserver has to support protobufs, we 81 // cannot default to it in generic apiserver and need to explicitly 82 // set it in kube-apiserver. 83 genericConfig.LoopbackClientConfig.ContentConfig.ContentType = "application/vnd.kubernetes.protobuf" 84 // Disable compression for self-communication, since we are going to be 85 // on a fast local network 86 genericConfig.LoopbackClientConfig.DisableCompression = true 87 88 kubeClientConfig := genericConfig.LoopbackClientConfig 89 clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeClientConfig) 90 if err != nil { 91 lastErr = fmt.Errorf("failed to create real external clientset: %v", err) 92 return 93 } 94 versionedInformers = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute) 95 96 if lastErr = s.Features.ApplyTo(genericConfig, clientgoExternalClient, versionedInformers); lastErr != nil { 97 return 98 } 99 if lastErr = s.APIEnablement.ApplyTo(genericConfig, controlplane.DefaultAPIResourceConfigSource(), legacyscheme.Scheme); lastErr != nil { 100 return 101 } 102 if lastErr = s.EgressSelector.ApplyTo(genericConfig); lastErr != nil { 103 return 104 } 105 if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) { 106 if lastErr = s.Traces.ApplyTo(genericConfig.EgressSelector, genericConfig); lastErr != nil { 107 return 108 } 109 } 110 // wrap the definitions to revert any changes from disabled features 111 getOpenAPIDefinitions = openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(getOpenAPIDefinitions) 112 namer := openapinamer.NewDefinitionNamer(schemes...) 113 genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(getOpenAPIDefinitions, namer) 114 genericConfig.OpenAPIConfig.Info.Title = "Kubernetes" 115 genericConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(getOpenAPIDefinitions, namer) 116 genericConfig.OpenAPIV3Config.Info.Title = "Kubernetes" 117 118 genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck( 119 sets.NewString("watch", "proxy"), 120 sets.NewString("attach", "exec", "proxy", "log", "portforward"), 121 ) 122 123 kubeVersion := version.Get() 124 genericConfig.Version = &kubeVersion 125 126 if genericConfig.EgressSelector != nil { 127 s.Etcd.StorageConfig.Transport.EgressLookup = genericConfig.EgressSelector.Lookup 128 } 129 if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) { 130 s.Etcd.StorageConfig.Transport.TracerProvider = genericConfig.TracerProvider 131 } else { 132 s.Etcd.StorageConfig.Transport.TracerProvider = oteltrace.NewNoopTracerProvider() 133 } 134 135 storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig() 136 storageFactoryConfig.APIResourceConfig = genericConfig.MergedResourceConfig 137 storageFactory, lastErr = storageFactoryConfig.Complete(s.Etcd).New() 138 if lastErr != nil { 139 return 140 } 141 if lastErr = s.Etcd.ApplyWithStorageFactoryTo(storageFactory, genericConfig); lastErr != nil { 142 return 143 } 144 145 // Authentication.ApplyTo requires already applied OpenAPIConfig and EgressSelector if present 146 if lastErr = s.Authentication.ApplyTo(&genericConfig.Authentication, genericConfig.SecureServing, genericConfig.EgressSelector, genericConfig.OpenAPIConfig, genericConfig.OpenAPIV3Config, clientgoExternalClient, versionedInformers); lastErr != nil { 147 return 148 } 149 150 var enablesRBAC bool 151 genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, enablesRBAC, err = BuildAuthorizer(s, genericConfig.EgressSelector, versionedInformers) 152 if err != nil { 153 lastErr = fmt.Errorf("invalid authorization config: %v", err) 154 return 155 } 156 if s.Authorization != nil && !enablesRBAC { 157 genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName) 158 } 159 160 lastErr = s.Audit.ApplyTo(genericConfig) 161 if lastErr != nil { 162 return 163 } 164 165 if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.AggregatedDiscoveryEndpoint) { 166 genericConfig.AggregatedDiscoveryGroupManager = aggregated.NewResourceManager("apis") 167 } 168 169 return 170 } 171 172 // BuildAuthorizer constructs the authorizer. If authorization is not set in s, it returns nil, nil, false, nil 173 func BuildAuthorizer(s controlplaneapiserver.CompletedOptions, egressSelector *egressselector.EgressSelector, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, bool, error) { 174 authorizationConfig, err := s.Authorization.ToAuthorizationConfig(versionedInformers) 175 if err != nil { 176 return nil, nil, false, err 177 } 178 if authorizationConfig == nil { 179 return nil, nil, false, nil 180 } 181 182 if egressSelector != nil { 183 egressDialer, err := egressSelector.Lookup(egressselector.ControlPlane.AsNetworkContext()) 184 if err != nil { 185 return nil, nil, false, err 186 } 187 authorizationConfig.CustomDial = egressDialer 188 } 189 190 enablesRBAC := false 191 for _, a := range authorizationConfig.AuthorizationConfiguration.Authorizers { 192 if string(a.Type) == modes.ModeRBAC { 193 enablesRBAC = true 194 break 195 } 196 } 197 198 authorizer, ruleResolver, err := authorizationConfig.New() 199 200 return authorizer, ruleResolver, enablesRBAC, err 201 } 202 203 // CreatePeerEndpointLeaseReconciler creates a apiserver endpoint lease reconciliation loop 204 // The peer endpoint leases are used to find network locations of apiservers for peer proxy 205 func CreatePeerEndpointLeaseReconciler(c genericapiserver.Config, storageFactory serverstorage.StorageFactory) (reconcilers.PeerEndpointLeaseReconciler, error) { 206 ttl := controlplane.DefaultEndpointReconcilerTTL 207 config, err := storageFactory.NewConfig(api.Resource("apiServerPeerIPInfo")) 208 if err != nil { 209 return nil, fmt.Errorf("error creating storage factory config: %w", err) 210 } 211 reconciler, err := reconcilers.NewPeerEndpointLeaseReconciler(config, "/peerserverleases/", ttl) 212 return reconciler, err 213 } 214 215 func BuildPeerProxy(versionedInformer clientgoinformers.SharedInformerFactory, svm storageversion.Manager, 216 proxyClientCertFile string, proxyClientKeyFile string, peerCAFile string, peerAdvertiseAddress reconcilers.PeerAdvertiseAddress, 217 apiServerID string, reconciler reconcilers.PeerEndpointLeaseReconciler, serializer runtime.NegotiatedSerializer) (utilpeerproxy.Interface, error) { 218 if proxyClientCertFile == "" { 219 return nil, fmt.Errorf("error building peer proxy handler, proxy-cert-file not specified") 220 } 221 if proxyClientKeyFile == "" { 222 return nil, fmt.Errorf("error building peer proxy handler, proxy-key-file not specified") 223 } 224 // create proxy client config 225 clientConfig := &transport.Config{ 226 TLS: transport.TLSConfig{ 227 Insecure: false, 228 CertFile: proxyClientCertFile, 229 KeyFile: proxyClientKeyFile, 230 CAFile: peerCAFile, 231 ServerName: "kubernetes.default.svc", 232 }} 233 234 // build proxy transport 235 proxyRoundTripper, transportBuildingError := transport.New(clientConfig) 236 if transportBuildingError != nil { 237 klog.Error(transportBuildingError.Error()) 238 return nil, transportBuildingError 239 } 240 return utilpeerproxy.NewPeerProxyHandler( 241 versionedInformer, 242 svm, 243 proxyRoundTripper, 244 apiServerID, 245 reconciler, 246 serializer, 247 ), nil 248 }