Example #1
0
// InClusterConfig returns a config object which uses the service account
// kubernetes gives to pods. It's intended for clients that expect to be
// running inside a pod running on kubernetes. It will return an error if
// called from a process not running in a kubernetes environment.
func InClusterConfig() (*Config, error) {
	host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
	if len(host) == 0 || len(port) == 0 {
		return nil, fmt.Errorf("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined")
	}

	token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountTokenKey)
	if err != nil {
		return nil, err
	}
	tlsClientConfig := TLSClientConfig{}
	rootCAFile := "/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountRootCAKey
	if _, err := certutil.NewPool(rootCAFile); err != nil {
		glog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)
	} else {
		tlsClientConfig.CAFile = rootCAFile
	}

	return &Config{
		// TODO: switch to using cluster DNS.
		Host:            "https://" + net.JoinHostPort(host, port),
		BearerToken:     string(token),
		TLSClientConfig: tlsClientConfig,
	}, nil
}
Example #2
0
// 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
}
Example #3
0
func (o CreateNodeConfigOptions) Validate(args []string) error {
	if len(args) != 0 {
		return errors.New("no arguments are supported")
	}
	if len(o.NodeConfigDir) == 0 {
		return errors.New("--node-dir must be provided")
	}
	if len(o.NodeName) == 0 {
		return errors.New("--node must be provided")
	}
	if len(o.APIServerURL) == 0 {
		return errors.New("--master must be provided")
	}
	if len(o.APIServerCAFiles) == 0 {
		return fmt.Errorf("--certificate-authority must be a valid certificate file")
	} else {
		for _, caFile := range o.APIServerCAFiles {
			if _, err := cert.NewPool(caFile); err != nil {
				return fmt.Errorf("--certificate-authority must be a valid certificate file: %v", err)
			}
		}
	}
	if len(o.Hostnames) == 0 {
		return errors.New("at least one hostname must be provided")
	}

	if len(o.ClientCertFile) != 0 {
		if len(o.ClientKeyFile) == 0 {
			return errors.New("--client-key must be provided if --client-certificate is provided")
		}
	} else if len(o.ClientKeyFile) != 0 {
		return errors.New("--client-certificate must be provided if --client-key is provided")
	}

	if len(o.ServerCertFile) != 0 {
		if len(o.ServerKeyFile) == 0 {
			return errors.New("--server-key must be provided if --server-certificate is provided")
		}
	} else if len(o.ServerKeyFile) != 0 {
		return errors.New("--server-certificate must be provided if --server-key is provided")
	}

	if o.IsCreateClientCertificate() || o.IsCreateServerCertificate() {
		if len(o.SignerCertOptions.KeyFile) == 0 {
			return errors.New("--signer-key must be provided to create certificates")
		}
		if len(o.SignerCertOptions.CertFile) == 0 {
			return errors.New("--signer-cert must be provided to create certificates")
		}
		if len(o.SignerCertOptions.SerialFile) == 0 {
			return errors.New("--signer-serial must be provided to create certificates")
		}
	}

	if o.ExpireDays < 0 {
		return errors.New("expire-days must be valid number of days")
	}

	return nil
}
Example #4
0
func (o CreateKubeConfigOptions) Validate(args []string) error {
	if len(args) != 0 {
		return errors.New("no arguments are supported")
	}
	if len(o.KubeConfigFile) == 0 {
		return errors.New("kubeconfig must be provided")
	}
	if len(o.CertFile) == 0 {
		return errors.New("client-certificate must be provided")
	}
	if len(o.KeyFile) == 0 {
		return errors.New("client-key must be provided")
	}
	if len(o.APIServerCAFiles) == 0 {
		return errors.New("certificate-authority must be provided")
	} else {
		for _, caFile := range o.APIServerCAFiles {
			if _, err := cert.NewPool(caFile); err != nil {
				return fmt.Errorf("certificate-authority must be a valid certificate file: %v", err)
			}
		}
	}
	if len(o.ContextNamespace) == 0 {
		return errors.New("namespace must be provided")
	}
	if len(o.APIServerURL) == 0 {
		return errors.New("master must be provided")
	}

	return nil
}
Example #5
0
// newAuthenticatorFromClientCAFile returns an authenticator.Request or an error
func newAuthenticatorFromClientCAFile(clientCAFile string) (authenticator.Request, error) {
	roots, err := certutil.NewPool(clientCAFile)
	if err != nil {
		return nil, err
	}

	opts := x509.DefaultVerifyOptions()
	opts.Roots = roots

	return x509.New(opts, x509.CommonNameUserConversion), nil
}
Example #6
0
// serveSecurely runs the secure http server. It fails only if certificates cannot
// be loaded or the initial listen call fails. The actual server loop (stoppable by closing
// stopCh) runs in a go routine, i.e. serveSecurely does not block.
func (s *GenericAPIServer) serveSecurely(stopCh <-chan struct{}) error {
	namedCerts, err := getNamedCertificateMap(s.SecureServingInfo.SNICerts)
	if err != nil {
		return fmt.Errorf("unable to load SNI certificates: %v", err)
	}

	secureServer := &http.Server{
		Addr:           s.SecureServingInfo.BindAddress,
		Handler:        s.Handler,
		MaxHeaderBytes: 1 << 20,
		TLSConfig: &tls.Config{
			NameToCertificate: namedCerts,
			// 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,
			// enable HTTP2 for go's 1.7 HTTP Server
			NextProtos: []string{"h2", "http/1.1"},
		},
	}

	if len(s.SecureServingInfo.ServerCert.CertFile) != 0 || len(s.SecureServingInfo.ServerCert.KeyFile) != 0 {
		secureServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
		secureServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(s.SecureServingInfo.ServerCert.CertFile, s.SecureServingInfo.ServerCert.KeyFile)
		if err != nil {
			return fmt.Errorf("unable to load server certificate: %v", err)
		}
	}

	// append all named certs. Otherwise, the go tls stack will think no SNI processing
	// is necessary because there is only one cert anyway.
	// Moreover, if ServerCert.CertFile/ServerCert.KeyFile are not set, the first SNI
	// cert will become the default cert. That's what we expect anyway.
	for _, c := range namedCerts {
		secureServer.TLSConfig.Certificates = append(secureServer.TLSConfig.Certificates, *c)
	}

	if len(s.SecureServingInfo.ClientCA) > 0 {
		clientCAs, err := certutil.NewPool(s.SecureServingInfo.ClientCA)
		if err != nil {
			return fmt.Errorf("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", s.SecureServingInfo.BindAddress)
	s.effectiveSecurePort, err = runServer(secureServer, stopCh)
	return err
}
Example #7
0
// New creates a token authenticator which validates OpenID Connect ID Tokens.
func New(opts OIDCOptions) (*OIDCAuthenticator, error) {
	url, err := url.Parse(opts.IssuerURL)
	if err != nil {
		return nil, err
	}

	if url.Scheme != "https" {
		return nil, fmt.Errorf("'oidc-issuer-url' (%q) has invalid scheme (%q), require 'https'", opts.IssuerURL, url.Scheme)
	}

	if opts.UsernameClaim == "" {
		return nil, errors.New("no username claim provided")
	}

	var roots *x509.CertPool
	if opts.CAFile != "" {
		roots, err = certutil.NewPool(opts.CAFile)
		if err != nil {
			return nil, fmt.Errorf("Failed to read the CA file: %v", err)
		}
	} else {
		glog.Info("OIDC: No x509 certificates provided, will use host's root CA set")
	}

	// Copied from http.DefaultTransport.
	tr := net.SetTransportDefaults(&http.Transport{
		// According to golang's doc, if RootCAs is nil,
		// TLS uses the host's root CA set.
		TLSClientConfig: &tls.Config{RootCAs: roots},
	})

	authenticator := &OIDCAuthenticator{
		issuerURL:       opts.IssuerURL,
		trustedClientID: opts.ClientID,
		usernameClaim:   opts.UsernameClaim,
		groupsClaim:     opts.GroupsClaim,
		httpClient:      &http.Client{Transport: tr},
	}

	// Attempt to initialize the authenticator asynchronously.
	//
	// Ignore errors instead of returning it since the OpenID Connect provider might not be
	// available yet, for instance if it's running on the cluster and needs the API server
	// to come up first. Errors will be logged within the client() method.
	go func() {
		defer runtime.HandleCrash()
		authenticator.client()
	}()

	return authenticator, nil
}
Example #8
0
func (o CreateMasterCertsOptions) Validate(args []string) error {
	if len(args) != 0 {
		return errors.New("no arguments are supported")
	}
	if len(o.Hostnames) == 0 {
		return errors.New("at least one hostname must be provided")
	}
	if len(o.CertDir) == 0 {
		return errors.New("cert-dir must be provided")
	}
	if len(o.SignerName) == 0 {
		return errors.New("signer-name must be provided")
	}
	if o.ExpireDays <= 0 {
		return errors.New("expire-days must be valid number of days")
	}
	if o.SignerExpireDays <= 0 {
		return errors.New("signer-expire-days must be valid number of days")
	}
	if len(o.APIServerURL) == 0 {
		return errors.New("master must be provided")
	} else if u, err := url.Parse(o.APIServerURL); err != nil {
		return errors.New("master must be a valid URL (e.g. https://10.0.0.1:8443)")
	} else if len(u.Scheme) == 0 {
		return errors.New("master must be a valid URL (e.g. https://10.0.0.1:8443)")
	}

	if len(o.PublicAPIServerURL) == 0 {
		// not required
	} else if u, err := url.Parse(o.PublicAPIServerURL); err != nil {
		return errors.New("public master must be a valid URL (e.g. https://example.com:8443)")
	} else if len(u.Scheme) == 0 {
		return errors.New("public master must be a valid URL (e.g. https://example.com:8443)")
	}

	for _, caFile := range o.APIServerCAFiles {
		if _, err := cert.NewPool(caFile); err != nil {
			return fmt.Errorf("certificate authority must be a valid certificate file: %v", err)
		}
	}

	return nil
}
// NewKeystoneAuthenticator returns a password authenticator that validates credentials using openstack keystone
func NewKeystoneAuthenticator(authURL string, caFile string) (*KeystoneAuthenticator, error) {
	if !strings.HasPrefix(authURL, "https") {
		return nil, errors.New("Auth URL should be secure and start with https")
	}
	if authURL == "" {
		return nil, errors.New("Auth URL is empty")
	}
	if caFile != "" {
		roots, err := certutil.NewPool(caFile)
		if err != nil {
			return nil, err
		}
		config := &tls.Config{}
		config.RootCAs = roots
		transport := netutil.SetOldTransportDefaults(&http.Transport{TLSClientConfig: config})
		return &KeystoneAuthenticator{authURL, transport}, nil
	}

	return &KeystoneAuthenticator{authURL: authURL}, nil
}
Example #10
0
func buildAuthn(client authenticationclient.TokenReviewInterface, authn componentconfig.KubeletAuthentication) (authenticator.Request, error) {
	authenticators := []authenticator.Request{}

	// x509 client cert auth
	if len(authn.X509.ClientCAFile) > 0 {
		clientCAs, err := cert.NewPool(authn.X509.ClientCAFile)
		if err != nil {
			return nil, fmt.Errorf("unable to load client CA file %s: %v", authn.X509.ClientCAFile, err)
		}
		verifyOpts := x509.DefaultVerifyOptions()
		verifyOpts.Roots = clientCAs
		authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion))
	}

	// bearer token auth that uses authentication.k8s.io TokenReview to determine userinfo
	if authn.Webhook.Enabled {
		if client == nil {
			return nil, errors.New("no client provided, cannot use webhook authentication")
		}
		tokenAuth, err := webhooktoken.NewFromInterface(client, authn.Webhook.CacheTTL.Duration)
		if err != nil {
			return nil, err
		}
		authenticators = append(authenticators, bearertoken.New(tokenAuth))
	}

	if len(authenticators) == 0 {
		if authn.Anonymous.Enabled {
			return anonymous.NewAuthenticator(), nil
		}
		return nil, errors.New("No authentication method configured")
	}

	authenticator := group.NewGroupAdder(unionauth.New(authenticators...), []string{"system:authenticated"})
	if authn.Anonymous.Enabled {
		authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
	}
	return authenticator, nil
}
Example #11
0
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 {}
}
Example #12
0
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 {}
}
Example #13
0
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 && s.Handler != 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"}

		}

		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 && s.InsecureHandler != 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 {}
}
Example #14
0
func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDefinitions, error) {
	authenticators := []authenticator.Request{}
	securityDefinitions := spec.SecurityDefinitions{}

	// front-proxy first, then remote
	// Add the front proxy authenticator if requested
	if c.RequestHeaderConfig != nil {
		requestHeaderAuthenticator, err := headerrequest.NewSecure(
			c.RequestHeaderConfig.ClientCA,
			c.RequestHeaderConfig.AllowedClientNames,
			c.RequestHeaderConfig.UsernameHeaders,
			c.RequestHeaderConfig.GroupHeaders,
			c.RequestHeaderConfig.ExtraHeaderPrefixes,
		)
		if err != nil {
			return nil, nil, err
		}
		authenticators = append(authenticators, requestHeaderAuthenticator)
	}

	// x509 client cert auth
	if len(c.ClientCAFile) > 0 {
		clientCAs, err := cert.NewPool(c.ClientCAFile)
		if err != nil {
			return nil, nil, fmt.Errorf("unable to load client CA file %s: %v", c.ClientCAFile, err)
		}
		verifyOpts := x509.DefaultVerifyOptions()
		verifyOpts.Roots = clientCAs
		authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion))
	}

	if c.TokenAccessReviewClient != nil {
		tokenAuth, err := webhooktoken.NewFromInterface(c.TokenAccessReviewClient, c.CacheTTL)
		if err != nil {
			return nil, nil, err
		}
		authenticators = append(authenticators, bearertoken.New(tokenAuth))

		securityDefinitions["BearerToken"] = &spec.SecurityScheme{
			SecuritySchemeProps: spec.SecuritySchemeProps{
				Type:        "apiKey",
				Name:        "authorization",
				In:          "header",
				Description: "Bearer Token authentication",
			},
		}
	}

	if len(authenticators) == 0 {
		if c.Anonymous {
			return anonymous.NewAuthenticator(), &securityDefinitions, nil
		}
		return nil, nil, errors.New("No authentication method configured")
	}

	authenticator := group.NewGroupAdder(unionauth.New(authenticators...), []string{user.AllAuthenticated})
	if c.Anonymous {
		authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
	}
	return authenticator, &securityDefinitions, nil
}