From 6ea1d5d53d89ad04b642da582cc1ad72a51e577c Mon Sep 17 00:00:00 2001 From: deads2k Date: Mon, 5 Dec 2016 15:30:13 -0500 Subject: [PATCH] join client CA bundles into the accept path for genericapiserver --- cmd/kube-apiserver/app/server.go | 4 +- examples/apiserver/apiserver.go | 4 +- .../cmd/federation-apiserver/app/server.go | 4 +- hack/local-up-cluster.sh | 4 +- pkg/genericapiserver/config.go | 37 ++++++++++++++++--- pkg/genericapiserver/serve.go | 9 +---- pkg/util/cert/io.go | 6 +-- 7 files changed, 46 insertions(+), 22 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 69588b0d15..b65280fced 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -103,7 +103,9 @@ func Run(s *options.ServerRunOptions) error { if _, err := genericConfig.ApplySecureServingOptions(s.SecureServing); err != nil { return fmt.Errorf("failed to configure https: %s", err) } - genericConfig.ApplyAuthenticationOptions(s.Authentication) + if _, err = genericConfig.ApplyAuthenticationOptions(s.Authentication); err != nil { + return fmt.Errorf("failed to configure authentication: %s", err) + } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: s.AllowPrivileged, diff --git a/examples/apiserver/apiserver.go b/examples/apiserver/apiserver.go index 6b0460020c..5442a6f1d1 100644 --- a/examples/apiserver/apiserver.go +++ b/examples/apiserver/apiserver.go @@ -106,7 +106,9 @@ func (serverOptions *ServerRunOptions) Run(stopCh <-chan struct{}) error { if _, err := config.ApplySecureServingOptions(serverOptions.SecureServing); err != nil { return fmt.Errorf("failed to configure https: %s", err) } - config.ApplyAuthenticationOptions(serverOptions.Authentication) + if _, err := config.ApplyAuthenticationOptions(serverOptions.Authentication); err != nil { + return fmt.Errorf("failed to configure authentication: %s", err) + } config.Authorizer = authorizer.NewAlwaysAllowAuthorizer() s, err := config.Complete().New() diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index bf44483390..435d8201e3 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -85,7 +85,9 @@ func Run(s *options.ServerRunOptions) error { if _, err := genericConfig.ApplySecureServingOptions(s.SecureServing); err != nil { return fmt.Errorf("failed to configure https: %s", err) } - genericConfig.ApplyAuthenticationOptions(s.Authentication) + if _, err := genericConfig.ApplyAuthenticationOptions(s.Authentication); err != nil { + return fmt.Errorf("failed to configure authentication: %s", err) + } // TODO: register cluster federation resources here. resourceConfig := genericapiserver.NewResourceConfig() diff --git a/hack/local-up-cluster.sh b/hack/local-up-cluster.sh index ccfd1a3901..20d9ca28d2 100755 --- a/hack/local-up-cluster.sh +++ b/hack/local-up-cluster.sh @@ -455,14 +455,12 @@ EOF EOF create_client_certkey auth-proxy-client-ca auth-proxy system:auth-proxy - sudo bash -c "cat '${CERT_DIR}/client-ca.crt' '${CERT_DIR}/auth-proxy-client-ca.crt' > '${CERT_DIR}/client-ca-bundle.crt'" - APISERVER_LOG=/tmp/kube-apiserver.log ${CONTROLPLANE_SUDO} "${GO_OUT}/hyperkube" apiserver ${anytoken_arg} ${auth_proxy_arg} ${authorizer_arg} ${priv_arg} ${runtime_config}\ ${advertise_address} \ --v=${LOG_LEVEL} \ --cert-dir="${CERT_DIR}" \ - --client-ca-file="${CERT_DIR}/client-ca-bundle.crt" \ + --client-ca-file="${CERT_DIR}/client-ca.crt" \ --service-account-key-file="${SERVICE_ACCOUNT_KEY}" \ --service-account-lookup="${SERVICE_ACCOUNT_LOOKUP}" \ --admission-control="${ADMISSION_CONTROL}" \ diff --git a/pkg/genericapiserver/config.go b/pkg/genericapiserver/config.go index 58d5140ba6..84f7f067bf 100644 --- a/pkg/genericapiserver/config.go +++ b/pkg/genericapiserver/config.go @@ -18,6 +18,7 @@ package genericapiserver import ( "crypto/tls" + "crypto/x509" "encoding/pem" "fmt" "io" @@ -60,6 +61,7 @@ import ( "k8s.io/kubernetes/pkg/genericapiserver/routes" genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation" "k8s.io/kubernetes/pkg/runtime" + certutil "k8s.io/kubernetes/pkg/util/cert" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/version" authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union" @@ -180,7 +182,7 @@ type SecureServingInfo struct { SNICerts map[string]*tls.Certificate // ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates - ClientCA string + ClientCA *x509.CertPool } // NewConfig returns a Config struct with the default values @@ -299,17 +301,40 @@ func (c *Config) ApplyInsecureServingOptions(insecureServing *options.ServingOpt return c } -func (c *Config) ApplyAuthenticationOptions(o *options.BuiltInAuthenticationOptions) *Config { +func (c *Config) ApplyAuthenticationOptions(o *options.BuiltInAuthenticationOptions) (*Config, error) { if o == nil || o.PasswordFile == nil { - return c + return c, nil } - if o.ClientCert != nil && c.SecureServingInfo != nil { - c.SecureServingInfo.ClientCA = o.ClientCert.ClientCA + if c.SecureServingInfo != nil { + if o.ClientCert != nil && len(o.ClientCert.ClientCA) > 0 { + clientCAs, err := certutil.CertsFromFile(o.ClientCert.ClientCA) + if err != nil { + return nil, fmt.Errorf("unable to load client CA file: %v", err) + } + if c.SecureServingInfo.ClientCA == nil { + c.SecureServingInfo.ClientCA = x509.NewCertPool() + } + for _, cert := range clientCAs { + c.SecureServingInfo.ClientCA.AddCert(cert) + } + } + if o.RequestHeader != nil && len(o.RequestHeader.ClientCAFile) > 0 { + clientCAs, err := certutil.CertsFromFile(o.RequestHeader.ClientCAFile) + if err != nil { + return nil, fmt.Errorf("unable to load requestheader client CA file: %v", err) + } + if c.SecureServingInfo.ClientCA == nil { + c.SecureServingInfo.ClientCA = x509.NewCertPool() + } + for _, cert := range clientCAs { + c.SecureServingInfo.ClientCA.AddCert(cert) + } + } } c.SupportsBasicAuth = len(o.PasswordFile.BasicAuthFile) > 0 - return c + return c, nil } // ApplyOptions applies the run options to the method receiver and returns self diff --git a/pkg/genericapiserver/serve.go b/pkg/genericapiserver/serve.go index 1a17eca3ea..c9b35fcf75 100644 --- a/pkg/genericapiserver/serve.go +++ b/pkg/genericapiserver/serve.go @@ -26,7 +26,6 @@ import ( "sync" "time" - certutil "k8s.io/kubernetes/pkg/util/cert" utilruntime "k8s.io/kubernetes/pkg/util/runtime" "k8s.io/kubernetes/pkg/util/validation" @@ -69,16 +68,12 @@ func (s *GenericAPIServer) serveSecurely(stopCh <-chan struct{}) error { 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) - } + if s.SecureServingInfo.ClientCA != nil { // 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 + secureServer.TLSConfig.ClientCAs = s.SecureServingInfo.ClientCA } glog.Infof("Serving securely on %s", s.SecureServingInfo.BindAddress) diff --git a/pkg/util/cert/io.go b/pkg/util/cert/io.go index 377b3d5892..2b6201fc30 100644 --- a/pkg/util/cert/io.go +++ b/pkg/util/cert/io.go @@ -90,7 +90,7 @@ func WriteKey(keyPath string, data []byte) error { // NewPool returns an x509.CertPool containing the certificates in the given PEM-encoded file. // Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates func NewPool(filename string) (*x509.CertPool, error) { - certs, err := certsFromFile(filename) + certs, err := CertsFromFile(filename) if err != nil { return nil, err } @@ -101,9 +101,9 @@ func NewPool(filename string) (*x509.CertPool, error) { return pool, nil } -// certsFromFile returns the x509.Certificates contained in the given PEM-encoded file. +// CertsFromFile returns the x509.Certificates contained in the given PEM-encoded file. // Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates -func certsFromFile(file string) ([]*x509.Certificate, error) { +func CertsFromFile(file string) ([]*x509.Certificate, error) { if len(file) == 0 { return nil, errors.New("error reading certificates from an empty filename") }