diff --git a/docs/drivers/openstack.md b/docs/drivers/openstack.md index 2e185c6..be514ac 100644 --- a/docs/drivers/openstack.md +++ b/docs/drivers/openstack.md @@ -25,6 +25,7 @@ Options: - `--openstack-active-timeout`: The timeout in seconds until the OpenStack instance must be active. - `--openstack-availability-zone`: The availability zone in which to launch the server. +- `--openstack-cacert`: The CA certificate bundle to verify against. - `--openstack-domain-name` or `--openstack-domain-id`: Domain to use for authentication (Keystone v3 only). - `--openstack-endpoint-type`: Endpoint type can be `internalURL`, `adminURL` on `publicURL`. If is a helper for the driver to choose the right URL in the OpenStack service catalog. If not provided the default id `publicURL` @@ -52,6 +53,7 @@ Environment variables and default values: | `--openstack-active-timeout` | `OS_ACTIVE_TIMEOUT` | `200` | | `--openstack-auth-url` | `OS_AUTH_URL` | - | | `--openstack-availability-zone` | `OS_AVAILABILITY_ZONE` | - | +| `--openstack-cacert` | `OS_CACERT | - | | `--openstack-domain-id` | `OS_DOMAIN_ID` | - | | `--openstack-domain-name` | `OS_DOMAIN_NAME` | - | | `--openstack-endpoint-type` | `OS_ENDPOINT_TYPE` | `publicURL` | diff --git a/drivers/openstack/client.go b/drivers/openstack/client.go index 83a5739..0bf32ca 100644 --- a/drivers/openstack/client.go +++ b/drivers/openstack/client.go @@ -2,7 +2,9 @@ package openstack import ( "crypto/tls" + "crypto/x509" "fmt" + "io/ioutil" "net/http" "time" @@ -532,6 +534,7 @@ func (c *GenericClient) Authenticate(d *Driver) error { log.Debug("Authenticating...", map[string]interface{}{ "AuthUrl": d.AuthUrl, "Insecure": d.Insecure, + "CaCert": d.CaCert, "DomainID": d.DomainID, "DomainName": d.DomainName, "Username": d.Username, @@ -555,21 +558,45 @@ func (c *GenericClient) Authenticate(d *Driver) error { return err } - provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%d", version.APIVersion)) + c.Provider = provider - if d.Insecure { - // Configure custom TLS settings. - config := &tls.Config{InsecureSkipVerify: true} - transport := &http.Transport{TLSClientConfig: config} - provider.HTTPClient.Transport = transport - } + c.Provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%d", version.APIVersion)) - err = openstack.Authenticate(provider, opts) + err = c.SetTLSConfig(d) if err != nil { return err } - c.Provider = provider + err = openstack.Authenticate(c.Provider, opts) + if err != nil { + return err + } return nil } + +func (c *GenericClient) SetTLSConfig(d *Driver) error { + + config := &tls.Config{} + config.InsecureSkipVerify = d.Insecure + + if d.CaCert != "" { + // Use custom CA certificate(s) for root of trust + certpool := x509.NewCertPool() + pem, err := ioutil.ReadFile(d.CaCert) + if err != nil { + log.Error("Unable to read specified CA certificate(s)") + return err + } + + ok := certpool.AppendCertsFromPEM(pem) + if !ok { + return fmt.Errorf("Ill-formed CA certificate(s) PEM file") + } + config.RootCAs = certpool + } + + transport := &http.Transport{TLSClientConfig: config} + c.Provider.HTTPClient.Transport = transport + return nil +} diff --git a/drivers/openstack/openstack.go b/drivers/openstack/openstack.go index 89ce20c..0eadb5a 100644 --- a/drivers/openstack/openstack.go +++ b/drivers/openstack/openstack.go @@ -20,6 +20,7 @@ type Driver struct { AuthUrl string ActiveTimeout int Insecure bool + CaCert string DomainID string DomainName string Username string @@ -66,6 +67,12 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag { Name: "openstack-insecure", Usage: "Disable TLS credential checking.", }, + mcnflag.StringFlag{ + EnvVar: "OS_CACERT", + Name: "openstack-cacert", + Usage: "CA certificate bundle to verify against", + Value: "", + }, mcnflag.StringFlag{ EnvVar: "OS_DOMAIN_ID", Name: "openstack-domain-id", @@ -252,6 +259,7 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.AuthUrl = flags.String("openstack-auth-url") d.ActiveTimeout = flags.Int("openstack-active-timeout") d.Insecure = flags.Bool("openstack-insecure") + d.CaCert = flags.String("openstack-cacert") d.DomainID = flags.String("openstack-domain-id") d.DomainName = flags.String("openstack-domain-name") d.Username = flags.String("openstack-username")