From dd6c98094919a4d8ce8709639f08270f50170c6b Mon Sep 17 00:00:00 2001 From: Di Xu Date: Tue, 25 Oct 2016 11:26:44 +0800 Subject: [PATCH] specify custom ca file to verify the keystone server --- cmd/kube-apiserver/app/server.go | 1 + hack/verify-flags/known-flags.txt | 1 + pkg/apiserver/authenticator/authn.go | 7 ++-- .../options/server_run_options.go | 5 +++ .../authenticator/password/keystone/BUILD | 2 + .../password/keystone/keystone.go | 41 ++++++++++++++++--- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 917b0acdabb..9c7e32bf362 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -230,6 +230,7 @@ func Run(s *options.ServerRunOptions) error { ServiceAccountLookup: s.ServiceAccountLookup, ServiceAccountTokenGetter: serviceAccountGetter, KeystoneURL: s.GenericServerRunOptions.KeystoneURL, + KeystoneCAFile: s.GenericServerRunOptions.KeystoneCAFile, WebhookTokenAuthnConfigFile: s.WebhookTokenAuthnConfigFile, WebhookTokenAuthnCacheTTL: s.WebhookTokenAuthnCacheTTL, RequestHeaderConfig: s.GenericServerRunOptions.AuthenticationRequestHeaderConfig(), diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index 3d89e2354d5..b58eafbbe86 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -189,6 +189,7 @@ exit-on-lock-contention experimental-allowed-unsafe-sysctls experimental-bootstrap-kubeconfig experimental-keystone-url +experimental-keystone-ca-file experimental-mounter-path experimental-mounter-rootfs-path experimental-nvidia-gpus diff --git a/pkg/apiserver/authenticator/authn.go b/pkg/apiserver/authenticator/authn.go index 6d5720077e3..acc8e6f2db1 100644 --- a/pkg/apiserver/authenticator/authn.go +++ b/pkg/apiserver/authenticator/authn.go @@ -64,6 +64,7 @@ type AuthenticatorConfig struct { ServiceAccountLookup bool ServiceAccountTokenGetter serviceaccount.ServiceAccountTokenGetter KeystoneURL string + KeystoneCAFile string WebhookTokenAuthnConfigFile string WebhookTokenAuthnCacheTTL time.Duration @@ -101,7 +102,7 @@ func New(config AuthenticatorConfig) (authenticator.Request, *spec.SecurityDefin hasBasicAuth = true } if len(config.KeystoneURL) > 0 { - keystoneAuth, err := newAuthenticatorFromKeystoneURL(config.KeystoneURL) + keystoneAuth, err := newAuthenticatorFromKeystoneURL(config.KeystoneURL, config.KeystoneCAFile) if err != nil { return nil, nil, err } @@ -283,8 +284,8 @@ func newAuthenticatorFromClientCAFile(clientCAFile string) (authenticator.Reques } // newAuthenticatorFromTokenFile returns an authenticator.Request or an error -func newAuthenticatorFromKeystoneURL(keystoneURL string) (authenticator.Request, error) { - keystoneAuthenticator, err := keystone.NewKeystoneAuthenticator(keystoneURL) +func newAuthenticatorFromKeystoneURL(keystoneURL string, keystoneCAFile string) (authenticator.Request, error) { + keystoneAuthenticator, err := keystone.NewKeystoneAuthenticator(keystoneURL, keystoneCAFile) if err != nil { return nil, err } diff --git a/pkg/genericapiserver/options/server_run_options.go b/pkg/genericapiserver/options/server_run_options.go index f80a36a0e07..2047d914208 100644 --- a/pkg/genericapiserver/options/server_run_options.go +++ b/pkg/genericapiserver/options/server_run_options.go @@ -91,6 +91,7 @@ type ServerRunOptions struct { InsecureBindAddress net.IP InsecurePort int KeystoneURL string + KeystoneCAFile string KubernetesServiceNodePort int LongRunningRequestRE string MasterCount int @@ -379,6 +380,10 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) { fs.StringVar(&s.KeystoneURL, "experimental-keystone-url", s.KeystoneURL, "If passed, activates the keystone authentication plugin.") + fs.StringVar(&s.KeystoneCAFile, "experimental-keystone-ca-file", s.KeystoneCAFile, ""+ + "If set, the Keystone server's certificate will be verified by one of the authorities "+ + "in the experimental-keystone-ca-file, otherwise the host's root CA set will be used.") + // See #14282 for details on how to test/try this option out. // TODO: remove this comment once this option is tested in CI. fs.IntVar(&s.KubernetesServiceNodePort, "kubernetes-service-node-port", s.KubernetesServiceNodePort, ""+ diff --git a/plugin/pkg/auth/authenticator/password/keystone/BUILD b/plugin/pkg/auth/authenticator/password/keystone/BUILD index b08f989971e..2e836ee31da 100644 --- a/plugin/pkg/auth/authenticator/password/keystone/BUILD +++ b/plugin/pkg/auth/authenticator/password/keystone/BUILD @@ -19,6 +19,8 @@ go_library( tags = ["automanaged"], deps = [ "//pkg/auth/user:go_default_library", + "//pkg/util/cert:go_default_library", + "//pkg/util/net:go_default_library", "//vendor:github.com/golang/glog", "//vendor:github.com/rackspace/gophercloud", "//vendor:github.com/rackspace/gophercloud/openstack", diff --git a/plugin/pkg/auth/authenticator/password/keystone/keystone.go b/plugin/pkg/auth/authenticator/password/keystone/keystone.go index 2ba449edeb0..1f261820b5c 100644 --- a/plugin/pkg/auth/authenticator/password/keystone/keystone.go +++ b/plugin/pkg/auth/authenticator/password/keystone/keystone.go @@ -17,19 +17,24 @@ limitations under the License. package keystone import ( + "crypto/tls" "errors" + "net/http" "strings" "github.com/golang/glog" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack" "k8s.io/kubernetes/pkg/auth/user" + certutil "k8s.io/kubernetes/pkg/util/cert" + netutil "k8s.io/kubernetes/pkg/util/net" ) // KeystoneAuthenticator contacts openstack keystone to validate user's credentials passed in the request. // The keystone endpoint is passed during apiserver startup type KeystoneAuthenticator struct { - authURL string + authURL string + transport http.RoundTripper } // AuthenticatePassword checks the username, password via keystone call @@ -40,23 +45,49 @@ func (keystoneAuthenticator *KeystoneAuthenticator) AuthenticatePassword(usernam Password: password, } - _, err := openstack.AuthenticatedClient(opts) + _, err := keystoneAuthenticator.AuthenticatedClient(opts) if err != nil { - glog.Info("Failed: Starting openstack authenticate client") + glog.Info("Failed: Starting openstack authenticate client:" + err.Error()) return nil, false, errors.New("Failed to authenticate") } return &user.DefaultInfo{Name: username}, true, nil } +// AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint specified by options, acquires a +// token, and returns a Client instance that's ready to operate. +func (keystoneAuthenticator *KeystoneAuthenticator) AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) { + client, err := openstack.NewClient(options.IdentityEndpoint) + if err != nil { + return nil, err + } + + if keystoneAuthenticator.transport != nil { + client.HTTPClient.Transport = keystoneAuthenticator.transport + } + + err = openstack.Authenticate(client, options) + return client, err +} + // NewKeystoneAuthenticator returns a password authenticator that validates credentials using openstack keystone -func NewKeystoneAuthenticator(authURL string) (*KeystoneAuthenticator, error) { +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}, nil + return &KeystoneAuthenticator{authURL: authURL}, nil }