Allow OpenStack SSL fields to be specified by contents
- OpenStack provider now supports either a path or the file contents for `cacert_file`, `cert`, and `key` - Makes it easier to automate TF by passing in certs as environment variables - set `OS_SSL_TESTS=true` to run the acceptance tests
This commit is contained in:
parent
2d894bae48
commit
3b7cf41b83
|
@ -4,12 +4,12 @@ import (
|
|||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/openstack"
|
||||
"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth"
|
||||
"github.com/hashicorp/terraform/helper/pathorcontents"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -70,13 +70,13 @@ func (c *Config) loadAndValidate() error {
|
|||
|
||||
config := &tls.Config{}
|
||||
if c.CACertFile != "" {
|
||||
caCert, err := ioutil.ReadFile(c.CACertFile)
|
||||
caCert, _, err := pathorcontents.Read(c.CACertFile)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Error reading CA Cert: %s", err)
|
||||
}
|
||||
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
caCertPool.AppendCertsFromPEM([]byte(caCert))
|
||||
config.RootCAs = caCertPool
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,16 @@ func (c *Config) loadAndValidate() error {
|
|||
}
|
||||
|
||||
if c.ClientCertFile != "" && c.ClientKeyFile != "" {
|
||||
cert, err := tls.LoadX509KeyPair(c.ClientCertFile, c.ClientKeyFile)
|
||||
clientCert, _, err := pathorcontents.Read(c.ClientCertFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading Client Cert: %s", err)
|
||||
}
|
||||
clientKey, _, err := pathorcontents.Read(c.ClientKeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading Client Key: %s", err)
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/config"
|
||||
"github.com/hashicorp/terraform/helper/pathorcontents"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
@ -23,16 +27,6 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_impl(t *testing.T) {
|
||||
var _ terraform.ResourceProvider = Provider()
|
||||
}
|
||||
|
||||
func testAccPreCheck(t *testing.T) {
|
||||
v := os.Getenv("OS_AUTH_URL")
|
||||
if v == "" {
|
||||
|
@ -73,3 +67,172 @@ func testAccPreCheck(t *testing.T) {
|
|||
t.Fatal("OS_EXTGW_ID must be set for acceptance tests")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_impl(t *testing.T) {
|
||||
var _ terraform.ResourceProvider = Provider()
|
||||
}
|
||||
|
||||
// Steps for configuring OpenStack with SSL validation are here:
|
||||
// https://github.com/hashicorp/terraform/pull/6279#issuecomment-219020144
|
||||
func TestAccProvider_caCertFile(t *testing.T) {
|
||||
if os.Getenv("TF_ACC") == "" || os.Getenv("OS_SSL_TESTS") == "" {
|
||||
t.Skip("TF_ACC or OS_SSL_TESTS not set, skipping OpenStack SSL test.")
|
||||
}
|
||||
if os.Getenv("OS_CACERT") == "" {
|
||||
t.Skip("OS_CACERT is not set; skipping OpenStack CA test.")
|
||||
}
|
||||
|
||||
p := Provider()
|
||||
|
||||
caFile, err := envVarFile("OS_CACERT")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(caFile)
|
||||
|
||||
raw := map[string]interface{}{
|
||||
"cacert_file": caFile,
|
||||
}
|
||||
rawConfig, err := config.NewRawConfig(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
err = p.Configure(terraform.NewResourceConfig(rawConfig))
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected err when specifying OpenStack CA by file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccProvider_caCertString(t *testing.T) {
|
||||
if os.Getenv("TF_ACC") == "" || os.Getenv("OS_SSL_TESTS") == "" {
|
||||
t.Skip("TF_ACC or OS_SSL_TESTS not set, skipping OpenStack SSL test.")
|
||||
}
|
||||
if os.Getenv("OS_CACERT") == "" {
|
||||
t.Skip("OS_CACERT is not set; skipping OpenStack CA test.")
|
||||
}
|
||||
|
||||
p := Provider()
|
||||
|
||||
caContents, err := envVarContents("OS_CACERT")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
raw := map[string]interface{}{
|
||||
"cacert_file": caContents,
|
||||
}
|
||||
rawConfig, err := config.NewRawConfig(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
err = p.Configure(terraform.NewResourceConfig(rawConfig))
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected err when specifying OpenStack CA by string: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccProvider_clientCertFile(t *testing.T) {
|
||||
if os.Getenv("TF_ACC") == "" || os.Getenv("OS_SSL_TESTS") == "" {
|
||||
t.Skip("TF_ACC or OS_SSL_TESTS not set, skipping OpenStack SSL test.")
|
||||
}
|
||||
if os.Getenv("OS_CERT") == "" || os.Getenv("OS_KEY") == "" {
|
||||
t.Skip("OS_CERT or OS_KEY is not set; skipping OpenStack client SSL auth test.")
|
||||
}
|
||||
|
||||
p := Provider()
|
||||
|
||||
certFile, err := envVarFile("OS_CERT")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(certFile)
|
||||
keyFile, err := envVarFile("OS_KEY")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(keyFile)
|
||||
|
||||
raw := map[string]interface{}{
|
||||
"cert": certFile,
|
||||
"key": keyFile,
|
||||
}
|
||||
rawConfig, err := config.NewRawConfig(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
err = p.Configure(terraform.NewResourceConfig(rawConfig))
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected err when specifying OpenStack Client keypair by file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccProvider_clientCertString(t *testing.T) {
|
||||
if os.Getenv("TF_ACC") == "" || os.Getenv("OS_SSL_TESTS") == "" {
|
||||
t.Skip("TF_ACC or OS_SSL_TESTS not set, skipping OpenStack SSL test.")
|
||||
}
|
||||
if os.Getenv("OS_CERT") == "" || os.Getenv("OS_KEY") == "" {
|
||||
t.Skip("OS_CERT or OS_KEY is not set; skipping OpenStack client SSL auth test.")
|
||||
}
|
||||
|
||||
p := Provider()
|
||||
|
||||
certContents, err := envVarContents("OS_CERT")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
keyContents, err := envVarContents("OS_KEY")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
raw := map[string]interface{}{
|
||||
"cert": certContents,
|
||||
"key": keyContents,
|
||||
}
|
||||
rawConfig, err := config.NewRawConfig(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
err = p.Configure(terraform.NewResourceConfig(rawConfig))
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected err when specifying OpenStack Client keypair by contents: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func envVarContents(varName string) (string, error) {
|
||||
contents, _, err := pathorcontents.Read(os.Getenv(varName))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error reading %s: %s", varName, err)
|
||||
}
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func envVarFile(varName string) (string, error) {
|
||||
contents, err := envVarContents(varName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tmpFile, err := ioutil.TempFile("", varName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error creating temp file: %s", err)
|
||||
}
|
||||
if _, err := tmpFile.Write([]byte(contents)); err != nil {
|
||||
_ = os.Remove(tmpFile.Name())
|
||||
return "", fmt.Errorf("Error writing temp file: %s", err)
|
||||
}
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
_ = os.Remove(tmpFile.Name())
|
||||
return "", fmt.Errorf("Error closing temp file: %s", err)
|
||||
}
|
||||
return tmpFile.Name(), nil
|
||||
}
|
||||
|
|
|
@ -74,13 +74,16 @@ The following arguments are supported:
|
|||
`OS_INSECURE` environment variable is used.
|
||||
|
||||
* `cacert_file` - (Optional) Specify a custom CA certificate when communicating
|
||||
over SSL. If omitted, the `OS_CACERT` environment variable is used.
|
||||
over SSL. You can specify either a path to the file or the contents of the
|
||||
certificate. If omitted, the `OS_CACERT` environment variable is used.
|
||||
|
||||
* `cert` - (Optional) Specify client certificate file for SSL client
|
||||
authentication. If omitted the `OS_CERT` environment variable is used.
|
||||
authentication. You can specify either a path to the file or the contents of
|
||||
the certificate. If omitted the `OS_CERT` environment variable is used.
|
||||
|
||||
* `key` - (Optional) Specify client private key file for SSL client
|
||||
authentication. If omitted the `OS_KEY` environment variable is used.
|
||||
authentication. You can specify either a path to the file or the contents of
|
||||
the key. If omitted the `OS_KEY` environment variable is used.
|
||||
|
||||
* `endpoint_type` - (Optional) Specify which type of endpoint to use from the
|
||||
service catalog. It can be set using the OS_ENDPOINT_TYPE environment
|
||||
|
|
Loading…
Reference in New Issue