From eb554e7d36b9a81cbbfb9b706d40322747413544 Mon Sep 17 00:00:00 2001 From: Martin Schuppert Date: Fri, 14 Jul 2023 15:24:09 +0200 Subject: [PATCH] [TLS] Gophercloud client to support TLS settings Allows to pass in TLSConfig settings the the openstackclient for register e.g. endpoints. The config can be a list of CACert's, Insecure parameter and client cert/key. Jira: OSP-26299 Jira: OSP-26845 --- modules/openstack/openstack.go | 74 ++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/modules/openstack/openstack.go b/modules/openstack/openstack.go index b392f6ed..95e37400 100644 --- a/modules/openstack/openstack.go +++ b/modules/openstack/openstack.go @@ -17,7 +17,11 @@ limitations under the License. package openstack import ( + "crypto/tls" + "crypto/x509" "fmt" + "net/http" + "time" "github.com/go-logr/logr" gophercloud "github.com/gophercloud/gophercloud" @@ -25,6 +29,11 @@ import ( service "github.com/openstack-k8s-operators/lib-common/modules/common/service" ) +const ( + // defaultRequestTimeout is the default timeout duration for requests + defaultRequestTimeout = 10 * time.Second +) + // OpenStack - type OpenStack struct { osclient *gophercloud.ServiceClient @@ -41,6 +50,15 @@ type AuthOpts struct { DomainName string Region string Scope *gophercloud.AuthScope + TLS *TLSConfig +} + +// TLSConfig - settings +type TLSConfig struct { + CACerts []string + Insecure bool + ClientCert string + ClientKey string } // NewOpenStack creates a new new instance of the openstack struct from a config struct @@ -60,12 +78,62 @@ func NewOpenStack( opts.Scope = cfg.Scope } - provider, err := openstack.AuthenticatedClient(opts) + // define http client for setting timeout, proxy and tls settings + httpClient := http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + }, + Timeout: defaultRequestTimeout, + } + + // create tls config + tlsConfig := &tls.Config{} + if cfg.TLS != nil { + if len(cfg.TLS.CACerts) > 0 { + caCertPool := x509.NewCertPool() + for _, caCert := range cfg.TLS.CACerts { + caCertPool.AppendCertsFromPEM([]byte(caCert)) + } + tlsConfig.RootCAs = caCertPool + } + if cfg.TLS.Insecure { + tlsConfig.InsecureSkipVerify = true + } + + if cfg.TLS.ClientCert != "" && cfg.TLS.ClientKey != "" { + cert, err := tls.LoadX509KeyPair(cfg.TLS.ClientCert, cfg.TLS.ClientKey) + if err != nil { + return nil, err + } + + tlsConfig.Certificates = []tls.Certificate{cert} + } + } + + transport := &http.Transport{Proxy: http.ProxyFromEnvironment, TLSClientConfig: tlsConfig} + + // create provider client and add inject customized http client + providerClient, err := openstack.NewClient(opts.IdentityEndpoint) + if err != nil { + return nil, err + } + + providerClient.HTTPClient = httpClient + providerClient.HTTPClient.Transport = transport + + // authenticate the client + err = openstack.Authenticate(providerClient, opts) if err != nil { return nil, err } - endpointOpts := gophercloud.EndpointOpts{Type: "identity", Region: cfg.Region} - identityClient, err := openstack.NewIdentityV3(provider, endpointOpts) + + // create the identity client using previous providerClient + endpointOpts := gophercloud.EndpointOpts{ + Type: "identity", + Region: cfg.Region, + Availability: gophercloud.AvailabilityInternal, + } + identityClient, err := openstack.NewIdentityV3(providerClient, endpointOpts) if err != nil { return nil, err }