...

Source file src/k8s.io/kubernetes/pkg/controlplane/apiserver/config.go

Documentation: k8s.io/kubernetes/pkg/controlplane/apiserver

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

View as plain text