From 9e1c4d0cde38e4b24e5c42066959939acd7c27d2 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Fri, 19 Nov 2021 12:58:37 -0700 Subject: [PATCH 01/11] wip: support connect CA without TLS --- .../fixtures/bases/intention/intention.yaml | 10 ++ .../bases/intention/kustomization.yaml | 2 + acceptance/tests/vault/vault_test.go | 113 ++++++++++++++---- .../templates/server-config-configmap.yaml | 25 ++++ charts/consul/values.yaml | 24 ++++ 5 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 acceptance/tests/fixtures/bases/intention/intention.yaml create mode 100644 acceptance/tests/fixtures/bases/intention/kustomization.yaml diff --git a/acceptance/tests/fixtures/bases/intention/intention.yaml b/acceptance/tests/fixtures/bases/intention/intention.yaml new file mode 100644 index 0000000000..c7bf26dac2 --- /dev/null +++ b/acceptance/tests/fixtures/bases/intention/intention.yaml @@ -0,0 +1,10 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceIntentions +metadata: + name: client-to-server +spec: + destination: + name: static-server + sources: + - name: static-client + action: allow diff --git a/acceptance/tests/fixtures/bases/intention/kustomization.yaml b/acceptance/tests/fixtures/bases/intention/kustomization.yaml new file mode 100644 index 0000000000..8d15c05511 --- /dev/null +++ b/acceptance/tests/fixtures/bases/intention/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - intention.yaml \ No newline at end of file diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 67b81f1884..7fbef81f73 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -4,34 +4,49 @@ import ( "crypto/rand" "encoding/base64" "fmt" + "testing" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/vault" "github.com/stretchr/testify/require" - "testing" ) -// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string. -func generateGossipSecret() (string, error) { - // This code was copied from Consul's Keygen command: - // https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go +const ( + gossipRules = ` +path "consul/data/secret/gossip" { + capabilities = ["read"] +}` - key := make([]byte, 32) - n, err := rand.Reader.Read(key) - if err != nil { - return "", fmt.Errorf("error reading random data: %s", err) - } - if n != 32 { - return "", fmt.Errorf("couldn't read enough entropy") - } + connectCARules = ` +path "/sys/mounts" { + capabilities = [ "read" ] +} - return base64.StdEncoding.EncodeToString(key), nil +path "/sys/mounts/connect_root" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "/sys/mounts/connect_inter" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "/connect_root/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] } +path "/connect_inter/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} +` +) + +// todo: update // Installs Vault, bootstraps it with secrets, policies, and Kube Auth Method // then creates a gossip encryption secret and uses this to bootstrap Consul. -func TestVault_BootstrapConsulGossipEncryptionKey(t *testing.T) { +func TestVault(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) @@ -48,16 +63,15 @@ func TestVault_BootstrapConsulGossipEncryptionKey(t *testing.T) { vaultClient := vaultCluster.VaultClient(t) // Create the Vault Policy for the gossip key. - logger.Log(t, "Creating the gossip policy") - rules := ` -path "consul/data/secret/gossip" { - capabilities = ["read"] -}` - err := vaultClient.Sys().PutPolicy("consul-gossip", rules) + logger.Log(t, "Creating policies") + err := vaultClient.Sys().PutPolicy("consul-gossip", gossipRules) + require.NoError(t, err) + + err = vaultClient.Sys().PutPolicy("connect-ca", connectCARules) require.NoError(t, err) - // Create the Auth Roles for consul-server + consul-client. - logger.Log(t, "Creating the consul-server and consul-client-roles") + // Create the Auth Roles for consul-server and consul-client. + logger.Log(t, "Creating the consul-server and consul-client roles") params := map[string]interface{}{ "bound_service_account_names": consulClientServiceAccountName, "bound_service_account_namespaces": "default", @@ -70,7 +84,7 @@ path "consul/data/secret/gossip" { params = map[string]interface{}{ "bound_service_account_names": consulServerServiceAccountName, "bound_service_account_namespaces": "default", - "policies": "consul-gossip", + "policies": "consul-gossip,connect-ca", "ttl": "24h", } _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-server", params) @@ -90,15 +104,22 @@ path "consul/data/secret/gossip" { require.NoError(t, err) consulHelmValues := map[string]string{ + "global.image": "ishustava/consul-dev@sha256:a873b4aa28f7511628281e852daab4c04918872bb86023cefb6197acabb43426", + "server.enabled": "true", "server.replicas": "1", "connectInject.enabled": "true", + "controller.enabled": "true", "global.secretsBackend.vault.enabled": "true", "global.secretsBackend.vault.consulServerRole": "consul-server", "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.connectCA.address": fmt.Sprintf("http://%s-vault:8200", vaultReleaseName), + "global.secretsBackend.vault.connectCA.rootPKIPath": "connect_root", + "global.secretsBackend.vault.connectCA.intermediatePKIPath": "connect_inter", + "global.acls.manageSystemACLs": "true", "global.tls.enabled": "true", "global.gossipEncryption.secretName": "consul/data/secret/gossip", @@ -113,6 +134,48 @@ path "consul/data/secret/gossip" { consulClient := consulCluster.SetupConsulClient(t, true) keys, err := consulClient.Operator().KeyringList(nil) require.NoError(t, err) - // We use keys[0] because KeyringList returns a list of keyrings for each dc, in this case there is only 1 dc. + // There should only be one key since there is only 1 dc. + require.Len(t, keys, 1) require.Equal(t, 1, keys[0].PrimaryKeys[gossipKey]) + + // Confirm that the Vault Connect CA has been bootstrapped correctly. + caConfig, _, err := consulClient.Connect().CAGetConfig(nil) + require.Equal(t, caConfig.Provider, "vault") + + // Deploy two services and check that they can talk to each other. + logger.Log(t, "creating static-server and static-client deployments") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if cfg.EnableTransparentProxy { + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + } else { + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.KubectlDeleteK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") + }) + k8s.KubectlApplyK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") + + logger.Log(t, "checking that connection is successful") + if cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://static-server") + } else { + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") + } +} + +// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string. +func generateGossipSecret() (string, error) { + // This code was copied from Consul's Keygen command: + // https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go + + key := make([]byte, 32) + n, err := rand.Reader.Read(key) + if err != nil { + return "", fmt.Errorf("error reading random data: %s", err) + } + if n != 32 { + return "", fmt.Errorf("couldn't read enough entropy") + } + + return base64.StdEncoding.EncodeToString(key), nil } diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index 6faf60b4b9..0b6516c8ce 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -11,6 +11,31 @@ metadata: heritage: {{ .Release.Service }} release: {{ .Release.Name }} data: + {{- with .Values.global.secretsBackend.vault }} + {{- if .connectCA }} + connect-ca-config.json: | + { + "connect": [ + { + "ca_config": [ + { + "address": "{{ .connectCA.address }}", + "intermediate_pki_path": "{{ .connectCA.intermediatePKIPath }}", + "root_pki_path": "{{ .connectCA.rootPKIPath }}", + "auth_method": { + "type": "kubernetes", + "params": { + "role": "{{.consulServerRole}}" + } + } + } + ], + "ca_provider": "vault" + } + ] + } + {{- end }} + {{- end }} extra-from-values.json: |- {{ tpl .Values.server.extraConfig . | trimAll "\"" | indent 4 }} {{- if .Values.global.acls.manageSystemACLs }} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 2a04d7416c..7ecf64a413 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -152,6 +152,30 @@ global: # and check the name of `metadata.name`. consulClientRole: "" + # Configuration for the Vault Connect CA provider. + # The provider will be configured to use the Vault Kubernetes auth method + # and therefore requires the role provided by `consulServerRole` + # needs to have permissions to the root and intermediate PKI paths. + # Please see https://www.consul.io/docs/connect/ca/vault#vault-acl-policies + # for information on how to configure the Vault policies. + connectCA: + # The address of the Vault server. + address: "" + + # The path to a PKI secrets engine for the root certificate. + # Please see https://www.consul.io/docs/connect/ca/vault#rootpkipath. + rootPKIPath: "" + + # The path to a PKI secrets engine for the generated intermediate certificate. + # Please see https://www.consul.io/docs/connect/ca/vault#intermediatepkipath. + intermediatePKIPath: "" + + # Additional Connect CA configuration in JSON format. + # Please see https://www.consul.io/docs/connect/ca/vault#common-ca-config-options + # for additional configuration options. + additionalConfig: | + {} + # Configures Consul's gossip encryption key. # (see `-encrypt` (https://consul.io/docs/agent/options#_encrypt)). # By default, gossip encryption is not enabled. The gossip encryption key may be set automatically or manually. From bcf121d33b803c49dca99239bbd22ca8214c2f65 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 22 Nov 2021 11:26:00 -0700 Subject: [PATCH 02/11] add unit tests --- .../templates/server-config-configmap.yaml | 9 +- .../test/unit/server-config-configmap.bats | 227 ++++++++++++++++++ 2 files changed, 234 insertions(+), 2 deletions(-) diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index 0b6516c8ce..2b8f07dc6b 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -11,8 +11,9 @@ metadata: heritage: {{ .Release.Service }} release: {{ .Release.Name }} data: + {{- $vaultConnectCAEnabled := and .Values.global.secretsBackend.vault.connectCA.address .Values.global.secretsBackend.vault.connectCA.rootPKIPath .Values.global.secretsBackend.vault.connectCA.intermediatePKIPath -}} + {{- if and .Values.global.secretsBackend.vault.enabled $vaultConnectCAEnabled }} {{- with .Values.global.secretsBackend.vault }} - {{- if .connectCA }} connect-ca-config.json: | { "connect": [ @@ -34,7 +35,11 @@ data: } ] } - {{- end }} + {{- if .connectCA.additionalConfig }} + additional-connect-ca-config.json: | +{{ tpl .connectCA.additionalConfig $ | trimAll "\"" | indent 4 }} + {{- end }} + {{- end }} {{- end }} extra-from-values.json: |- {{ tpl .Values.server.extraConfig . | trimAll "\"" | indent 4 }} diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index 25a08da37c..8245fb215e 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -179,3 +179,230 @@ load _helpers yq -r '.data["acl-config.json"]' | yq -r '.acl.enable_token_replication' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# Vault Connect CA + +@test "server/ConfigMap: doesn't add connect CA config by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled but vault address, root and int PKI paths are not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and vault address is set, but root and int PKI paths are not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and root pki path is set, but vault address and int PKI paths are not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and int path is set, but vault address and root PKI paths are not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and root and int paths are set, but vault address is not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and root path and address are set, but int path is not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and int path and address are set, but root path is not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.intPKIPath=int' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.intPKIPath=int' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: adds connect CA config when vault is enabled and connect CA are configured" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"]' | tee /dev/stderr) + [ "${actual}" = '"{\n \"connect\": [\n {\n \"ca_config\": [\n {\n \"address\": \"example.com\",\n \"intermediate_pki_path\": \"int\",\n \"root_pki_path\": \"root\",\n \"auth_method\": {\n \"type\": \"kubernetes\",\n \"params\": {\n \"role\": \"foo\"\n }\n }\n }\n ],\n \"ca_provider\": \"vault\"\n }\n ]\n}\n"' ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"]' | tee /dev/stderr) + [ "${actual}" = '"{}\n"' ] +} + +@test "server/ConfigMap: can set additional connect CA config" { + cd `chart_dir` + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + --set 'global.secretsBackend.vault.connectCA.additionalConfig="{\"hello\": \"world\"}"' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"]' | tee /dev/stderr) + [ "${actual}" = '"{\"hello\": \"world\"}\n"' ] +} \ No newline at end of file From 274b5f673b21f2ba64693b50e7b43779d1820277 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 22 Nov 2021 11:36:26 -0700 Subject: [PATCH 03/11] include additional ca example --- charts/consul/values.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 7ecf64a413..22ba5819b5 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -173,6 +173,19 @@ global: # Additional Connect CA configuration in JSON format. # Please see https://www.consul.io/docs/connect/ca/vault#common-ca-config-options # for additional configuration options. + # + # Example: + # + # ```yaml + # additionalConfig: | + # { + # "connect": [{ + # "ca_config": [{ + # "leaf_cert_ttl": "36h" + # }] + # }] + # } + # ``` additionalConfig: | {} From 9085c097b20c867b4f462ff54d57b0276994b4c7 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 22 Nov 2021 12:12:10 -0700 Subject: [PATCH 04/11] remove todo; update consul image --- acceptance/tests/vault/vault_test.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 7fbef81f73..003684af6f 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -43,9 +43,8 @@ path "/connect_inter/*" { ` ) -// todo: update -// Installs Vault, bootstraps it with secrets, policies, and Kube Auth Method -// then creates a gossip encryption secret and uses this to bootstrap Consul. +// TestVault installs Vault, bootstraps it with secrets, policies, and Kube Auth Method. +// It then configures Consul to use vault as the backend and checks that it works. func TestVault(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) @@ -102,9 +101,8 @@ func TestVault(t *testing.T) { } _, err = vaultClient.Logical().Write("consul/data/secret/gossip", params) require.NoError(t, err) - consulHelmValues := map[string]string{ - "global.image": "ishustava/consul-dev@sha256:a873b4aa28f7511628281e852daab4c04918872bb86023cefb6197acabb43426", + "global.image": "docker.mirror.hashicorp.services/hashicorpdev/consul:latest", "server.enabled": "true", "server.replicas": "1", @@ -134,8 +132,8 @@ func TestVault(t *testing.T) { consulClient := consulCluster.SetupConsulClient(t, true) keys, err := consulClient.Operator().KeyringList(nil) require.NoError(t, err) - // There should only be one key since there is only 1 dc. - require.Len(t, keys, 1) + // There are two identical keys for LAN and WAN since there is only 1 dc. + require.Len(t, keys, 2) require.Equal(t, 1, keys[0].PrimaryKeys[gossipKey]) // Confirm that the Vault Connect CA has been bootstrapped correctly. From 814a65062e761c9f310f1420934531f3cadf6863 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 22 Nov 2021 12:24:27 -0700 Subject: [PATCH 05/11] fix linter error --- acceptance/tests/vault/vault_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 003684af6f..f16f0827cf 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -138,6 +138,7 @@ func TestVault(t *testing.T) { // Confirm that the Vault Connect CA has been bootstrapped correctly. caConfig, _, err := consulClient.Connect().CAGetConfig(nil) + require.NoError(t, err) require.Equal(t, caConfig.Provider, "vault") // Deploy two services and check that they can talk to each other. From 633300846585317a4ebddd7da64b4d12e840bac3 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 22 Nov 2021 15:35:46 -0700 Subject: [PATCH 06/11] Make sure there are pods in WaitForAllPodsToBeReady --- acceptance/framework/helpers/helpers.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index f173aeea6f..ff7c49ff37 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/gruntwork-io/terratest/modules/helm" "os" "os/signal" "strings" @@ -12,6 +11,8 @@ import ( "testing" "time" + "github.com/gruntwork-io/terratest/modules/helm" + terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" "github.com/gruntwork-io/terratest/modules/random" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" @@ -85,6 +86,7 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) + require.NotEmpty(t, pods.Items) var notReadyPods []string for _, pod := range pods.Items { From f957474486734a0ed580d5c189eb889e69186858 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 22 Nov 2021 15:43:06 -0700 Subject: [PATCH 07/11] Add clarifying comment about connect CA policy --- acceptance/tests/vault/vault_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index f16f0827cf..78fe92ded7 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -20,6 +20,8 @@ path "consul/data/secret/gossip" { capabilities = ["read"] }` + // connectCAPolicy allows Consul to bootstrap all certificates for the service mesh in Vault. + // Adapted from https://www.consul.io/docs/connect/ca/vault#consul-managed-pki-paths. connectCARules = ` path "/sys/mounts" { capabilities = [ "read" ] From 010fd45d5d0f48a17f83f457fc4df5491a79dd57 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 22 Nov 2021 15:38:34 -0700 Subject: [PATCH 08/11] rename rules->policy --- acceptance/framework/helpers/helpers.go | 2 +- acceptance/tests/vault/vault_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index ff7c49ff37..1c40112e7d 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -86,7 +86,7 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) - require.NotEmpty(t, pods.Items) + require.NotEmpty(r, pods.Items) var notReadyPods []string for _, pod := range pods.Items { diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 78fe92ded7..d5069f389a 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -15,14 +15,14 @@ import ( ) const ( - gossipRules = ` + gossipPolicy = ` path "consul/data/secret/gossip" { capabilities = ["read"] }` // connectCAPolicy allows Consul to bootstrap all certificates for the service mesh in Vault. // Adapted from https://www.consul.io/docs/connect/ca/vault#consul-managed-pki-paths. - connectCARules = ` + connectCAPolicy = ` path "/sys/mounts" { capabilities = [ "read" ] } @@ -65,10 +65,10 @@ func TestVault(t *testing.T) { // Create the Vault Policy for the gossip key. logger.Log(t, "Creating policies") - err := vaultClient.Sys().PutPolicy("consul-gossip", gossipRules) + err := vaultClient.Sys().PutPolicy("consul-gossip", gossipPolicy) require.NoError(t, err) - err = vaultClient.Sys().PutPolicy("connect-ca", connectCARules) + err = vaultClient.Sys().PutPolicy("connect-ca", connectCAPolicy) require.NoError(t, err) // Create the Auth Roles for consul-server and consul-client. From 3eb912a00c6a47c27fbb2ca26f7dc370cdc59b6d Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 23 Nov 2021 12:27:12 -0700 Subject: [PATCH 09/11] Update charts/consul/values.yaml --- charts/consul/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 22ba5819b5..2f66531bf4 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -155,7 +155,7 @@ global: # Configuration for the Vault Connect CA provider. # The provider will be configured to use the Vault Kubernetes auth method # and therefore requires the role provided by `consulServerRole` - # needs to have permissions to the root and intermediate PKI paths. + # to have permissions to the root and intermediate PKI paths. # Please see https://www.consul.io/docs/connect/ca/vault#vault-acl-policies # for information on how to configure the Vault policies. connectCA: From cc8f3a2f234fc9a8c15747423b0e34717a8bbbb4 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 23 Nov 2021 15:41:10 -0700 Subject: [PATCH 10/11] Add a clarifying comment about vault roles --- acceptance/tests/vault/vault_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index d5069f389a..94d09f1492 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -72,6 +72,11 @@ func TestVault(t *testing.T) { require.NoError(t, err) // Create the Auth Roles for consul-server and consul-client. + // Auth roles bind policies to Kubernetes service accounts, which + // then enables the Vault agent init container to call 'vault login' + // with the Kubernetes auth method to obtain a Vault token. + // Please see https://www.vaultproject.io/docs/auth/kubernetes#configuration + // for more details. logger.Log(t, "Creating the consul-server and consul-client roles") params := map[string]interface{}{ "bound_service_account_names": consulClientServiceAccountName, From 2d0013ba1348c92c64e53ea6ce2b440eab1ad840 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 23 Nov 2021 16:14:16 -0700 Subject: [PATCH 11/11] Update based on Nitya's review --- charts/consul/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 2f66531bf4..480e46bee5 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -154,7 +154,7 @@ global: # Configuration for the Vault Connect CA provider. # The provider will be configured to use the Vault Kubernetes auth method - # and therefore requires the role provided by `consulServerRole` + # and therefore requires the role provided by `global.secretsBackend.vault.consulServerRole` # to have permissions to the root and intermediate PKI paths. # Please see https://www.consul.io/docs/connect/ca/vault#vault-acl-policies # for information on how to configure the Vault policies.