Merge pull request #1682 from hashicorp/f-refactor-tls-config

Refactor the TLS configuration between meta.Client and the api.Config
This commit is contained in:
Alex Dadgar
2016-08-02 13:35:37 -07:00
committed by GitHub
2 changed files with 86 additions and 64 deletions

View File

@@ -57,6 +57,31 @@ type Config struct {
MaxRetries int MaxRetries int
} }
// TLSConfig contains the parameters needed to configure TLS on the HTTP client
// used to communicate with Vault.
type TLSConfig struct {
// CACert is the path to a PEM-encoded CA cert file to use to verify the
// Vault server SSL certificate.
CACert string
// CAPath is the path to a directory of PEM-encoded CA cert files to verify
// the Vault server SSL certificate.
CAPath string
// ClientCert is the path to the certificate for Vault communication
ClientCert string
// ClientKey is the path to the private key for Vault communication
ClientKey string
// TLSServerName, if set, is used to set the SNI host when connecting via
// TLS.
TLSServerName string
// Insecure enables or disables SSL verification
Insecure bool
}
// DefaultConfig returns a default configuration for the client. It is // DefaultConfig returns a default configuration for the client. It is
// safe to modify the return value of this function. // safe to modify the return value of this function.
// //
@@ -84,6 +109,49 @@ func DefaultConfig() *Config {
return config return config
} }
// ConfigureTLS takes a set of TLS configurations and applies those to the the HTTP client.
func (c *Config) ConfigureTLS(t *TLSConfig) error {
if c.HttpClient == nil {
return fmt.Errorf("config HTTP Client must be set")
}
var clientCert tls.Certificate
foundClientCert := false
if t.CACert != "" || t.CAPath != "" || t.ClientCert != "" || t.ClientKey != "" || t.Insecure {
if t.ClientCert != "" && t.ClientKey != "" {
var err error
clientCert, err = tls.LoadX509KeyPair(t.ClientCert, t.ClientKey)
if err != nil {
return err
}
foundClientCert = true
} else if t.ClientCert != "" || t.ClientKey != "" {
return fmt.Errorf("Both client cert and client key must be provided")
}
}
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
rootConfig := &rootcerts.Config{
CAFile: t.CACert,
CAPath: t.CAPath,
}
if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil {
return err
}
clientTLSConfig.InsecureSkipVerify = t.Insecure
if foundClientCert {
clientTLSConfig.Certificates = []tls.Certificate{clientCert}
}
if t.TLSServerName != "" {
clientTLSConfig.ServerName = t.TLSServerName
}
return nil
}
// ReadEnvironment reads configuration information from the // ReadEnvironment reads configuration information from the
// environment. If there is an error, no configuration value // environment. If there is an error, no configuration value
// is updated. // is updated.
@@ -94,15 +162,10 @@ func (c *Config) ReadEnvironment() error {
var envClientCert string var envClientCert string
var envClientKey string var envClientKey string
var envInsecure bool var envInsecure bool
var foundInsecure bool
var envTLSServerName string var envTLSServerName string
var envMaxRetries *uint64 var envMaxRetries *uint64
var clientCert tls.Certificate // Parse the environment variables
var foundClientCert bool
var err error
if v := os.Getenv(EnvVaultAddress); v != "" { if v := os.Getenv(EnvVaultAddress); v != "" {
envAddress = v envAddress = v
} }
@@ -131,31 +194,21 @@ func (c *Config) ReadEnvironment() error {
if err != nil { if err != nil {
return fmt.Errorf("Could not parse VAULT_SKIP_VERIFY") return fmt.Errorf("Could not parse VAULT_SKIP_VERIFY")
} }
foundInsecure = true
} }
if v := os.Getenv(EnvVaultTLSServerName); v != "" { if v := os.Getenv(EnvVaultTLSServerName); v != "" {
envTLSServerName = v envTLSServerName = v
} }
// If we need custom TLS configuration, then set it
if envCACert != "" || envCAPath != "" || envClientCert != "" || envClientKey != "" || envInsecure {
if envClientCert != "" && envClientKey != "" {
clientCert, err = tls.LoadX509KeyPair(envClientCert, envClientKey)
if err != nil {
return err
}
foundClientCert = true
} else if envClientCert != "" || envClientKey != "" {
return fmt.Errorf("Both client cert and client key must be provided")
}
}
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig // Configure the HTTP clients TLS configuration.
rootConfig := &rootcerts.Config{ t := &TLSConfig{
CAFile: envCACert, CACert: envCACert,
CAPath: envCAPath, CAPath: envCAPath,
ClientCert: envClientCert,
ClientKey: envClientKey,
TLSServerName: envTLSServerName,
Insecure: envInsecure,
} }
err = rootcerts.ConfigureTLS(clientTLSConfig, rootConfig) if err := c.ConfigureTLS(t); err != nil {
if err != nil {
return err return err
} }
@@ -167,17 +220,6 @@ func (c *Config) ReadEnvironment() error {
c.MaxRetries = int(*envMaxRetries) + 1 c.MaxRetries = int(*envMaxRetries) + 1
} }
if foundInsecure {
clientTLSConfig.InsecureSkipVerify = envInsecure
}
if foundClientCert {
clientTLSConfig.Certificates = []tls.Certificate{clientCert}
}
if envTLSServerName != "" {
clientTLSConfig.ServerName = envTLSServerName
}
return nil return nil
} }

View File

@@ -2,15 +2,11 @@ package meta
import ( import (
"bufio" "bufio"
"crypto/tls"
"flag" "flag"
"fmt"
"io" "io"
"net/http"
"os" "os"
"github.com/hashicorp/errwrap" "github.com/hashicorp/errwrap"
"github.com/hashicorp/go-rootcerts"
"github.com/hashicorp/vault/api" "github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/token" "github.com/hashicorp/vault/command/token"
"github.com/mitchellh/cli" "github.com/mitchellh/cli"
@@ -76,31 +72,15 @@ func (m *Meta) Client() (*api.Client, error) {
} }
// If we need custom TLS configuration, then set it // If we need custom TLS configuration, then set it
if m.flagCACert != "" || m.flagCAPath != "" || m.flagClientCert != "" || m.flagClientKey != "" || m.flagInsecure { if m.flagCACert != "" || m.flagCAPath != "" || m.flagClientCert != "" || m.flagClientKey != "" || m.flagInsecure {
// We may have set items from the environment so start with the t := &api.TLSConfig{
// existing TLS config CACert: m.flagCACert,
tlsConfig := config.HttpClient.Transport.(*http.Transport).TLSClientConfig
rootConfig := &rootcerts.Config{
CAFile: m.flagCACert,
CAPath: m.flagCAPath, CAPath: m.flagCAPath,
ClientCert: m.flagClientCert,
ClientKey: m.flagClientKey,
TLSServerName: "",
Insecure: m.flagInsecure,
} }
if err := rootcerts.ConfigureTLS(tlsConfig, rootConfig); err != nil { config.ConfigureTLS(t)
return nil, err
}
if m.flagInsecure {
tlsConfig.InsecureSkipVerify = true
}
if m.flagClientCert != "" && m.flagClientKey != "" {
tlsCert, err := tls.LoadX509KeyPair(m.flagClientCert, m.flagClientKey)
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{tlsCert}
} else if m.flagClientCert != "" || m.flagClientKey != "" {
return nil, fmt.Errorf("Both client cert and client key must be provided")
}
} }
// Build the client // Build the client