func setExtensionsDefaults(config *Config) error { // if experimental group is not registered, return an error g, err := latest.Group("extensions") if err != nil { return err } config.Prefix = "apis/" if config.UserAgent == "" { config.UserAgent = DefaultKubernetesUserAgent() } // TODO: Unconditionally set the config.Version, until we fix the config. //if config.Version == "" { config.Version = g.GroupVersion //} versionInterfaces, err := g.InterfacesFor(config.Version) if err != nil { return fmt.Errorf("Extensions API version '%s' is not recognized (valid values: %s)", config.Version, strings.Join(latest.GroupOrDie("extensions").Versions, ", ")) } config.Codec = versionInterfaces.Codec if config.QPS == 0 { config.QPS = 5 } if config.Burst == 0 { config.Burst = 10 } return nil }
// New creates a Kubernetes client for the given config. This client works with pods, // replication controllers, daemons, and services. It allows operations such as list, get, update // and delete on these objects. An error is returned if the provided configuration // is not valid. func New(c *Config) (*Client, error) { config := *c if err := SetKubernetesDefaults(&config); err != nil { return nil, err } client, err := RESTClientFor(&config) if err != nil { return nil, err } discoveryConfig := *c discoveryClient, err := NewDiscoveryClient(&discoveryConfig) if err != nil { return nil, err } if _, err := latest.Group("extensions"); err != nil { return &Client{RESTClient: client, ExtensionsClient: nil, DiscoveryClient: discoveryClient}, nil } experimentalConfig := *c experimentalClient, err := NewExtensions(&experimentalConfig) if err != nil { return nil, err } return &Client{RESTClient: client, ExtensionsClient: experimentalClient, DiscoveryClient: discoveryClient}, nil }
// InterfacesFor returns the default Codec and ResourceVersioner for a given version // string, or an error if the version is not known. func interfacesFor(version string) (*meta.VersionInterfaces, error) { switch version { case "extensions/v1beta1": return &meta.VersionInterfaces{ Codec: v1beta1.Codec, ObjectConvertor: api.Scheme, MetadataAccessor: accessor, }, nil default: g, _ := latest.Group("extensions") return nil, fmt.Errorf("unsupported storage version: %s (valid: %s)", version, strings.Join(g.Versions, ", ")) } }
// RunExplain executes the appropriate steps to print a model's documentation func RunExplain(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if len(args) != 1 { return cmdutil.UsageError(cmd, "We accept only this format: explain RESOURCE") } client, err := f.Client() if err != nil { return err } recursive := cmdutil.GetFlagBool(cmd, "recursive") apiV := cmdutil.GetFlagString(cmd, "api-version") mapper, _ := f.Object() // TODO: After we figured out the new syntax to separate group and resource, allow // the users to use it in explain (kubectl explain <group><syntax><resource>). // Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax. inModel, fieldsPath, err := kubectl.SplitAndParseResourceRequest(args[0], mapper) if err != nil { return err } // TODO: We should deduce the group for a resource by discovering the supported resources at server. group, err := mapper.GroupForResource(inModel) if err != nil { return err } if len(apiV) == 0 { groupMeta, err := latest.Group(group) if err != nil { return err } apiV = groupMeta.GroupVersion } swagSchema, err := kubectl.GetSwaggerSchema(apiV, client) if err != nil { return err } return kubectl.PrintModelDescription(inModel, fieldsPath, out, swagSchema, recursive) }
// parse the value of --etcd-servers-overrides and update given storageDestinations. func updateEtcdOverrides(overrides []string, storageVersions map[string]string, prefix string, storageDestinations *master.StorageDestinations, newEtcdFn newEtcdFunc) { if len(overrides) == 0 { return } for _, override := range overrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) } group := apiresource[0] resource := apiresource[1] apigroup, err := latest.Group(group) if err != nil { glog.Errorf("invalid api group %s: %v", group, err) continue } if _, found := storageVersions[apigroup.Group]; !found { glog.Errorf("Couldn't find the storage version for group %s", apigroup.Group) continue } servers := strings.Split(tokens[1], ";") etcdOverrideStorage, err := newEtcdFn("", servers, apigroup.InterfacesFor, storageVersions[apigroup.Group], prefix) if err != nil { glog.Fatalf("Invalid storage version or misconfigured etcd for %s: %v", tokens[0], err) } storageDestinations.AddStorageOverride(group, resource, etcdOverrideStorage) } }
// init initializes master. func (m *Master) init(c *Config) { if c.ProxyDialer != nil || c.ProxyTLSClientConfig != nil { m.proxyTransport = util.SetTransportDefaults(&http.Transport{ Dial: c.ProxyDialer, TLSClientConfig: c.ProxyTLSClientConfig, }) } healthzChecks := []healthz.HealthzChecker{} dbClient := func(resource string) storage.Interface { return c.StorageDestinations.get("", resource) } podStorage := podetcd.NewStorage(dbClient("pods"), c.EnableWatchCache, c.KubeletClient, m.proxyTransport) podTemplateStorage := podtemplateetcd.NewREST(dbClient("podTemplates")) eventStorage := eventetcd.NewREST(dbClient("events"), uint64(c.EventTTL.Seconds())) limitRangeStorage := limitrangeetcd.NewREST(dbClient("limitRanges")) resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewREST(dbClient("resourceQuotas")) secretStorage := secretetcd.NewREST(dbClient("secrets")) serviceAccountStorage := serviceaccountetcd.NewREST(dbClient("serviceAccounts")) persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewREST(dbClient("persistentVolumes")) persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewREST(dbClient("persistentVolumeClaims")) namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewREST(dbClient("namespaces")) m.namespaceRegistry = namespace.NewRegistry(namespaceStorage) endpointsStorage := endpointsetcd.NewREST(dbClient("endpoints"), c.EnableWatchCache) m.endpointRegistry = endpoint.NewRegistry(endpointsStorage) nodeStorage, nodeStatusStorage := nodeetcd.NewREST(dbClient("nodes"), c.EnableWatchCache, c.KubeletClient, m.proxyTransport) m.nodeRegistry = node.NewRegistry(nodeStorage) serviceStorage := serviceetcd.NewREST(dbClient("services")) m.serviceRegistry = service.NewRegistry(serviceStorage) var serviceClusterIPRegistry service.RangeRegistry serviceClusterIPAllocator := ipallocator.NewAllocatorCIDRRange(m.serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) etcd := etcdallocator.NewEtcd(mem, "/ranges/serviceips", "serviceipallocation", dbClient("services")) serviceClusterIPRegistry = etcd return etcd }) m.serviceClusterIPAllocator = serviceClusterIPRegistry var serviceNodePortRegistry service.RangeRegistry serviceNodePortAllocator := portallocator.NewPortAllocatorCustom(m.serviceNodePortRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) etcd := etcdallocator.NewEtcd(mem, "/ranges/servicenodeports", "servicenodeportallocation", dbClient("services")) serviceNodePortRegistry = etcd return etcd }) m.serviceNodePortAllocator = serviceNodePortRegistry controllerStorage, controllerStatusStorage := controlleretcd.NewREST(dbClient("replicationControllers")) // TODO: Factor out the core API registration m.storage = map[string]rest.Storage{ "pods": podStorage.Pod, "pods/attach": podStorage.Attach, "pods/status": podStorage.Status, "pods/log": podStorage.Log, "pods/exec": podStorage.Exec, "pods/portforward": podStorage.PortForward, "pods/proxy": podStorage.Proxy, "pods/binding": podStorage.Binding, "bindings": podStorage.Binding, "podTemplates": podTemplateStorage, "replicationControllers": controllerStorage, "replicationControllers/status": controllerStatusStorage, "services": service.NewStorage(m.serviceRegistry, m.endpointRegistry, serviceClusterIPAllocator, serviceNodePortAllocator, m.proxyTransport), "endpoints": endpointsStorage, "nodes": nodeStorage, "nodes/status": nodeStatusStorage, "events": eventStorage, "limitRanges": limitRangeStorage, "resourceQuotas": resourceQuotaStorage, "resourceQuotas/status": resourceQuotaStatusStorage, "namespaces": namespaceStorage, "namespaces/status": namespaceStatusStorage, "namespaces/finalize": namespaceFinalizeStorage, "secrets": secretStorage, "serviceAccounts": serviceAccountStorage, "persistentVolumes": persistentVolumeStorage, "persistentVolumes/status": persistentVolumeStatusStorage, "persistentVolumeClaims": persistentVolumeClaimStorage, "persistentVolumeClaims/status": persistentVolumeClaimStatusStorage, "componentStatuses": componentstatus.NewStorage(func() map[string]apiserver.Server { return m.getServersToValidate(c) }), } if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) prometheus.NewGaugeFunc(prometheus.GaugeOpts{ Name: "apiserver_proxy_tunnel_sync_latency_secs", Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.", }, func() float64 { return float64(m.tunneler.SecondsSinceSync()) }) } apiVersions := []string{} // Install v1 unless disabled. if !m.apiGroupVersionOverrides["api/v1"].Disable { if err := m.api_v1().InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup API v1: %v", err) } apiVersions = append(apiVersions, "v1") } apiserver.InstallSupport(m.muxHelper, m.rootWebService, c.EnableProfiling, healthzChecks...) apiserver.AddApiWebService(m.handlerContainer, c.APIPrefix, apiVersions) defaultVersion := m.defaultAPIGroupVersion() requestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(defaultVersion.Root, "/")), RestMapper: defaultVersion.Mapper} apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions) // allGroups records all supported groups at /apis allGroups := []unversioned.APIGroup{} // Install extensions unless disabled. if !m.apiGroupVersionOverrides["extensions/v1beta1"].Disable { m.thirdPartyStorage = c.StorageDestinations.APIGroups["extensions"].Default m.thirdPartyResources = map[string]*thirdpartyresourcedataetcd.REST{} expVersion := m.experimental(c) if err := expVersion.InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup experimental api: %v", err) } g, err := latest.Group("extensions") if err != nil { glog.Fatalf("Unable to setup experimental api: %v", err) } expAPIVersions := []unversioned.GroupVersion{ { GroupVersion: expVersion.Version, Version: apiutil.GetVersion(expVersion.Version), }, } storageVersion, found := c.StorageVersions[g.Group] if !found { glog.Fatalf("Couldn't find storage version of group %v", g.Group) } group := unversioned.APIGroup{ Name: g.Group, Versions: expAPIVersions, PreferredVersion: unversioned.GroupVersion{GroupVersion: storageVersion, Version: apiutil.GetVersion(storageVersion)}, } apiserver.AddGroupWebService(m.handlerContainer, c.APIGroupPrefix+"/"+latest.GroupOrDie("extensions").Group, group) allGroups = append(allGroups, group) expRequestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(expVersion.Root, "/")), RestMapper: expVersion.Mapper} apiserver.InstallServiceErrorHandler(m.handlerContainer, expRequestInfoResolver, []string{expVersion.Version}) } // This should be done after all groups are registered // TODO: replace the hardcoded "apis". apiserver.AddApisWebService(m.handlerContainer, "/apis", allGroups) // Register root handler. // We do not register this using restful Webservice since we do not want to surface this in api docs. // Allow master to be embedded in contexts which already have something registered at the root if c.EnableIndex { m.mux.HandleFunc("/", apiserver.IndexHandler(m.handlerContainer, m.muxHelper)) } if c.EnableLogsSupport { apiserver.InstallLogsSupport(m.muxHelper) } if c.EnableUISupport { ui.InstallSupport(m.muxHelper, m.enableSwaggerSupport) } if c.EnableProfiling { m.mux.HandleFunc("/debug/pprof/", pprof.Index) m.mux.HandleFunc("/debug/pprof/profile", pprof.Profile) m.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) } handler := http.Handler(m.mux.(*http.ServeMux)) // TODO: handle CORS and auth using go-restful // See github.com/emicklei/go-restful/blob/master/examples/restful-CORS-filter.go, and // github.com/emicklei/go-restful/blob/master/examples/restful-basic-authentication.go if len(c.CorsAllowedOriginList) > 0 { allowedOriginRegexps, err := util.CompileRegexps(c.CorsAllowedOriginList) if err != nil { glog.Fatalf("Invalid CORS allowed origin, --cors-allowed-origins flag was set to %v - %v", strings.Join(c.CorsAllowedOriginList, ","), err) } handler = apiserver.CORS(handler, allowedOriginRegexps, nil, nil, "true") } m.InsecureHandler = handler attributeGetter := apiserver.NewRequestAttributeGetter(m.requestContextMapper, latest.GroupOrDie("").RESTMapper, "api") handler = apiserver.WithAuthorizationCheck(handler, attributeGetter, m.authorizer) // Install Authenticator if c.Authenticator != nil { authenticatedHandler, err := handlers.NewRequestAuthenticator(m.requestContextMapper, c.Authenticator, handlers.Unauthorized(c.SupportsBasicAuth), handler) if err != nil { glog.Fatalf("Could not initialize authenticator: %v", err) } handler = authenticatedHandler } // Install root web services m.handlerContainer.Add(m.rootWebService) // TODO: Make this optional? Consumers of master depend on this currently. m.Handler = handler if m.enableSwaggerSupport { m.InstallSwaggerAPI() } // After all wrapping is done, put a context filter around both handlers if handler, err := api.NewRequestContextFilter(m.requestContextMapper, m.Handler); err != nil { glog.Fatalf("Could not initialize request context filter: %v", err) } else { m.Handler = handler } if handler, err := api.NewRequestContextFilter(m.requestContextMapper, m.InsecureHandler); err != nil { glog.Fatalf("Could not initialize request context filter: %v", err) } else { m.InsecureHandler = handler } // TODO: Attempt clean shutdown? if m.enableCoreControllers { m.NewBootstrapController().Start() } }
// Run runs the specified APIServer. This should never exit. func (s *APIServer) Run(_ []string) error { s.verifyClusterIPFlags() // If advertise-address is not specified, use bind-address. If bind-address // is not usable (unset, 0.0.0.0, or loopback), setDefaults() in // pkg/master/master.go will do the right thing and use the host's default // interface. if s.AdvertiseAddress == nil || s.AdvertiseAddress.IsUnspecified() { s.AdvertiseAddress = s.BindAddress } if (s.EtcdConfigFile != "" && len(s.EtcdServerList) != 0) || (s.EtcdConfigFile == "" && len(s.EtcdServerList) == 0) { glog.Fatalf("specify either --etcd-servers or --etcd-config") } 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, }) cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } // Setup tunneler if needed var tunneler master.Tunneler var proxyDialerFn apiserver.ProxyDialerFunc if len(s.SSHUser) > 0 { // Get ssh key distribution func, if supported var installSSH master.InstallSSHKey if cloud != nil { if instances, supported := cloud.Instances(); supported { installSSH = instances.AddSSHKeyToAllInstances } } // Set up the tunneler tunneler = master.NewSSHTunneler(s.SSHUser, s.SSHKeyfile, installSSH) // Use the tunneler's dialer to connect to the kubelet s.KubeletConfig.Dial = tunneler.Dial // Use the tunneler's dialer when proxying to pods, services, and nodes proxyDialerFn = tunneler.Dial } // Proxying to pods and services is IP-based... don't expect to be able to verify the hostname proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true} kubeletClient, err := client.NewKubeletClient(&s.KubeletConfig) if err != nil { glog.Fatalf("Failure to start kubelet client: %v", err) } apiGroupVersionOverrides, err := s.parseRuntimeConfig() if err != nil { glog.Fatalf("error in parsing runtime-config: %s", err) } clientConfig := &client.Config{ Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)), Version: s.DeprecatedStorageVersion, } client, err := client.New(clientConfig) if err != nil { glog.Fatalf("Invalid server address: %v", err) } legacyV1Group, err := latest.Group("") if err != nil { return err } storageDestinations := master.NewStorageDestinations() storageVersions := generateStorageVersionMap(s.DeprecatedStorageVersion, s.StorageVersions) if _, found := storageVersions[legacyV1Group.Group]; !found { glog.Fatalf("Couldn't find the storage version for group: %q in storageVersions: %v", legacyV1Group.Group, storageVersions) } etcdStorage, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, legacyV1Group.InterfacesFor, storageVersions[legacyV1Group.Group], s.EtcdPathPrefix) if err != nil { glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err) } storageDestinations.AddAPIGroup("", etcdStorage) if !apiGroupVersionOverrides["extensions/v1beta1"].Disable { expGroup, err := latest.Group("extensions") if err != nil { glog.Fatalf("Extensions API is enabled in runtime config, but not enabled in the environment variable KUBE_API_VERSIONS. Error: %v", err) } if _, found := storageVersions[expGroup.Group]; !found { glog.Fatalf("Couldn't find the storage version for group: %q in storageVersions: %v", expGroup.Group, storageVersions) } expEtcdStorage, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, expGroup.InterfacesFor, storageVersions[expGroup.Group], s.EtcdPathPrefix) if err != nil { glog.Fatalf("Invalid extensions storage version or misconfigured etcd: %v", err) } storageDestinations.AddAPIGroup("extensions", expEtcdStorage) } updateEtcdOverrides(s.EtcdServersOverrides, storageVersions, s.EtcdPathPrefix, &storageDestinations, newEtcd) n := s.ServiceClusterIPRange // Default to the private server key for service account token signing if s.ServiceAccountKeyFile == "" && s.TLSPrivateKeyFile != "" { if apiserver.IsValidServiceAccountKeyFile(s.TLSPrivateKeyFile) { s.ServiceAccountKeyFile = s.TLSPrivateKeyFile } else { glog.Warning("no RSA key provided, service account token authentication disabled") } } authenticator, err := apiserver.NewAuthenticator(apiserver.AuthenticatorConfig{ BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, ServiceAccountKeyFile: s.ServiceAccountKeyFile, ServiceAccountLookup: s.ServiceAccountLookup, Storage: etcdStorage, KeystoneURL: s.KeystoneURL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, s.AuthorizationPolicyFile) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile) if len(s.ExternalHost) == 0 { // TODO: extend for other providers if s.CloudProvider == "gce" { instances, supported := cloud.Instances() if !supported { glog.Fatalf("gce cloud provider has no instances. this shouldn't happen. exiting.") } name, err := os.Hostname() if err != nil { glog.Fatalf("failed to get hostname: %v", err) } addrs, err := instances.NodeAddresses(name) if err != nil { glog.Warningf("unable to obtain external host address from cloud provider: %v", err) } else { for _, addr := range addrs { if addr.Type == api.NodeExternalIP { s.ExternalHost = addr.Address } } } } } config := &master.Config{ StorageDestinations: storageDestinations, StorageVersions: storageVersions, EventTTL: s.EventTTL, KubeletClient: kubeletClient, ServiceClusterIPRange: &n, EnableCoreControllers: true, EnableLogsSupport: s.EnableLogsSupport, EnableUISupport: true, EnableSwaggerSupport: true, EnableProfiling: s.EnableProfiling, EnableWatchCache: s.EnableWatchCache, EnableIndex: true, APIPrefix: s.APIPrefix, APIGroupPrefix: s.APIGroupPrefix, CorsAllowedOriginList: s.CorsAllowedOriginList, ReadWritePort: s.SecurePort, PublicAddress: s.AdvertiseAddress, Authenticator: authenticator, SupportsBasicAuth: len(s.BasicAuthFile) > 0, Authorizer: authorizer, AdmissionControl: admissionController, APIGroupVersionOverrides: apiGroupVersionOverrides, MasterServiceNamespace: s.MasterServiceNamespace, ClusterName: s.ClusterName, ExternalHost: s.ExternalHost, MinRequestTimeout: s.MinRequestTimeout, ProxyDialer: proxyDialerFn, ProxyTLSClientConfig: proxyTLSClientConfig, Tunneler: tunneler, ServiceNodePortRange: s.ServiceNodePortRange, } m := master.New(config) // We serve on 2 ports. See docs/accessing_the_api.md secureLocation := "" if s.SecurePort != 0 { secureLocation = net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.SecurePort)) } insecureLocation := net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)) // See the flag commentary to understand our assumptions when opening the read-only and read-write ports. var sem chan bool if s.MaxRequestsInFlight > 0 { sem = make(chan bool, s.MaxRequestsInFlight) } longRunningRE := regexp.MustCompile(s.LongRunningRequestRE) longRunningTimeout := func(req *http.Request) (<-chan time.Time, string) { // TODO unify this with apiserver.MaxInFlightLimit if longRunningRE.MatchString(req.URL.Path) || req.URL.Query().Get("watch") == "true" { return nil, "" } return time.After(time.Minute), "" } if secureLocation != "" { handler := apiserver.TimeoutHandler(m.Handler, longRunningTimeout) secureServer := &http.Server{ Addr: secureLocation, Handler: apiserver.MaxInFlightLimit(sem, longRunningRE, apiserver.RecoverPanics(handler)), MaxHeaderBytes: 1 << 20, TLSConfig: &tls.Config{ // Change default from SSLv3 to TLSv1.0 (because of POODLE vulnerability) MinVersion: tls.VersionTLS10, }, } if len(s.ClientCAFile) > 0 { clientCAs, err := util.CertPoolFromFile(s.ClientCAFile) if err != nil { glog.Fatalf("unable to load client CA file: %v", err) } // Populate PeerCertificates in requests, but don't reject connections without certificates // This allows certificates to be validated by authenticators, while still allowing other auth types secureServer.TLSConfig.ClientAuth = tls.RequestClientCert // Specify allowed CAs for client certificates secureServer.TLSConfig.ClientCAs = clientCAs } glog.Infof("Serving securely on %s", secureLocation) if s.TLSCertFile == "" && s.TLSPrivateKeyFile == "" { s.TLSCertFile = path.Join(s.CertDirectory, "apiserver.crt") s.TLSPrivateKeyFile = path.Join(s.CertDirectory, "apiserver.key") // TODO (cjcullen): Is PublicAddress the right address to sign a cert with? alternateIPs := []net.IP{config.ServiceReadWriteIP} alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"} // It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless // alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME") if err := util.GenerateSelfSignedCert(config.PublicAddress.String(), s.TLSCertFile, s.TLSPrivateKeyFile, alternateIPs, alternateDNS); err != nil { glog.Errorf("Unable to generate self signed cert: %v", err) } else { glog.Infof("Using self-signed cert (%s, %s)", s.TLSCertFile, s.TLSPrivateKeyFile) } } go func() { defer util.HandleCrash() for { // err == systemd.SdNotifyNoSocket when not running on a systemd system if err := systemd.SdNotify("READY=1\n"); err != nil && err != systemd.SdNotifyNoSocket { glog.Errorf("Unable to send systemd daemon successful start message: %v\n", err) } if err := secureServer.ListenAndServeTLS(s.TLSCertFile, s.TLSPrivateKeyFile); err != nil { glog.Errorf("Unable to listen for secure (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } handler := apiserver.TimeoutHandler(m.InsecureHandler, longRunningTimeout) http := &http.Server{ Addr: insecureLocation, Handler: apiserver.RecoverPanics(handler), MaxHeaderBytes: 1 << 20, } if secureLocation == "" { // err == systemd.SdNotifyNoSocket when not running on a systemd system if err := systemd.SdNotify("READY=1\n"); err != nil && err != systemd.SdNotifyNoSocket { glog.Errorf("Unable to send systemd daemon successful start message: %v\n", err) } } glog.Infof("Serving insecurely on %s", insecureLocation) glog.Fatal(http.ListenAndServe()) return nil }