From 092907077d9eef1e84fb6307a42aca2002635ef0 Mon Sep 17 00:00:00 2001 From: Hans Hasselberg Date: Tue, 8 Jan 2019 17:09:22 +0100 Subject: [PATCH] connect: add tls config for vault connect ca provider (#5125) * add tlsconfig for vault connect ca provider. * add options to the docs * add tests for new configuration --- agent/config/builder.go | 6 +++ agent/config/runtime_test.go | 56 ++++++++++++++++++++ agent/connect/ca/provider_vault.go | 15 ++++++ agent/connect/ca/provider_vault_test.go | 20 +++++++ agent/structs/connect_ca.go | 7 +++ website/source/docs/connect/ca/vault.html.md | 23 ++++++++ 6 files changed, 127 insertions(+) diff --git a/agent/config/builder.go b/agent/config/builder.go index 4d8455f3b..0a2635200 100644 --- a/agent/config/builder.go +++ b/agent/config/builder.go @@ -568,6 +568,12 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) { "token": "Token", "root_pki_path": "RootPKIPath", "intermediate_pki_path": "IntermediatePKIPath", + "ca_file": "CAFile", + "ca_path": "CAPath", + "cert_file": "CertFile", + "key_file": "KeyFile", + "tls_server_name": "TLSServerName", + "tls_skip_verify": "TLSSkipVerify", // Common CA config "leaf_cert_ttl": "LeafCertTTL", diff --git a/agent/config/runtime_test.go b/agent/config/runtime_test.go index 26408d67e..b1f2c1631 100644 --- a/agent/config/runtime_test.go +++ b/agent/config/runtime_test.go @@ -2637,6 +2637,62 @@ func TestConfigFlagsAndEdgecases(t *testing.T) { rt.VerifyOutgoing = true }, }, + { + desc: "test connect vault provider configuration", + args: []string{ + `-data-dir=` + dataDir, + }, + json: []string{`{ + "connect": { + "enabled": true, + "ca_provider": "vault", + "ca_config": { + "ca_file": "/capath/ca.pem", + "ca_path": "/capath/", + "cert_file": "/certpath/cert.pem", + "key_file": "/certpath/key.pem", + "tls_server_name": "server.name", + "tls_skip_verify": true, + "token": "abc", + "root_pki_path": "consul-vault", + "intermediate_pki_path": "connect-intermediate" + } + } + }`}, + hcl: []string{` + connect { + enabled = true + ca_provider = "vault" + ca_config { + ca_file = "/capath/ca.pem" + ca_path = "/capath/" + cert_file = "/certpath/cert.pem" + key_file = "/certpath/key.pem" + tls_server_name = "server.name" + tls_skip_verify = true + token = "abc" + root_pki_path = "consul-vault" + intermediate_pki_path = "connect-intermediate" + } + } + `}, + patch: func(rt *RuntimeConfig) { + rt.DataDir = dataDir + rt.ConnectEnabled = true + rt.ConnectCAProvider = "vault" + rt.ConnectCAConfig = map[string]interface{}{ + "CAFile": "/capath/ca.pem", + "CAPath": "/capath/", + "CertFile": "/certpath/cert.pem", + "KeyFile": "/certpath/key.pem", + "TLSServerName": "server.name", + "TLSSkipVerify": true, + "Token": "abc", + "RootPKIPath": "consul-vault", + "IntermediatePKIPath": "connect-intermediate", + } + }, + }, } testConfig(t, tests, dataDir) diff --git a/agent/connect/ca/provider_vault.go b/agent/connect/ca/provider_vault.go index a583f9197..c9c0076de 100644 --- a/agent/connect/ca/provider_vault.go +++ b/agent/connect/ca/provider_vault.go @@ -28,6 +28,17 @@ type VaultProvider struct { clusterId string } +func vaultTLSConfig(config *structs.VaultCAProviderConfig) *vaultapi.TLSConfig { + return &vaultapi.TLSConfig{ + CACert: config.CAFile, + CAPath: config.CAPath, + ClientCert: config.CertFile, + ClientKey: config.KeyFile, + Insecure: config.TLSSkipVerify, + TLSServerName: config.TLSServerName, + } +} + // Configure sets up the provider using the given configuration. func (v *VaultProvider) Configure(clusterId string, isRoot bool, rawConfig map[string]interface{}) error { config, err := ParseVaultCAConfig(rawConfig) @@ -38,6 +49,10 @@ func (v *VaultProvider) Configure(clusterId string, isRoot bool, rawConfig map[s clientConf := &vaultapi.Config{ Address: config.Address, } + err = clientConf.ConfigureTLS(vaultTLSConfig(config)) + if err != nil { + return err + } client, err := vaultapi.NewClient(clientConf) if err != nil { return err diff --git a/agent/connect/ca/provider_vault_test.go b/agent/connect/ca/provider_vault_test.go index 7409ae7c6..d236b7287 100644 --- a/agent/connect/ca/provider_vault_test.go +++ b/agent/connect/ca/provider_vault_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/hashicorp/consul/agent/connect" + "github.com/hashicorp/consul/agent/structs" vaultapi "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/builtin/logical/pki" vaulthttp "github.com/hashicorp/vault/http" @@ -51,6 +52,25 @@ func testVaultClusterWithConfig(t *testing.T, isRoot bool, rawConf map[string]in return provider, core, ln } +func TestVaultCAProvider_VaultTLSConfig(t *testing.T) { + config := &structs.VaultCAProviderConfig{ + CAFile: "/capath/ca.pem", + CAPath: "/capath/", + CertFile: "/certpath/cert.pem", + KeyFile: "/certpath/key.pem", + TLSServerName: "server.name", + TLSSkipVerify: true, + } + tlsConfig := vaultTLSConfig(config) + require := require.New(t) + require.Equal(config.CAFile, tlsConfig.CACert) + require.Equal(config.CAPath, tlsConfig.CAPath) + require.Equal(config.CertFile, tlsConfig.ClientCert) + require.Equal(config.KeyFile, tlsConfig.ClientKey) + require.Equal(config.TLSServerName, tlsConfig.TLSServerName) + require.Equal(config.TLSSkipVerify, tlsConfig.Insecure) +} + func TestVaultCAProvider_Bootstrap(t *testing.T) { t.Parallel() diff --git a/agent/structs/connect_ca.go b/agent/structs/connect_ca.go index a5a78aac1..a51f9b4bd 100644 --- a/agent/structs/connect_ca.go +++ b/agent/structs/connect_ca.go @@ -286,6 +286,13 @@ type VaultCAProviderConfig struct { Token string RootPKIPath string IntermediatePKIPath string + + CAFile string + CAPath string + CertFile string + KeyFile string + TLSServerName string + TLSSkipVerify bool } // ParseDurationFunc is a mapstructure hook for decoding a string or diff --git a/website/source/docs/connect/ca/vault.html.md b/website/source/docs/connect/ca/vault.html.md index 43440bc58..70af12336 100644 --- a/website/source/docs/connect/ca/vault.html.md +++ b/website/source/docs/connect/ca/vault.html.md @@ -68,6 +68,29 @@ is used if configuring in an agent configuration file. path doesn't exist, Consul will attempt to mount and configure this automatically. + * `CAFile` / `ca_file` (`string: ""`) - Specifies an optional path to the CA + certificate used for Vault communication. If unspecified, this will fallback + to the default system CA bundle, which varies by OS and version. + + * `CAPath` / `ca_path` (`string: ""`) - Specifies an optional path to a folder + containing CA certificates to be used for Vault communication. If + unspecified, this will fallback to the default system CA bundle, which + varies by OS and version. + + * `CertFile` / `cert_file` (`string: ""`) - Specifies the path to the + certificate used for Vault communication. If this is set then you need to + also set tls_key_file. + + * `KeyFile` / `key_file` (`string: ""`) - Specifies the path to the private + key used for Vault communication. If this is set then you need to also set + cert_file. + + * `TLSServerName` / `tls_server_name` (`string: ""`) - Specifies an optional + string used to set the SNI host when connecting to Vault via TLS. + + * `TLSSkipVerify` / `tls_skip_verify` (`bool: false`) - Specifies if SSL peer + validation should be enforced. + ## Root and Intermediate PKI Paths The Vault CA provider uses two separately configured