// InitializeTLS checks for a configured TLSCertFile and TLSPrivateKeyFile: if unspecified a new self-signed // certificate and key file are generated. Returns a configured server.TLSOptions object. func InitializeTLS(kc *componentconfig.KubeletConfiguration) (*server.TLSOptions, error) { if kc.TLSCertFile == "" && kc.TLSPrivateKeyFile == "" { kc.TLSCertFile = path.Join(kc.CertDirectory, "kubelet.crt") kc.TLSPrivateKeyFile = path.Join(kc.CertDirectory, "kubelet.key") if !certutil.CanReadCertOrKey(kc.TLSCertFile, kc.TLSPrivateKeyFile) { if err := certutil.GenerateSelfSignedCert(nodeutil.GetHostname(kc.HostnameOverride), kc.TLSCertFile, kc.TLSPrivateKeyFile, nil, nil); err != nil { return nil, fmt.Errorf("unable to generate self signed cert: %v", err) } glog.V(4).Infof("Using self-signed cert (%s, %s)", kc.TLSCertFile, kc.TLSPrivateKeyFile) } } tlsOptions := &server.TLSOptions{ Config: &tls.Config{ // Can't use SSLv3 because of POODLE and BEAST // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher // Can't use TLSv1.1 because of RC4 cipher usage MinVersion: tls.VersionTLS12, }, CertFile: kc.TLSCertFile, KeyFile: kc.TLSPrivateKeyFile, } if len(kc.Authentication.X509.ClientCAFile) > 0 { clientCAs, err := cert.NewPool(kc.Authentication.X509.ClientCAFile) if err != nil { return nil, fmt.Errorf("unable to load client CA file %s: %v", kc.Authentication.X509.ClientCAFile, err) } // Specify allowed CAs for client certificates tlsOptions.Config.ClientCAs = clientCAs // Populate PeerCertificates in requests, but don't reject connections without verified certificates tlsOptions.Config.ClientAuth = tls.RequestClientCert } return tlsOptions, nil }
// MaybeGenerateServingCerts generates serving certificates if requested and needed. func (c completedConfig) MaybeGenerateServingCerts() error { // 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 c.SecureServingInfo != nil && c.SecureServingInfo.ServerCert.Generate && !certutil.CanReadCertOrKey(c.SecureServingInfo.ServerCert.CertFile, c.SecureServingInfo.ServerCert.KeyFile) { // TODO (cjcullen): Is ClusterIP the right address to sign a cert with? alternateIPs := []net.IP{c.ServiceReadWriteIP} alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes", "localhost"} if err := certutil.GenerateSelfSignedCert(c.PublicAddress.String(), c.SecureServingInfo.ServerCert.CertFile, c.SecureServingInfo.ServerCert.KeyFile, alternateIPs, alternateDNS); err != nil { return fmt.Errorf("Unable to generate self signed cert: %v", err) } else { glog.Infof("Generated self-signed cert (%s, %s)", c.SecureServingInfo.ServerCert.CertFile, c.SecureServingInfo.ServerCert.KeyFile) } } return nil }
func (s *GenericAPIServer) Run(options *options.ServerRunOptions) { // install APIs which depend on other APIs to be installed if s.enableSwaggerSupport { s.InstallSwaggerAPI() } if s.enableOpenAPISupport { s.InstallOpenAPI() } secureStartedCh := make(chan struct{}) if options.SecurePort != 0 { secureLocation := net.JoinHostPort(options.BindAddress.String(), strconv.Itoa(options.SecurePort)) secureServer := &http.Server{ Addr: secureLocation, Handler: s.Handler, MaxHeaderBytes: 1 << 20, TLSConfig: &tls.Config{ // Can't use SSLv3 because of POODLE and BEAST // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher // Can't use TLSv1.1 because of RC4 cipher usage MinVersion: tls.VersionTLS12, }, } if len(options.ClientCAFile) > 0 { clientCAs, err := certutil.NewPool(options.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 // "h2" NextProtos is necessary for enabling HTTP2 for go's 1.7 HTTP Server secureServer.TLSConfig.NextProtos = []string{"h2"} } glog.Infof("Serving securely on %s", secureLocation) if options.TLSCertFile == "" && options.TLSPrivateKeyFile == "" { options.TLSCertFile = path.Join(options.CertDirectory, "apiserver.crt") options.TLSPrivateKeyFile = path.Join(options.CertDirectory, "apiserver.key") // TODO (cjcullen): Is ClusterIP the right address to sign a cert with? alternateIPs := []net.IP{s.ServiceReadWriteIP} alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes", "localhost"} // 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 !certutil.CanReadCertOrKey(options.TLSCertFile, options.TLSPrivateKeyFile) { if err := certutil.GenerateSelfSignedCert(s.ClusterIP.String(), options.TLSCertFile, options.TLSPrivateKeyFile, alternateIPs, alternateDNS); err != nil { glog.Errorf("Unable to generate self signed cert: %v", err) } else { glog.Infof("Using self-signed cert (%s, %s)", options.TLSCertFile, options.TLSPrivateKeyFile) } } } go func() { defer utilruntime.HandleCrash() notifyStarted := sync.Once{} for { if err := secureServer.ListenAndServeTLS(options.TLSCertFile, options.TLSPrivateKeyFile); err != nil { glog.Errorf("Unable to listen for secure (%v); will try again.", err) } else { notifyStarted.Do(func() { close(secureStartedCh) }) } time.Sleep(15 * time.Second) } }() } else { close(secureStartedCh) } insecureLocation := net.JoinHostPort(options.InsecureBindAddress.String(), strconv.Itoa(options.InsecurePort)) insecureServer := &http.Server{ Addr: insecureLocation, Handler: s.InsecureHandler, MaxHeaderBytes: 1 << 20, } insecureStartedCh := make(chan struct{}) glog.Infof("Serving insecurely on %s", insecureLocation) go func() { defer utilruntime.HandleCrash() notifyStarted := sync.Once{} for { if err := insecureServer.ListenAndServe(); err != nil { glog.Errorf("Unable to listen for insecure (%v); will try again.", err) } else { notifyStarted.Do(func() { close(insecureStartedCh) }) } time.Sleep(15 * time.Second) } }() <-secureStartedCh <-insecureStartedCh s.RunPostStartHooks(PostStartHookContext{}) // 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) } select {} }
func (s *GenericAPIServer) Run() { // install APIs which depend on other APIs to be installed if s.enableSwaggerSupport { s.InstallSwaggerAPI() } if s.enableOpenAPISupport { s.InstallOpenAPI() } if s.SecureServingInfo != nil { secureServer := &http.Server{ Addr: s.SecureServingInfo.BindAddress, Handler: s.Handler, MaxHeaderBytes: 1 << 20, TLSConfig: &tls.Config{ // Can't use SSLv3 because of POODLE and BEAST // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher // Can't use TLSv1.1 because of RC4 cipher usage MinVersion: tls.VersionTLS12, }, } if len(s.SecureServingInfo.ClientCA) > 0 { clientCAs, err := certutil.NewPool(s.SecureServingInfo.ClientCA) 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 // "h2" NextProtos is necessary for enabling HTTP2 for go's 1.7 HTTP Server secureServer.TLSConfig.NextProtos = []string{"h2"} } // 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 s.SecureServingInfo.ServerCert.Generate && !certutil.CanReadCertOrKey(s.SecureServingInfo.ServerCert.CertFile, s.SecureServingInfo.ServerCert.KeyFile) { // TODO (cjcullen): Is ClusterIP the right address to sign a cert with? alternateIPs := []net.IP{s.ServiceReadWriteIP} alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes", "localhost"} if err := certutil.GenerateSelfSignedCert(s.ClusterIP.String(), s.SecureServingInfo.ServerCert.CertFile, s.SecureServingInfo.ServerCert.KeyFile, alternateIPs, alternateDNS); err != nil { glog.Errorf("Unable to generate self signed cert: %v", err) } else { glog.Infof("Using self-signed cert (%s, %s)", s.SecureServingInfo.ServerCert.CertFile, s.SecureServingInfo.ServerCert.KeyFile) } } glog.Infof("Serving securely on %s", s.SecureServingInfo.BindAddress) go func() { defer utilruntime.HandleCrash() for { if err := secureServer.ListenAndServeTLS(s.SecureServingInfo.ServerCert.CertFile, s.SecureServingInfo.ServerCert.KeyFile); err != nil { glog.Errorf("Unable to listen for secure (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } if s.InsecureServingInfo != nil { insecureServer := &http.Server{ Addr: s.InsecureServingInfo.BindAddress, Handler: s.InsecureHandler, MaxHeaderBytes: 1 << 20, } glog.Infof("Serving insecurely on %s", s.InsecureServingInfo.BindAddress) go func() { defer utilruntime.HandleCrash() for { if err := insecureServer.ListenAndServe(); err != nil { glog.Errorf("Unable to listen for insecure (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } // Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try) per port if s.SecureServingInfo != nil { if err := waitForSuccessfulDial(true, "tcp", s.SecureServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100); err != nil { glog.Fatalf("Secure server never started: %v", err) } } if s.InsecureServingInfo != nil { if err := waitForSuccessfulDial(false, "tcp", s.InsecureServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100); err != nil { glog.Fatalf("Insecure server never started: %v", err) } } s.RunPostStartHooks() // 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) } select {} }