Change:
Hi, I tried to integrate the keystone auth plugin (which would be perfect for my needs) into the cluster I'm currently setting up. However, I can't get the connection working since our keystone installation is currently only reachable over http As far as I can see in , there is no option to deactivate this check. I think this should be an optional parameter on startup, similar to defaulting to the check being activated.
I don't think we should enable username/password checking over http.
I agree that we are loosing a security layer here, but you can't guarantee you got the password from client over https, so it might be intercepted at this point anyways. More general, I think the proper way to authenticate to Kubernetes with the Keystone plugin using tokens since they will limited lifetime restricted on keystone only which is a big deal regarding keystone likely being bound to a LDAP and thus the password being valid for other services. So I don't want to check username/password directly. I'm just starting out with the Keystone plugin, so I want to point this out in general, if token auth is supported, the better. Couldn't try it in praxis for now since I can't get the auth URL running.
Assigning to to add a priority label.
Setting the priority low until we have a sense of how many users have this restriction (keystone only reachable over http).
I ran into this same issue with trying to deploy kubernetes with devstack in the same vm and wanted to test integration and do some development. I think there are a significant number of developers in this same boat. http is secure enough since it doesn't leave the developers vm and it isn't intended for production. The use case is the same as:
I'd vastly prefer allowing specifying the CA for the keystone server over allowing http auth calls carrying usernames and passwords
I don't disagree. :) But, I also think Kubernetes shouldn't handle the usernames/passwords at all. In http mode, sending a token is much less risky then a username/password since they expire relatively quickly. See this issue for details:
I agree tokens would be preferable, but I wouldn't expect credentials of any kind sent over http to remote servers
Agreed. No one in their right mind should be passing creds or bearer tokens over http over a network. I'm just interested in being able to easily deploy a k8s in DevStack with a simple plugin, where that k8s is hooked into the deployed keystone so that we can start developing things in OpenStack that depend on k8s. This gives developers a smooth/easy experience to then focus on doing the development stuff and not have to mess with setting up a CA/k8s, which will prevent some of them from contributing to k8s/OpenStack. The idea is simple for developers, secure for operators. Totally separate use cases.
It should be as simple as telling k8s to trust the keystone cert as a CA (assuming the self-signed cert generated by keystone is correctly marked as a CA, which it should be, since it is signing for itself). I've seen too many production installations running with http or untrusted TLS settings to believe that only developers will use this option if it's made available.
I didn't think Devstack could easily deploy with SSL enabled, but it looks like you can: So http support might not be as important as I thought. It could be relegated to a documentation issue for deploying Devstack in this mode when deploying with Kubernetes. We'd still need a way to specify the root CA though for Keystone.
So, I played around with this a little. For my current non devstack based system, I've deployed kubernetes as a cluster running on my laptop deployed as a set of pods via /etc/kubernetes/manifests. Only kubelet is native and all the rest of the services are containers direct from google. Its working well, but since I have 3 api server containers, and get the containers direct from google, I'd have to jump through a bunch of hoops to add the keystone ssl ca cert to each of the containers. I still think an option to specify the ssl cert for keystone would be useful rather then having to merge it into the system's chain of trust.
That's how I'd want to handle this as well

Discussion:
ServiceAccountLookup:        s.ServiceAccountLookup, ServiceAccountTokenGetter:   serviceAccountGetter, KeystoneURL:                 s.GenericServerRunOptions.KeystoneURL, <ins> KeystoneCAFile:              s.GenericServerRunOptions.KeystoneCAFile, </ins> WebhookTokenAuthnConfigFile: s.WebhookTokenAuthnConfigFile, WebhookTokenAuthnCacheTTL:   s.WebhookTokenAuthnCacheTTL, RequestHeaderConfig:         s.GenericServerRunOptions.AuthenticationRequestHeaderConfig(),

experimental-allowed-unsafe-sysctls experimental-bootstrap-kubeconfig experimental-keystone-url <ins> experimental-keystone-ca-file </ins> experimental-mounter-path experimental-mounter-rootfs-path experimental-nvidia-gpus

ServiceAccountLookup        bool ServiceAccountTokenGetter   serviceaccount.ServiceAccountTokenGetter KeystoneURL                 string <ins> KeystoneCAFile              string </ins> WebhookTokenAuthnConfigFile string WebhookTokenAuthnCacheTTL   time.Duration

hasBasicAuth = true } if len(config.KeystoneURL) > 0 { <del> keystoneAuth, err := newAuthenticatorFromKeystoneURL(config.KeystoneURL) </del> <ins> keystoneAuth, err := newAuthenticatorFromKeystoneURL(config.KeystoneURL, config.KeystoneCAFile) </ins> if err != nil { return nil, nil, err }

} // newAuthenticatorFromTokenFile returns an authenticator.Request or an error <del> func newAuthenticatorFromKeystoneURL(keystoneURL string) (authenticator.Request, error) { keystoneAuthenticator, err := keystone.NewKeystoneAuthenticator(keystoneURL) </del> <ins> func newAuthenticatorFromKeystoneURL(keystoneURL string, keystoneCAFile string) (authenticator.Request, error) { keystoneAuthenticator, err := keystone.NewKeystoneAuthenticator(keystoneURL, keystoneCAFile) </ins> if err != nil { return nil, err }

InsecureBindAddress          net.IP InsecurePort                 int KeystoneURL                  string <ins> KeystoneCAFile               string </ins> KubernetesServiceNodePort    int LongRunningRequestRE         string MasterCount                  int

fs.StringVar(&s.KeystoneURL, "experimental-keystone-url", s.KeystoneURL, "If passed, activates the keystone authentication plugin.") <ins> 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.") </ins> // 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, ""+

tags = ["automanaged"], deps = [ "//pkg/auth/user:go_default_library", <ins> "//pkg/util/cert:go_default_library", "//pkg/util/net:go_default_library", </ins> "//vendor:github.com/golang/glog", "//vendor:github.com/rackspace/gophercloud", "//vendor:github.com/rackspace/gophercloud/openstack",

package keystone import ( <ins> "crypto/tls" </ins> "errors" <ins> "net/http" </ins> "strings" "github.com/golang/glog" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack" "k8s.io/kubernetes/pkg/auth/user" <ins> certutil "k8s.io/kubernetes/pkg/util/cert" netutil "k8s.io/kubernetes/pkg/util/net" </ins> ) // KeystoneAuthenticator contacts openstack keystone to validate user's credentials passed in the request. // The keystone endpoint is passed during apiserver startup type KeystoneAuthenticator struct { <del> authURL string </del> <ins> authURL   string transport http.RoundTripper </ins> } // AuthenticatePassword checks the username, password via keystone call

Password:         password, } <del> _, err := openstack.AuthenticatedClient(opts) </del> <ins> _, err := keystoneAuthenticator.AuthenticatedClient(opts) </ins> if err != nil { <del> glog.Info("Failed: Starting openstack authenticate client") </del> <ins> glog.Info("Failed: Starting openstack authenticate client:" + err.Error()) </ins> return nil, false, errors.New("Failed to authenticate") } return &user.DefaultInfo{Name: username}, true, nil } <ins> // 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 } </ins> // NewKeystoneAuthenticator returns a password authenticator that validates credentials using openstack keystone <del> func NewKeystoneAuthenticator(authURL string) (*KeystoneAuthenticator, error) { </del> <ins> func NewKeystoneAuthenticator(authURL string, caFile string) (*KeystoneAuthenticator, error) { </ins> 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") } <ins> 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 } </ins> <del> return &KeystoneAuthenticator{authURL}, nil </del> <ins> return &KeystoneAuthenticator{authURL: authURL}, nil </ins> }