server.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // Package app does all of the work necessary to create a Kubernetes
  14. // APIServer by binding together the API, master and APIServer infrastructure.
  15. // It can be configured and called directly or via the hyperkube framework.
  16. package app
  17. import (
  18. "crypto/tls"
  19. "fmt"
  20. "io/ioutil"
  21. "net"
  22. "net/http"
  23. "net/url"
  24. "os"
  25. "strconv"
  26. "strings"
  27. "time"
  28. "github.com/go-openapi/spec"
  29. "github.com/spf13/cobra"
  30. extensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
  31. v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  32. utilerrors "k8s.io/apimachinery/pkg/util/errors"
  33. utilnet "k8s.io/apimachinery/pkg/util/net"
  34. "k8s.io/apimachinery/pkg/util/sets"
  35. utilwait "k8s.io/apimachinery/pkg/util/wait"
  36. "k8s.io/apiserver/pkg/admission"
  37. "k8s.io/apiserver/pkg/authentication/authenticator"
  38. "k8s.io/apiserver/pkg/authorization/authorizer"
  39. openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
  40. genericapiserver "k8s.io/apiserver/pkg/server"
  41. "k8s.io/apiserver/pkg/server/filters"
  42. serveroptions "k8s.io/apiserver/pkg/server/options"
  43. serverstorage "k8s.io/apiserver/pkg/server/storage"
  44. "k8s.io/apiserver/pkg/storage/etcd3/preflight"
  45. "k8s.io/apiserver/pkg/util/term"
  46. "k8s.io/apiserver/pkg/util/webhook"
  47. clientgoinformers "k8s.io/client-go/informers"
  48. clientgoclientset "k8s.io/client-go/kubernetes"
  49. "k8s.io/client-go/util/keyutil"
  50. cloudprovider "k8s.io/cloud-provider"
  51. cliflag "k8s.io/component-base/cli/flag"
  52. "k8s.io/component-base/cli/globalflag"
  53. "k8s.io/klog"
  54. aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver"
  55. aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
  56. "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
  57. "k8s.io/kubernetes/pkg/api/legacyscheme"
  58. "k8s.io/kubernetes/pkg/capabilities"
  59. serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
  60. generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
  61. "k8s.io/kubernetes/pkg/kubeapiserver"
  62. kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
  63. kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator"
  64. "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
  65. kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
  66. kubeserver "k8s.io/kubernetes/pkg/kubeapiserver/server"
  67. "k8s.io/kubernetes/pkg/master"
  68. "k8s.io/kubernetes/pkg/master/reconcilers"
  69. "k8s.io/kubernetes/pkg/master/tunneler"
  70. "k8s.io/kubernetes/pkg/registry/cachesize"
  71. rbacrest "k8s.io/kubernetes/pkg/registry/rbac/rest"
  72. "k8s.io/kubernetes/pkg/serviceaccount"
  73. utilflag "k8s.io/kubernetes/pkg/util/flag"
  74. _ "k8s.io/kubernetes/pkg/util/workqueue/prometheus" // for workqueue metric registration
  75. "k8s.io/kubernetes/pkg/version"
  76. "k8s.io/kubernetes/pkg/version/verflag"
  77. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
  78. )
  79. const (
  80. etcdRetryLimit = 60
  81. etcdRetryInterval = 1 * time.Second
  82. )
  83. // NewAPIServerCommand creates a *cobra.Command object with default parameters
  84. func NewAPIServerCommand() *cobra.Command {
  85. s := options.NewServerRunOptions()
  86. cmd := &cobra.Command{
  87. Use: "kube-apiserver",
  88. Long: `The Kubernetes API server validates and configures data
  89. for the api objects which include pods, services, replicationcontrollers, and
  90. others. The API Server services REST operations and provides the frontend to the
  91. cluster's shared state through which all other components interact.`,
  92. RunE: func(cmd *cobra.Command, args []string) error {
  93. verflag.PrintAndExitIfRequested()
  94. utilflag.PrintFlags(cmd.Flags())
  95. // set default options
  96. completedOptions, err := Complete(s)
  97. if err != nil {
  98. return err
  99. }
  100. // validate options
  101. if errs := completedOptions.Validate(); len(errs) != 0 {
  102. return utilerrors.NewAggregate(errs)
  103. }
  104. return Run(completedOptions, genericapiserver.SetupSignalHandler())
  105. },
  106. }
  107. fs := cmd.Flags()
  108. namedFlagSets := s.Flags()
  109. verflag.AddFlags(namedFlagSets.FlagSet("global"))
  110. globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())
  111. options.AddCustomGlobalFlags(namedFlagSets.FlagSet("generic"))
  112. for _, f := range namedFlagSets.FlagSets {
  113. fs.AddFlagSet(f)
  114. }
  115. usageFmt := "Usage:\n %s\n"
  116. cols, _, _ := term.TerminalSize(cmd.OutOrStdout())
  117. cmd.SetUsageFunc(func(cmd *cobra.Command) error {
  118. fmt.Fprintf(cmd.OutOrStderr(), usageFmt, cmd.UseLine())
  119. cliflag.PrintSections(cmd.OutOrStderr(), namedFlagSets, cols)
  120. return nil
  121. })
  122. cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
  123. fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n"+usageFmt, cmd.Long, cmd.UseLine())
  124. cliflag.PrintSections(cmd.OutOrStdout(), namedFlagSets, cols)
  125. })
  126. return cmd
  127. }
  128. // Run runs the specified APIServer. This should never exit.
  129. func Run(completeOptions completedServerRunOptions, stopCh <-chan struct{}) error {
  130. // To help debugging, immediately log version
  131. klog.Infof("Version: %+v", version.Get())
  132. server, err := CreateServerChain(completeOptions, stopCh)
  133. if err != nil {
  134. return err
  135. }
  136. return server.PrepareRun().Run(stopCh)
  137. }
  138. // CreateServerChain creates the apiservers connected via delegation.
  139. func CreateServerChain(completedOptions completedServerRunOptions, stopCh <-chan struct{}) (*genericapiserver.GenericAPIServer, error) {
  140. nodeTunneler, proxyTransport, err := CreateNodeDialer(completedOptions)
  141. if err != nil {
  142. return nil, err
  143. }
  144. kubeAPIServerConfig, insecureServingInfo, serviceResolver, pluginInitializer, admissionPostStartHook, err := CreateKubeAPIServerConfig(completedOptions, nodeTunneler, proxyTransport)
  145. if err != nil {
  146. return nil, err
  147. }
  148. // If additional API servers are added, they should be gated.
  149. apiExtensionsConfig, err := createAPIExtensionsConfig(*kubeAPIServerConfig.GenericConfig, kubeAPIServerConfig.ExtraConfig.VersionedInformers, pluginInitializer, completedOptions.ServerRunOptions, completedOptions.MasterCount,
  150. serviceResolver, webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, kubeAPIServerConfig.GenericConfig.LoopbackClientConfig))
  151. if err != nil {
  152. return nil, err
  153. }
  154. apiExtensionsServer, err := createAPIExtensionsServer(apiExtensionsConfig, genericapiserver.NewEmptyDelegate())
  155. if err != nil {
  156. return nil, err
  157. }
  158. kubeAPIServer, err := CreateKubeAPIServer(kubeAPIServerConfig, apiExtensionsServer.GenericAPIServer, admissionPostStartHook)
  159. if err != nil {
  160. return nil, err
  161. }
  162. // otherwise go down the normal path of standing the aggregator up in front of the API server
  163. // this wires up openapi
  164. kubeAPIServer.GenericAPIServer.PrepareRun()
  165. // This will wire up openapi for extension api server
  166. apiExtensionsServer.GenericAPIServer.PrepareRun()
  167. // aggregator comes last in the chain
  168. aggregatorConfig, err := createAggregatorConfig(*kubeAPIServerConfig.GenericConfig, completedOptions.ServerRunOptions, kubeAPIServerConfig.ExtraConfig.VersionedInformers, serviceResolver, proxyTransport, pluginInitializer)
  169. if err != nil {
  170. return nil, err
  171. }
  172. aggregatorServer, err := createAggregatorServer(aggregatorConfig, kubeAPIServer.GenericAPIServer, apiExtensionsServer.Informers)
  173. if err != nil {
  174. // we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines
  175. return nil, err
  176. }
  177. if insecureServingInfo != nil {
  178. insecureHandlerChain := kubeserver.BuildInsecureHandlerChain(aggregatorServer.GenericAPIServer.UnprotectedHandler(), kubeAPIServerConfig.GenericConfig)
  179. if err := insecureServingInfo.Serve(insecureHandlerChain, kubeAPIServerConfig.GenericConfig.RequestTimeout, stopCh); err != nil {
  180. return nil, err
  181. }
  182. }
  183. return aggregatorServer.GenericAPIServer, nil
  184. }
  185. // CreateKubeAPIServer creates and wires a workable kube-apiserver
  186. func CreateKubeAPIServer(kubeAPIServerConfig *master.Config, delegateAPIServer genericapiserver.DelegationTarget, admissionPostStartHook genericapiserver.PostStartHookFunc) (*master.Master, error) {
  187. kubeAPIServer, err := kubeAPIServerConfig.Complete().New(delegateAPIServer)
  188. if err != nil {
  189. return nil, err
  190. }
  191. kubeAPIServer.GenericAPIServer.AddPostStartHookOrDie("start-kube-apiserver-admission-initializer", admissionPostStartHook)
  192. return kubeAPIServer, nil
  193. }
  194. // CreateNodeDialer creates the dialer infrastructure to connect to the nodes.
  195. func CreateNodeDialer(s completedServerRunOptions) (tunneler.Tunneler, *http.Transport, error) {
  196. // Setup nodeTunneler if needed
  197. var nodeTunneler tunneler.Tunneler
  198. var proxyDialerFn utilnet.DialFunc
  199. if len(s.SSHUser) > 0 {
  200. // Get ssh key distribution func, if supported
  201. var installSSHKey tunneler.InstallSSHKey
  202. cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider.CloudProvider, s.CloudProvider.CloudConfigFile)
  203. if err != nil {
  204. return nil, nil, fmt.Errorf("cloud provider could not be initialized: %v", err)
  205. }
  206. if cloud != nil {
  207. if instances, supported := cloud.Instances(); supported {
  208. installSSHKey = instances.AddSSHKeyToAllInstances
  209. }
  210. }
  211. if s.KubeletConfig.Port == 0 {
  212. return nil, nil, fmt.Errorf("must enable kubelet port if proxy ssh-tunneling is specified")
  213. }
  214. if s.KubeletConfig.ReadOnlyPort == 0 {
  215. return nil, nil, fmt.Errorf("must enable kubelet readonly port if proxy ssh-tunneling is specified")
  216. }
  217. // Set up the nodeTunneler
  218. // TODO(cjcullen): If we want this to handle per-kubelet ports or other
  219. // kubelet listen-addresses, we need to plumb through options.
  220. healthCheckPath := &url.URL{
  221. Scheme: "http",
  222. Host: net.JoinHostPort("127.0.0.1", strconv.FormatUint(uint64(s.KubeletConfig.ReadOnlyPort), 10)),
  223. Path: "healthz",
  224. }
  225. nodeTunneler = tunneler.New(s.SSHUser, s.SSHKeyfile, healthCheckPath, installSSHKey)
  226. // Use the nodeTunneler's dialer when proxying to pods, services, and nodes
  227. proxyDialerFn = nodeTunneler.Dial
  228. }
  229. // Proxying to pods and services is IP-based... don't expect to be able to verify the hostname
  230. proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true}
  231. proxyTransport := utilnet.SetTransportDefaults(&http.Transport{
  232. DialContext: proxyDialerFn,
  233. TLSClientConfig: proxyTLSClientConfig,
  234. })
  235. return nodeTunneler, proxyTransport, nil
  236. }
  237. // CreateKubeAPIServerConfig creates all the resources for running the API server, but runs none of them
  238. func CreateKubeAPIServerConfig(
  239. s completedServerRunOptions,
  240. nodeTunneler tunneler.Tunneler,
  241. proxyTransport *http.Transport,
  242. ) (
  243. config *master.Config,
  244. insecureServingInfo *genericapiserver.DeprecatedInsecureServingInfo,
  245. serviceResolver aggregatorapiserver.ServiceResolver,
  246. pluginInitializers []admission.PluginInitializer,
  247. admissionPostStartHook genericapiserver.PostStartHookFunc,
  248. lastErr error,
  249. ) {
  250. var genericConfig *genericapiserver.Config
  251. var storageFactory *serverstorage.DefaultStorageFactory
  252. var versionedInformers clientgoinformers.SharedInformerFactory
  253. genericConfig, versionedInformers, insecureServingInfo, serviceResolver, pluginInitializers, admissionPostStartHook, storageFactory, lastErr = buildGenericConfig(s.ServerRunOptions, proxyTransport)
  254. if lastErr != nil {
  255. return
  256. }
  257. if _, port, err := net.SplitHostPort(s.Etcd.StorageConfig.Transport.ServerList[0]); err == nil && port != "0" && len(port) != 0 {
  258. if err := utilwait.PollImmediate(etcdRetryInterval, etcdRetryLimit*etcdRetryInterval, preflight.EtcdConnection{ServerList: s.Etcd.StorageConfig.Transport.ServerList}.CheckEtcdServers); err != nil {
  259. lastErr = fmt.Errorf("error waiting for etcd connection: %v", err)
  260. return
  261. }
  262. }
  263. capabilities.Initialize(capabilities.Capabilities{
  264. AllowPrivileged: s.AllowPrivileged,
  265. // TODO(vmarmol): Implement support for HostNetworkSources.
  266. PrivilegedSources: capabilities.PrivilegedSources{
  267. HostNetworkSources: []string{},
  268. HostPIDSources: []string{},
  269. HostIPCSources: []string{},
  270. },
  271. PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec,
  272. })
  273. serviceIPRange, apiServerServiceIP, lastErr := master.DefaultServiceIPRange(s.ServiceClusterIPRange)
  274. if lastErr != nil {
  275. return
  276. }
  277. clientCA, lastErr := readCAorNil(s.Authentication.ClientCert.ClientCA)
  278. if lastErr != nil {
  279. return
  280. }
  281. requestHeaderProxyCA, lastErr := readCAorNil(s.Authentication.RequestHeader.ClientCAFile)
  282. if lastErr != nil {
  283. return
  284. }
  285. config = &master.Config{
  286. GenericConfig: genericConfig,
  287. ExtraConfig: master.ExtraConfig{
  288. ClientCARegistrationHook: master.ClientCARegistrationHook{
  289. ClientCA: clientCA,
  290. RequestHeaderUsernameHeaders: s.Authentication.RequestHeader.UsernameHeaders,
  291. RequestHeaderGroupHeaders: s.Authentication.RequestHeader.GroupHeaders,
  292. RequestHeaderExtraHeaderPrefixes: s.Authentication.RequestHeader.ExtraHeaderPrefixes,
  293. RequestHeaderCA: requestHeaderProxyCA,
  294. RequestHeaderAllowedNames: s.Authentication.RequestHeader.AllowedNames,
  295. },
  296. APIResourceConfigSource: storageFactory.APIResourceConfigSource,
  297. StorageFactory: storageFactory,
  298. EventTTL: s.EventTTL,
  299. KubeletClientConfig: s.KubeletConfig,
  300. EnableLogsSupport: s.EnableLogsHandler,
  301. ProxyTransport: proxyTransport,
  302. Tunneler: nodeTunneler,
  303. ServiceIPRange: serviceIPRange,
  304. APIServerServiceIP: apiServerServiceIP,
  305. APIServerServicePort: 443,
  306. ServiceNodePortRange: s.ServiceNodePortRange,
  307. KubernetesServiceNodePort: s.KubernetesServiceNodePort,
  308. EndpointReconcilerType: reconcilers.Type(s.EndpointReconcilerType),
  309. MasterCount: s.MasterCount,
  310. ServiceAccountIssuer: s.ServiceAccountIssuer,
  311. ServiceAccountMaxExpiration: s.ServiceAccountTokenMaxExpiration,
  312. VersionedInformers: versionedInformers,
  313. },
  314. }
  315. if nodeTunneler != nil {
  316. // Use the nodeTunneler's dialer to connect to the kubelet
  317. config.ExtraConfig.KubeletClientConfig.Dial = nodeTunneler.Dial
  318. }
  319. return
  320. }
  321. // BuildGenericConfig takes the master server options and produces the genericapiserver.Config associated with it
  322. func buildGenericConfig(
  323. s *options.ServerRunOptions,
  324. proxyTransport *http.Transport,
  325. ) (
  326. genericConfig *genericapiserver.Config,
  327. versionedInformers clientgoinformers.SharedInformerFactory,
  328. insecureServingInfo *genericapiserver.DeprecatedInsecureServingInfo,
  329. serviceResolver aggregatorapiserver.ServiceResolver,
  330. pluginInitializers []admission.PluginInitializer,
  331. admissionPostStartHook genericapiserver.PostStartHookFunc,
  332. storageFactory *serverstorage.DefaultStorageFactory,
  333. lastErr error,
  334. ) {
  335. genericConfig = genericapiserver.NewConfig(legacyscheme.Codecs)
  336. genericConfig.MergedResourceConfig = master.DefaultAPIResourceConfigSource()
  337. if lastErr = s.GenericServerRunOptions.ApplyTo(genericConfig); lastErr != nil {
  338. return
  339. }
  340. if lastErr = s.InsecureServing.ApplyTo(&insecureServingInfo, &genericConfig.LoopbackClientConfig); lastErr != nil {
  341. return
  342. }
  343. if lastErr = s.SecureServing.ApplyTo(&genericConfig.SecureServing, &genericConfig.LoopbackClientConfig); lastErr != nil {
  344. return
  345. }
  346. if lastErr = s.Authentication.ApplyTo(genericConfig); lastErr != nil {
  347. return
  348. }
  349. if lastErr = s.Features.ApplyTo(genericConfig); lastErr != nil {
  350. return
  351. }
  352. if lastErr = s.APIEnablement.ApplyTo(genericConfig, master.DefaultAPIResourceConfigSource(), legacyscheme.Scheme); lastErr != nil {
  353. return
  354. }
  355. genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(legacyscheme.Scheme, extensionsapiserver.Scheme, aggregatorscheme.Scheme))
  356. genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
  357. genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
  358. sets.NewString("watch", "proxy"),
  359. sets.NewString("attach", "exec", "proxy", "log", "portforward"),
  360. )
  361. kubeVersion := version.Get()
  362. genericConfig.Version = &kubeVersion
  363. storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig()
  364. storageFactoryConfig.ApiResourceConfig = genericConfig.MergedResourceConfig
  365. completedStorageFactoryConfig, err := storageFactoryConfig.Complete(s.Etcd)
  366. if err != nil {
  367. lastErr = err
  368. return
  369. }
  370. storageFactory, lastErr = completedStorageFactoryConfig.New()
  371. if lastErr != nil {
  372. return
  373. }
  374. if lastErr = s.Etcd.ApplyWithStorageFactoryTo(storageFactory, genericConfig); lastErr != nil {
  375. return
  376. }
  377. // Use protobufs for self-communication.
  378. // Since not every generic apiserver has to support protobufs, we
  379. // cannot default to it in generic apiserver and need to explicitly
  380. // set it in kube-apiserver.
  381. genericConfig.LoopbackClientConfig.ContentConfig.ContentType = "application/vnd.kubernetes.protobuf"
  382. kubeClientConfig := genericConfig.LoopbackClientConfig
  383. clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeClientConfig)
  384. if err != nil {
  385. lastErr = fmt.Errorf("failed to create real external clientset: %v", err)
  386. return
  387. }
  388. versionedInformers = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)
  389. genericConfig.Authentication.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, clientgoExternalClient, versionedInformers)
  390. if err != nil {
  391. lastErr = fmt.Errorf("invalid authentication config: %v", err)
  392. return
  393. }
  394. genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, err = BuildAuthorizer(s, versionedInformers)
  395. if err != nil {
  396. lastErr = fmt.Errorf("invalid authorization config: %v", err)
  397. return
  398. }
  399. if !sets.NewString(s.Authorization.Modes...).Has(modes.ModeRBAC) {
  400. genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName)
  401. }
  402. admissionConfig := &kubeapiserveradmission.Config{
  403. ExternalInformers: versionedInformers,
  404. LoopbackClientConfig: genericConfig.LoopbackClientConfig,
  405. CloudConfigFile: s.CloudProvider.CloudConfigFile,
  406. }
  407. serviceResolver = buildServiceResolver(s.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers)
  408. authInfoResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, genericConfig.LoopbackClientConfig)
  409. lastErr = s.Audit.ApplyTo(
  410. genericConfig,
  411. genericConfig.LoopbackClientConfig,
  412. versionedInformers,
  413. serveroptions.NewProcessInfo("kube-apiserver", "kube-system"),
  414. &serveroptions.WebhookOptions{
  415. AuthInfoResolverWrapper: authInfoResolverWrapper,
  416. ServiceResolver: serviceResolver,
  417. },
  418. )
  419. if lastErr != nil {
  420. return
  421. }
  422. pluginInitializers, admissionPostStartHook, err = admissionConfig.New(proxyTransport, serviceResolver)
  423. if err != nil {
  424. lastErr = fmt.Errorf("failed to create admission plugin initializer: %v", err)
  425. return
  426. }
  427. err = s.Admission.ApplyTo(
  428. genericConfig,
  429. versionedInformers,
  430. kubeClientConfig,
  431. pluginInitializers...)
  432. if err != nil {
  433. lastErr = fmt.Errorf("failed to initialize admission: %v", err)
  434. }
  435. return
  436. }
  437. // BuildAuthenticator constructs the authenticator
  438. func BuildAuthenticator(s *options.ServerRunOptions, extclient clientgoclientset.Interface, versionedInformer clientgoinformers.SharedInformerFactory) (authenticator.Request, *spec.SecurityDefinitions, error) {
  439. authenticatorConfig := s.Authentication.ToAuthenticationConfig()
  440. if s.Authentication.ServiceAccounts.Lookup {
  441. authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromClient(
  442. extclient,
  443. versionedInformer.Core().V1().Secrets().Lister(),
  444. versionedInformer.Core().V1().ServiceAccounts().Lister(),
  445. versionedInformer.Core().V1().Pods().Lister(),
  446. )
  447. }
  448. authenticatorConfig.BootstrapTokenAuthenticator = bootstrap.NewTokenAuthenticator(
  449. versionedInformer.Core().V1().Secrets().Lister().Secrets(v1.NamespaceSystem),
  450. )
  451. return authenticatorConfig.New()
  452. }
  453. // BuildAuthorizer constructs the authorizer
  454. func BuildAuthorizer(s *options.ServerRunOptions, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, error) {
  455. authorizationConfig := s.Authorization.ToAuthorizationConfig(versionedInformers)
  456. return authorizationConfig.New()
  457. }
  458. // completedServerRunOptions is a private wrapper that enforces a call of Complete() before Run can be invoked.
  459. type completedServerRunOptions struct {
  460. *options.ServerRunOptions
  461. }
  462. // Complete set default ServerRunOptions.
  463. // Should be called after kube-apiserver flags parsed.
  464. func Complete(s *options.ServerRunOptions) (completedServerRunOptions, error) {
  465. var options completedServerRunOptions
  466. // set defaults
  467. if err := s.GenericServerRunOptions.DefaultAdvertiseAddress(s.SecureServing.SecureServingOptions); err != nil {
  468. return options, err
  469. }
  470. if err := kubeoptions.DefaultAdvertiseAddress(s.GenericServerRunOptions, s.InsecureServing.DeprecatedInsecureServingOptions); err != nil {
  471. return options, err
  472. }
  473. serviceIPRange, apiServerServiceIP, err := master.DefaultServiceIPRange(s.ServiceClusterIPRange)
  474. if err != nil {
  475. return options, fmt.Errorf("error determining service IP ranges: %v", err)
  476. }
  477. s.ServiceClusterIPRange = serviceIPRange
  478. if err := s.SecureServing.MaybeDefaultWithSelfSignedCerts(s.GenericServerRunOptions.AdvertiseAddress.String(), []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}, []net.IP{apiServerServiceIP}); err != nil {
  479. return options, fmt.Errorf("error creating self-signed certificates: %v", err)
  480. }
  481. if len(s.GenericServerRunOptions.ExternalHost) == 0 {
  482. if len(s.GenericServerRunOptions.AdvertiseAddress) > 0 {
  483. s.GenericServerRunOptions.ExternalHost = s.GenericServerRunOptions.AdvertiseAddress.String()
  484. } else {
  485. if hostname, err := os.Hostname(); err == nil {
  486. s.GenericServerRunOptions.ExternalHost = hostname
  487. } else {
  488. return options, fmt.Errorf("error finding host name: %v", err)
  489. }
  490. }
  491. klog.Infof("external host was not specified, using %v", s.GenericServerRunOptions.ExternalHost)
  492. }
  493. s.Authentication.ApplyAuthorization(s.Authorization)
  494. // Use (ServiceAccountSigningKeyFile != "") as a proxy to the user enabling
  495. // TokenRequest functionality. This defaulting was convenient, but messed up
  496. // a lot of people when they rotated their serving cert with no idea it was
  497. // connected to their service account keys. We are taking this oppurtunity to
  498. // remove this problematic defaulting.
  499. if s.ServiceAccountSigningKeyFile == "" {
  500. // Default to the private server key for service account token signing
  501. if len(s.Authentication.ServiceAccounts.KeyFiles) == 0 && s.SecureServing.ServerCert.CertKey.KeyFile != "" {
  502. if kubeauthenticator.IsValidServiceAccountKeyFile(s.SecureServing.ServerCert.CertKey.KeyFile) {
  503. s.Authentication.ServiceAccounts.KeyFiles = []string{s.SecureServing.ServerCert.CertKey.KeyFile}
  504. } else {
  505. klog.Warning("No TLS key provided, service account token authentication disabled")
  506. }
  507. }
  508. }
  509. if s.ServiceAccountSigningKeyFile != "" && s.Authentication.ServiceAccounts.Issuer != "" {
  510. sk, err := keyutil.PrivateKeyFromFile(s.ServiceAccountSigningKeyFile)
  511. if err != nil {
  512. return options, fmt.Errorf("failed to parse service-account-issuer-key-file: %v", err)
  513. }
  514. if s.Authentication.ServiceAccounts.MaxExpiration != 0 {
  515. lowBound := time.Hour
  516. upBound := time.Duration(1<<32) * time.Second
  517. if s.Authentication.ServiceAccounts.MaxExpiration < lowBound ||
  518. s.Authentication.ServiceAccounts.MaxExpiration > upBound {
  519. return options, fmt.Errorf("the serviceaccount max expiration must be between 1 hour to 2^32 seconds")
  520. }
  521. }
  522. s.ServiceAccountIssuer, err = serviceaccount.JWTTokenGenerator(s.Authentication.ServiceAccounts.Issuer, sk)
  523. if err != nil {
  524. return options, fmt.Errorf("failed to build token generator: %v", err)
  525. }
  526. s.ServiceAccountTokenMaxExpiration = s.Authentication.ServiceAccounts.MaxExpiration
  527. }
  528. if s.Etcd.EnableWatchCache {
  529. klog.V(2).Infof("Initializing cache sizes based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB)
  530. sizes := cachesize.NewHeuristicWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB)
  531. if userSpecified, err := serveroptions.ParseWatchCacheSizes(s.Etcd.WatchCacheSizes); err == nil {
  532. for resource, size := range userSpecified {
  533. sizes[resource] = size
  534. }
  535. }
  536. s.Etcd.WatchCacheSizes, err = serveroptions.WriteWatchCacheSizes(sizes)
  537. if err != nil {
  538. return options, err
  539. }
  540. }
  541. // TODO: remove when we stop supporting the legacy group version.
  542. if s.APIEnablement.RuntimeConfig != nil {
  543. for key, value := range s.APIEnablement.RuntimeConfig {
  544. if key == "v1" || strings.HasPrefix(key, "v1/") ||
  545. key == "api/v1" || strings.HasPrefix(key, "api/v1/") {
  546. delete(s.APIEnablement.RuntimeConfig, key)
  547. s.APIEnablement.RuntimeConfig["/v1"] = value
  548. }
  549. if key == "api/legacy" {
  550. delete(s.APIEnablement.RuntimeConfig, key)
  551. }
  552. }
  553. }
  554. options.ServerRunOptions = s
  555. return options, nil
  556. }
  557. func buildServiceResolver(enabledAggregatorRouting bool, hostname string, informer clientgoinformers.SharedInformerFactory) webhook.ServiceResolver {
  558. var serviceResolver webhook.ServiceResolver
  559. if enabledAggregatorRouting {
  560. serviceResolver = aggregatorapiserver.NewEndpointServiceResolver(
  561. informer.Core().V1().Services().Lister(),
  562. informer.Core().V1().Endpoints().Lister(),
  563. )
  564. } else {
  565. serviceResolver = aggregatorapiserver.NewClusterIPServiceResolver(
  566. informer.Core().V1().Services().Lister(),
  567. )
  568. }
  569. // resolve kubernetes.default.svc locally
  570. if localHost, err := url.Parse(hostname); err == nil {
  571. serviceResolver = aggregatorapiserver.NewLoopbackServiceResolver(serviceResolver, localHost)
  572. }
  573. return serviceResolver
  574. }
  575. func readCAorNil(file string) ([]byte, error) {
  576. if len(file) == 0 {
  577. return nil, nil
  578. }
  579. return ioutil.ReadFile(file)
  580. }