From efe4b212877fbb913efb677e59f8a3a7f7dd3aa3 Mon Sep 17 00:00:00 2001 From: Connor Date: Fri, 5 Nov 2021 11:42:28 -0500 Subject: [PATCH] Support Vault Namespaces explicitly in CA config (#11477) * Support Vault Namespaces explicitly in CA config If there is a Namespace entry included in the Vault CA configuration, set it as the Vault Namespace on the Vault client Currently the only way to support Vault namespaces in the Consul CA config is by doing one of the following: 1) Set the VAULT_NAMESPACE environment variable which will be picked up by the Vault API client 2) Prefix all Vault paths with the namespace Neither of these are super pleasant. The first requires direct access and modification to the Consul runtime environment. It's possible and expected, not super pleasant. The second requires more indepth knowledge of Vault and how it uses Namespaces and could be confusing for anyone without that context. It also infers that it is not supported * Add changelog * Remove fmt.Fprint calls * Make comment clearer * Add next consul version to website docs * Add new test for default configuration * go mod tidy * Add skip if vault not present * Tweak changelog text --- .changelog/11477.txt | 3 ++ agent/connect/ca/provider_vault.go | 8 +++++ agent/connect/ca/provider_vault_test.go | 41 +++++++++++++++++++++++ agent/structs/connect_ca.go | 1 + go.mod | 1 + website/content/docs/connect/ca/vault.mdx | 4 +++ 6 files changed, 58 insertions(+) create mode 100644 .changelog/11477.txt diff --git a/.changelog/11477.txt b/.changelog/11477.txt new file mode 100644 index 0000000000..12b6745fc2 --- /dev/null +++ b/.changelog/11477.txt @@ -0,0 +1,3 @@ +```release-note:improvement +connect: add Namespace configuration setting for Vault CA provider +``` diff --git a/agent/connect/ca/provider_vault.go b/agent/connect/ca/provider_vault.go index 872ca2e5e2..0f174f1a5b 100644 --- a/agent/connect/ca/provider_vault.go +++ b/agent/connect/ca/provider_vault.go @@ -75,6 +75,14 @@ func (v *VaultProvider) Configure(cfg ProviderConfig) error { } client.SetToken(config.Token) + + // We don't want to set the namespace if it's empty to prevent potential + // unknown behavior (what does Vault do with an empty namespace). The Vault + // client also makes sure the inputs are not empty strings so let's do the + // same. + if config.Namespace != "" { + client.SetNamespace(config.Namespace) + } v.config = config v.client = client v.isPrimary = cfg.IsPrimary diff --git a/agent/connect/ca/provider_vault_test.go b/agent/connect/ca/provider_vault_test.go index a670effd2b..ccb7fc01c3 100644 --- a/agent/connect/ca/provider_vault_test.go +++ b/agent/connect/ca/provider_vault_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/go-hclog" vaultapi "github.com/hashicorp/vault/api" + vaultconst "github.com/hashicorp/vault/sdk/helper/consts" "github.com/stretchr/testify/require" "github.com/hashicorp/consul/agent/connect" @@ -36,6 +37,46 @@ func TestVaultCAProvider_VaultTLSConfig(t *testing.T) { require.Equal(config.TLSSkipVerify, tlsConfig.Insecure) } +func TestVaultCAProvider_Configure(t *testing.T) { + SkipIfVaultNotPresent(t) + + testcases := []struct { + name string + rawConfig map[string]interface{} + expectedValue func(t *testing.T, v *VaultProvider) + }{ + { + name: "DefaultConfig", + rawConfig: map[string]interface{}{}, + expectedValue: func(t *testing.T, v *VaultProvider) { + headers := v.client.Headers() + require.Equal(t, "", headers.Get(vaultconst.NamespaceHeaderName)) + require.Equal(t, "pki-root/", v.config.RootPKIPath) + require.Equal(t, "pki-intermediate/", v.config.IntermediatePKIPath) + }, + }, + { + name: "TestConfigWithNamespace", + rawConfig: map[string]interface{}{"namespace": "ns1"}, + expectedValue: func(t *testing.T, v *VaultProvider) { + + h := v.client.Headers() + require.Equal(t, "ns1", h.Get(vaultconst.NamespaceHeaderName)) + }, + }, + } + + for _, testcase := range testcases { + t.Run(testcase.name, func(t *testing.T) { + provider, _ := testVaultProviderWithConfig(t, true, testcase.rawConfig) + + testcase.expectedValue(t, provider) + }) + } + + return +} + func TestVaultCAProvider_SecondaryActiveIntermediate(t *testing.T) { SkipIfVaultNotPresent(t) diff --git a/agent/structs/connect_ca.go b/agent/structs/connect_ca.go index 8c2186498f..e7e9822bcb 100644 --- a/agent/structs/connect_ca.go +++ b/agent/structs/connect_ca.go @@ -473,6 +473,7 @@ type VaultCAProviderConfig struct { Token string RootPKIPath string IntermediatePKIPath string + Namespace string CAFile string CAPath string diff --git a/go.mod b/go.mod index aea4264ed1..a697ac7ab6 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,7 @@ require ( github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea github.com/hashicorp/serf v0.9.6-0.20210609195804-2b5dd0cd2de9 github.com/hashicorp/vault/api v1.0.5-0.20200717191844-f687267c8086 + github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267 github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 github.com/imdario/mergo v0.3.6 github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect diff --git a/website/content/docs/connect/ca/vault.mdx b/website/content/docs/connect/ca/vault.mdx index e562df62eb..622bf47c30 100644 --- a/website/content/docs/connect/ca/vault.mdx +++ b/website/content/docs/connect/ca/vault.mdx @@ -132,6 +132,10 @@ The configuration options are listed below. - `TLSSkipVerify` / `tls_skip_verify` (`bool: false`) - Specifies if SSL peer validation should be enforced. +- `Namespace` / `namespace` (`string: `) - The Vault Namespace that + the `Token` and PKI Certificates are a part of. Vault Namespaces are a Vault + Enterprise feature. Added in Consul 1.11.0 + @include 'http_api_connect_ca_common_options.mdx' ## Root and Intermediate PKI Paths