123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- // Package app does all of the work necessary to create a Kubernetes
- // APIServer by binding together the API, master and APIServer infrastructure.
- // It can be configured and called directly or via the hyperkube framework.
- package app
- import (
- "crypto/tls"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "net/url"
- "os"
- "strconv"
- "strings"
- "time"
- "github.com/go-openapi/spec"
- "github.com/spf13/cobra"
- extensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
- v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- utilerrors "k8s.io/apimachinery/pkg/util/errors"
- utilnet "k8s.io/apimachinery/pkg/util/net"
- "k8s.io/apimachinery/pkg/util/sets"
- utilwait "k8s.io/apimachinery/pkg/util/wait"
- "k8s.io/apiserver/pkg/admission"
- "k8s.io/apiserver/pkg/authentication/authenticator"
- "k8s.io/apiserver/pkg/authorization/authorizer"
- openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
- genericapiserver "k8s.io/apiserver/pkg/server"
- "k8s.io/apiserver/pkg/server/filters"
- serveroptions "k8s.io/apiserver/pkg/server/options"
- serverstorage "k8s.io/apiserver/pkg/server/storage"
- "k8s.io/apiserver/pkg/storage/etcd3/preflight"
- "k8s.io/apiserver/pkg/util/term"
- "k8s.io/apiserver/pkg/util/webhook"
- clientgoinformers "k8s.io/client-go/informers"
- clientgoclientset "k8s.io/client-go/kubernetes"
- "k8s.io/client-go/util/keyutil"
- cloudprovider "k8s.io/cloud-provider"
- cliflag "k8s.io/component-base/cli/flag"
- "k8s.io/component-base/cli/globalflag"
- "k8s.io/klog"
- aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver"
- aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
- "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
- "k8s.io/kubernetes/pkg/api/legacyscheme"
- "k8s.io/kubernetes/pkg/capabilities"
- serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
- generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
- "k8s.io/kubernetes/pkg/kubeapiserver"
- kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
- kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator"
- "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
- kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
- kubeserver "k8s.io/kubernetes/pkg/kubeapiserver/server"
- "k8s.io/kubernetes/pkg/master"
- "k8s.io/kubernetes/pkg/master/reconcilers"
- "k8s.io/kubernetes/pkg/master/tunneler"
- "k8s.io/kubernetes/pkg/registry/cachesize"
- rbacrest "k8s.io/kubernetes/pkg/registry/rbac/rest"
- "k8s.io/kubernetes/pkg/serviceaccount"
- utilflag "k8s.io/kubernetes/pkg/util/flag"
- _ "k8s.io/kubernetes/pkg/util/workqueue/prometheus" // for workqueue metric registration
- "k8s.io/kubernetes/pkg/version"
- "k8s.io/kubernetes/pkg/version/verflag"
- "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
- )
- const (
- etcdRetryLimit = 60
- etcdRetryInterval = 1 * time.Second
- )
- // NewAPIServerCommand creates a *cobra.Command object with default parameters
- func NewAPIServerCommand() *cobra.Command {
- s := options.NewServerRunOptions()
- cmd := &cobra.Command{
- Use: "kube-apiserver",
- Long: `The Kubernetes API server validates and configures data
- for the api objects which include pods, services, replicationcontrollers, and
- others. The API Server services REST operations and provides the frontend to the
- cluster's shared state through which all other components interact.`,
- RunE: func(cmd *cobra.Command, args []string) error {
- verflag.PrintAndExitIfRequested()
- utilflag.PrintFlags(cmd.Flags())
- // set default options
- completedOptions, err := Complete(s)
- if err != nil {
- return err
- }
- // validate options
- if errs := completedOptions.Validate(); len(errs) != 0 {
- return utilerrors.NewAggregate(errs)
- }
- return Run(completedOptions, genericapiserver.SetupSignalHandler())
- },
- }
- fs := cmd.Flags()
- namedFlagSets := s.Flags()
- verflag.AddFlags(namedFlagSets.FlagSet("global"))
- globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())
- options.AddCustomGlobalFlags(namedFlagSets.FlagSet("generic"))
- for _, f := range namedFlagSets.FlagSets {
- fs.AddFlagSet(f)
- }
- usageFmt := "Usage:\n %s\n"
- cols, _, _ := term.TerminalSize(cmd.OutOrStdout())
- cmd.SetUsageFunc(func(cmd *cobra.Command) error {
- fmt.Fprintf(cmd.OutOrStderr(), usageFmt, cmd.UseLine())
- cliflag.PrintSections(cmd.OutOrStderr(), namedFlagSets, cols)
- return nil
- })
- cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
- fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n"+usageFmt, cmd.Long, cmd.UseLine())
- cliflag.PrintSections(cmd.OutOrStdout(), namedFlagSets, cols)
- })
- return cmd
- }
- // Run runs the specified APIServer. This should never exit.
- func Run(completeOptions completedServerRunOptions, stopCh <-chan struct{}) error {
- // To help debugging, immediately log version
- klog.Infof("Version: %+v", version.Get())
- server, err := CreateServerChain(completeOptions, stopCh)
- if err != nil {
- return err
- }
- return server.PrepareRun().Run(stopCh)
- }
- // CreateServerChain creates the apiservers connected via delegation.
- func CreateServerChain(completedOptions completedServerRunOptions, stopCh <-chan struct{}) (*genericapiserver.GenericAPIServer, error) {
- nodeTunneler, proxyTransport, err := CreateNodeDialer(completedOptions)
- if err != nil {
- return nil, err
- }
- kubeAPIServerConfig, insecureServingInfo, serviceResolver, pluginInitializer, admissionPostStartHook, err := CreateKubeAPIServerConfig(completedOptions, nodeTunneler, proxyTransport)
- if err != nil {
- return nil, err
- }
- // If additional API servers are added, they should be gated.
- apiExtensionsConfig, err := createAPIExtensionsConfig(*kubeAPIServerConfig.GenericConfig, kubeAPIServerConfig.ExtraConfig.VersionedInformers, pluginInitializer, completedOptions.ServerRunOptions, completedOptions.MasterCount,
- serviceResolver, webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, kubeAPIServerConfig.GenericConfig.LoopbackClientConfig))
- if err != nil {
- return nil, err
- }
- apiExtensionsServer, err := createAPIExtensionsServer(apiExtensionsConfig, genericapiserver.NewEmptyDelegate())
- if err != nil {
- return nil, err
- }
- kubeAPIServer, err := CreateKubeAPIServer(kubeAPIServerConfig, apiExtensionsServer.GenericAPIServer, admissionPostStartHook)
- if err != nil {
- return nil, err
- }
- // otherwise go down the normal path of standing the aggregator up in front of the API server
- // this wires up openapi
- kubeAPIServer.GenericAPIServer.PrepareRun()
- // This will wire up openapi for extension api server
- apiExtensionsServer.GenericAPIServer.PrepareRun()
- // aggregator comes last in the chain
- aggregatorConfig, err := createAggregatorConfig(*kubeAPIServerConfig.GenericConfig, completedOptions.ServerRunOptions, kubeAPIServerConfig.ExtraConfig.VersionedInformers, serviceResolver, proxyTransport, pluginInitializer)
- if err != nil {
- return nil, err
- }
- aggregatorServer, err := createAggregatorServer(aggregatorConfig, kubeAPIServer.GenericAPIServer, apiExtensionsServer.Informers)
- if err != nil {
- // we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines
- return nil, err
- }
- if insecureServingInfo != nil {
- insecureHandlerChain := kubeserver.BuildInsecureHandlerChain(aggregatorServer.GenericAPIServer.UnprotectedHandler(), kubeAPIServerConfig.GenericConfig)
- if err := insecureServingInfo.Serve(insecureHandlerChain, kubeAPIServerConfig.GenericConfig.RequestTimeout, stopCh); err != nil {
- return nil, err
- }
- }
- return aggregatorServer.GenericAPIServer, nil
- }
- // CreateKubeAPIServer creates and wires a workable kube-apiserver
- func CreateKubeAPIServer(kubeAPIServerConfig *master.Config, delegateAPIServer genericapiserver.DelegationTarget, admissionPostStartHook genericapiserver.PostStartHookFunc) (*master.Master, error) {
- kubeAPIServer, err := kubeAPIServerConfig.Complete().New(delegateAPIServer)
- if err != nil {
- return nil, err
- }
- kubeAPIServer.GenericAPIServer.AddPostStartHookOrDie("start-kube-apiserver-admission-initializer", admissionPostStartHook)
- return kubeAPIServer, nil
- }
- // CreateNodeDialer creates the dialer infrastructure to connect to the nodes.
- func CreateNodeDialer(s completedServerRunOptions) (tunneler.Tunneler, *http.Transport, error) {
- // Setup nodeTunneler if needed
- var nodeTunneler tunneler.Tunneler
- var proxyDialerFn utilnet.DialFunc
- if len(s.SSHUser) > 0 {
- // Get ssh key distribution func, if supported
- var installSSHKey tunneler.InstallSSHKey
- cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider.CloudProvider, s.CloudProvider.CloudConfigFile)
- if err != nil {
- return nil, nil, fmt.Errorf("cloud provider could not be initialized: %v", err)
- }
- if cloud != nil {
- if instances, supported := cloud.Instances(); supported {
- installSSHKey = instances.AddSSHKeyToAllInstances
- }
- }
- if s.KubeletConfig.Port == 0 {
- return nil, nil, fmt.Errorf("must enable kubelet port if proxy ssh-tunneling is specified")
- }
- if s.KubeletConfig.ReadOnlyPort == 0 {
- return nil, nil, fmt.Errorf("must enable kubelet readonly port if proxy ssh-tunneling is specified")
- }
- // Set up the nodeTunneler
- // TODO(cjcullen): If we want this to handle per-kubelet ports or other
- // kubelet listen-addresses, we need to plumb through options.
- healthCheckPath := &url.URL{
- Scheme: "http",
- Host: net.JoinHostPort("127.0.0.1", strconv.FormatUint(uint64(s.KubeletConfig.ReadOnlyPort), 10)),
- Path: "healthz",
- }
- nodeTunneler = tunneler.New(s.SSHUser, s.SSHKeyfile, healthCheckPath, installSSHKey)
- // Use the nodeTunneler's dialer when proxying to pods, services, and nodes
- proxyDialerFn = nodeTunneler.Dial
- }
- // Proxying to pods and services is IP-based... don't expect to be able to verify the hostname
- proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true}
- proxyTransport := utilnet.SetTransportDefaults(&http.Transport{
- DialContext: proxyDialerFn,
- TLSClientConfig: proxyTLSClientConfig,
- })
- return nodeTunneler, proxyTransport, nil
- }
- // CreateKubeAPIServerConfig creates all the resources for running the API server, but runs none of them
- func CreateKubeAPIServerConfig(
- s completedServerRunOptions,
- nodeTunneler tunneler.Tunneler,
- proxyTransport *http.Transport,
- ) (
- config *master.Config,
- insecureServingInfo *genericapiserver.DeprecatedInsecureServingInfo,
- serviceResolver aggregatorapiserver.ServiceResolver,
- pluginInitializers []admission.PluginInitializer,
- admissionPostStartHook genericapiserver.PostStartHookFunc,
- lastErr error,
- ) {
- var genericConfig *genericapiserver.Config
- var storageFactory *serverstorage.DefaultStorageFactory
- var versionedInformers clientgoinformers.SharedInformerFactory
- genericConfig, versionedInformers, insecureServingInfo, serviceResolver, pluginInitializers, admissionPostStartHook, storageFactory, lastErr = buildGenericConfig(s.ServerRunOptions, proxyTransport)
- if lastErr != nil {
- return
- }
- if _, port, err := net.SplitHostPort(s.Etcd.StorageConfig.Transport.ServerList[0]); err == nil && port != "0" && len(port) != 0 {
- if err := utilwait.PollImmediate(etcdRetryInterval, etcdRetryLimit*etcdRetryInterval, preflight.EtcdConnection{ServerList: s.Etcd.StorageConfig.Transport.ServerList}.CheckEtcdServers); err != nil {
- lastErr = fmt.Errorf("error waiting for etcd connection: %v", err)
- return
- }
- }
- capabilities.Initialize(capabilities.Capabilities{
- AllowPrivileged: s.AllowPrivileged,
- // TODO(vmarmol): Implement support for HostNetworkSources.
- PrivilegedSources: capabilities.PrivilegedSources{
- HostNetworkSources: []string{},
- HostPIDSources: []string{},
- HostIPCSources: []string{},
- },
- PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec,
- })
- serviceIPRange, apiServerServiceIP, lastErr := master.DefaultServiceIPRange(s.ServiceClusterIPRange)
- if lastErr != nil {
- return
- }
- clientCA, lastErr := readCAorNil(s.Authentication.ClientCert.ClientCA)
- if lastErr != nil {
- return
- }
- requestHeaderProxyCA, lastErr := readCAorNil(s.Authentication.RequestHeader.ClientCAFile)
- if lastErr != nil {
- return
- }
- config = &master.Config{
- GenericConfig: genericConfig,
- ExtraConfig: master.ExtraConfig{
- ClientCARegistrationHook: master.ClientCARegistrationHook{
- ClientCA: clientCA,
- RequestHeaderUsernameHeaders: s.Authentication.RequestHeader.UsernameHeaders,
- RequestHeaderGroupHeaders: s.Authentication.RequestHeader.GroupHeaders,
- RequestHeaderExtraHeaderPrefixes: s.Authentication.RequestHeader.ExtraHeaderPrefixes,
- RequestHeaderCA: requestHeaderProxyCA,
- RequestHeaderAllowedNames: s.Authentication.RequestHeader.AllowedNames,
- },
- APIResourceConfigSource: storageFactory.APIResourceConfigSource,
- StorageFactory: storageFactory,
- EventTTL: s.EventTTL,
- KubeletClientConfig: s.KubeletConfig,
- EnableLogsSupport: s.EnableLogsHandler,
- ProxyTransport: proxyTransport,
- Tunneler: nodeTunneler,
- ServiceIPRange: serviceIPRange,
- APIServerServiceIP: apiServerServiceIP,
- APIServerServicePort: 443,
- ServiceNodePortRange: s.ServiceNodePortRange,
- KubernetesServiceNodePort: s.KubernetesServiceNodePort,
- EndpointReconcilerType: reconcilers.Type(s.EndpointReconcilerType),
- MasterCount: s.MasterCount,
- ServiceAccountIssuer: s.ServiceAccountIssuer,
- ServiceAccountMaxExpiration: s.ServiceAccountTokenMaxExpiration,
- VersionedInformers: versionedInformers,
- },
- }
- if nodeTunneler != nil {
- // Use the nodeTunneler's dialer to connect to the kubelet
- config.ExtraConfig.KubeletClientConfig.Dial = nodeTunneler.Dial
- }
- return
- }
- // BuildGenericConfig takes the master server options and produces the genericapiserver.Config associated with it
- func buildGenericConfig(
- s *options.ServerRunOptions,
- proxyTransport *http.Transport,
- ) (
- genericConfig *genericapiserver.Config,
- versionedInformers clientgoinformers.SharedInformerFactory,
- insecureServingInfo *genericapiserver.DeprecatedInsecureServingInfo,
- serviceResolver aggregatorapiserver.ServiceResolver,
- pluginInitializers []admission.PluginInitializer,
- admissionPostStartHook genericapiserver.PostStartHookFunc,
- storageFactory *serverstorage.DefaultStorageFactory,
- lastErr error,
- ) {
- genericConfig = genericapiserver.NewConfig(legacyscheme.Codecs)
- genericConfig.MergedResourceConfig = master.DefaultAPIResourceConfigSource()
- if lastErr = s.GenericServerRunOptions.ApplyTo(genericConfig); lastErr != nil {
- return
- }
- if lastErr = s.InsecureServing.ApplyTo(&insecureServingInfo, &genericConfig.LoopbackClientConfig); lastErr != nil {
- return
- }
- if lastErr = s.SecureServing.ApplyTo(&genericConfig.SecureServing, &genericConfig.LoopbackClientConfig); lastErr != nil {
- return
- }
- if lastErr = s.Authentication.ApplyTo(genericConfig); lastErr != nil {
- return
- }
- if lastErr = s.Features.ApplyTo(genericConfig); lastErr != nil {
- return
- }
- if lastErr = s.APIEnablement.ApplyTo(genericConfig, master.DefaultAPIResourceConfigSource(), legacyscheme.Scheme); lastErr != nil {
- return
- }
- genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(legacyscheme.Scheme, extensionsapiserver.Scheme, aggregatorscheme.Scheme))
- genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
- genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
- sets.NewString("watch", "proxy"),
- sets.NewString("attach", "exec", "proxy", "log", "portforward"),
- )
- kubeVersion := version.Get()
- genericConfig.Version = &kubeVersion
- storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig()
- storageFactoryConfig.ApiResourceConfig = genericConfig.MergedResourceConfig
- completedStorageFactoryConfig, err := storageFactoryConfig.Complete(s.Etcd)
- if err != nil {
- lastErr = err
- return
- }
- storageFactory, lastErr = completedStorageFactoryConfig.New()
- if lastErr != nil {
- return
- }
- if lastErr = s.Etcd.ApplyWithStorageFactoryTo(storageFactory, genericConfig); lastErr != nil {
- return
- }
- // Use protobufs for self-communication.
- // Since not every generic apiserver has to support protobufs, we
- // cannot default to it in generic apiserver and need to explicitly
- // set it in kube-apiserver.
- genericConfig.LoopbackClientConfig.ContentConfig.ContentType = "application/vnd.kubernetes.protobuf"
- kubeClientConfig := genericConfig.LoopbackClientConfig
- clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeClientConfig)
- if err != nil {
- lastErr = fmt.Errorf("failed to create real external clientset: %v", err)
- return
- }
- versionedInformers = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)
- genericConfig.Authentication.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, clientgoExternalClient, versionedInformers)
- if err != nil {
- lastErr = fmt.Errorf("invalid authentication config: %v", err)
- return
- }
- genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, err = BuildAuthorizer(s, versionedInformers)
- if err != nil {
- lastErr = fmt.Errorf("invalid authorization config: %v", err)
- return
- }
- if !sets.NewString(s.Authorization.Modes...).Has(modes.ModeRBAC) {
- genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName)
- }
- admissionConfig := &kubeapiserveradmission.Config{
- ExternalInformers: versionedInformers,
- LoopbackClientConfig: genericConfig.LoopbackClientConfig,
- CloudConfigFile: s.CloudProvider.CloudConfigFile,
- }
- serviceResolver = buildServiceResolver(s.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers)
- authInfoResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, genericConfig.LoopbackClientConfig)
- lastErr = s.Audit.ApplyTo(
- genericConfig,
- genericConfig.LoopbackClientConfig,
- versionedInformers,
- serveroptions.NewProcessInfo("kube-apiserver", "kube-system"),
- &serveroptions.WebhookOptions{
- AuthInfoResolverWrapper: authInfoResolverWrapper,
- ServiceResolver: serviceResolver,
- },
- )
- if lastErr != nil {
- return
- }
- pluginInitializers, admissionPostStartHook, err = admissionConfig.New(proxyTransport, serviceResolver)
- if err != nil {
- lastErr = fmt.Errorf("failed to create admission plugin initializer: %v", err)
- return
- }
- err = s.Admission.ApplyTo(
- genericConfig,
- versionedInformers,
- kubeClientConfig,
- pluginInitializers...)
- if err != nil {
- lastErr = fmt.Errorf("failed to initialize admission: %v", err)
- }
- return
- }
- // BuildAuthenticator constructs the authenticator
- func BuildAuthenticator(s *options.ServerRunOptions, extclient clientgoclientset.Interface, versionedInformer clientgoinformers.SharedInformerFactory) (authenticator.Request, *spec.SecurityDefinitions, error) {
- authenticatorConfig := s.Authentication.ToAuthenticationConfig()
- if s.Authentication.ServiceAccounts.Lookup {
- authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromClient(
- extclient,
- versionedInformer.Core().V1().Secrets().Lister(),
- versionedInformer.Core().V1().ServiceAccounts().Lister(),
- versionedInformer.Core().V1().Pods().Lister(),
- )
- }
- authenticatorConfig.BootstrapTokenAuthenticator = bootstrap.NewTokenAuthenticator(
- versionedInformer.Core().V1().Secrets().Lister().Secrets(v1.NamespaceSystem),
- )
- return authenticatorConfig.New()
- }
- // BuildAuthorizer constructs the authorizer
- func BuildAuthorizer(s *options.ServerRunOptions, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, error) {
- authorizationConfig := s.Authorization.ToAuthorizationConfig(versionedInformers)
- return authorizationConfig.New()
- }
- // completedServerRunOptions is a private wrapper that enforces a call of Complete() before Run can be invoked.
- type completedServerRunOptions struct {
- *options.ServerRunOptions
- }
- // Complete set default ServerRunOptions.
- // Should be called after kube-apiserver flags parsed.
- func Complete(s *options.ServerRunOptions) (completedServerRunOptions, error) {
- var options completedServerRunOptions
- // set defaults
- if err := s.GenericServerRunOptions.DefaultAdvertiseAddress(s.SecureServing.SecureServingOptions); err != nil {
- return options, err
- }
- if err := kubeoptions.DefaultAdvertiseAddress(s.GenericServerRunOptions, s.InsecureServing.DeprecatedInsecureServingOptions); err != nil {
- return options, err
- }
- serviceIPRange, apiServerServiceIP, err := master.DefaultServiceIPRange(s.ServiceClusterIPRange)
- if err != nil {
- return options, fmt.Errorf("error determining service IP ranges: %v", err)
- }
- s.ServiceClusterIPRange = serviceIPRange
- if err := s.SecureServing.MaybeDefaultWithSelfSignedCerts(s.GenericServerRunOptions.AdvertiseAddress.String(), []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}, []net.IP{apiServerServiceIP}); err != nil {
- return options, fmt.Errorf("error creating self-signed certificates: %v", err)
- }
- if len(s.GenericServerRunOptions.ExternalHost) == 0 {
- if len(s.GenericServerRunOptions.AdvertiseAddress) > 0 {
- s.GenericServerRunOptions.ExternalHost = s.GenericServerRunOptions.AdvertiseAddress.String()
- } else {
- if hostname, err := os.Hostname(); err == nil {
- s.GenericServerRunOptions.ExternalHost = hostname
- } else {
- return options, fmt.Errorf("error finding host name: %v", err)
- }
- }
- klog.Infof("external host was not specified, using %v", s.GenericServerRunOptions.ExternalHost)
- }
- s.Authentication.ApplyAuthorization(s.Authorization)
- // Use (ServiceAccountSigningKeyFile != "") as a proxy to the user enabling
- // TokenRequest functionality. This defaulting was convenient, but messed up
- // a lot of people when they rotated their serving cert with no idea it was
- // connected to their service account keys. We are taking this oppurtunity to
- // remove this problematic defaulting.
- if s.ServiceAccountSigningKeyFile == "" {
- // Default to the private server key for service account token signing
- if len(s.Authentication.ServiceAccounts.KeyFiles) == 0 && s.SecureServing.ServerCert.CertKey.KeyFile != "" {
- if kubeauthenticator.IsValidServiceAccountKeyFile(s.SecureServing.ServerCert.CertKey.KeyFile) {
- s.Authentication.ServiceAccounts.KeyFiles = []string{s.SecureServing.ServerCert.CertKey.KeyFile}
- } else {
- klog.Warning("No TLS key provided, service account token authentication disabled")
- }
- }
- }
- if s.ServiceAccountSigningKeyFile != "" && s.Authentication.ServiceAccounts.Issuer != "" {
- sk, err := keyutil.PrivateKeyFromFile(s.ServiceAccountSigningKeyFile)
- if err != nil {
- return options, fmt.Errorf("failed to parse service-account-issuer-key-file: %v", err)
- }
- if s.Authentication.ServiceAccounts.MaxExpiration != 0 {
- lowBound := time.Hour
- upBound := time.Duration(1<<32) * time.Second
- if s.Authentication.ServiceAccounts.MaxExpiration < lowBound ||
- s.Authentication.ServiceAccounts.MaxExpiration > upBound {
- return options, fmt.Errorf("the serviceaccount max expiration must be between 1 hour to 2^32 seconds")
- }
- }
- s.ServiceAccountIssuer, err = serviceaccount.JWTTokenGenerator(s.Authentication.ServiceAccounts.Issuer, sk)
- if err != nil {
- return options, fmt.Errorf("failed to build token generator: %v", err)
- }
- s.ServiceAccountTokenMaxExpiration = s.Authentication.ServiceAccounts.MaxExpiration
- }
- if s.Etcd.EnableWatchCache {
- klog.V(2).Infof("Initializing cache sizes based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB)
- sizes := cachesize.NewHeuristicWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB)
- if userSpecified, err := serveroptions.ParseWatchCacheSizes(s.Etcd.WatchCacheSizes); err == nil {
- for resource, size := range userSpecified {
- sizes[resource] = size
- }
- }
- s.Etcd.WatchCacheSizes, err = serveroptions.WriteWatchCacheSizes(sizes)
- if err != nil {
- return options, err
- }
- }
- // TODO: remove when we stop supporting the legacy group version.
- if s.APIEnablement.RuntimeConfig != nil {
- for key, value := range s.APIEnablement.RuntimeConfig {
- if key == "v1" || strings.HasPrefix(key, "v1/") ||
- key == "api/v1" || strings.HasPrefix(key, "api/v1/") {
- delete(s.APIEnablement.RuntimeConfig, key)
- s.APIEnablement.RuntimeConfig["/v1"] = value
- }
- if key == "api/legacy" {
- delete(s.APIEnablement.RuntimeConfig, key)
- }
- }
- }
- options.ServerRunOptions = s
- return options, nil
- }
- func buildServiceResolver(enabledAggregatorRouting bool, hostname string, informer clientgoinformers.SharedInformerFactory) webhook.ServiceResolver {
- var serviceResolver webhook.ServiceResolver
- if enabledAggregatorRouting {
- serviceResolver = aggregatorapiserver.NewEndpointServiceResolver(
- informer.Core().V1().Services().Lister(),
- informer.Core().V1().Endpoints().Lister(),
- )
- } else {
- serviceResolver = aggregatorapiserver.NewClusterIPServiceResolver(
- informer.Core().V1().Services().Lister(),
- )
- }
- // resolve kubernetes.default.svc locally
- if localHost, err := url.Parse(hostname); err == nil {
- serviceResolver = aggregatorapiserver.NewLoopbackServiceResolver(serviceResolver, localHost)
- }
- return serviceResolver
- }
- func readCAorNil(file string) ([]byte, error) {
- if len(file) == 0 {
- return nil, nil
- }
- return ioutil.ReadFile(file)
- }
|