diff --git a/templates/server-statefulset.yaml b/templates/server-statefulset.yaml index eb0625de..867f3437 100644 --- a/templates/server-statefulset.yaml +++ b/templates/server-statefulset.yaml @@ -1,6 +1,7 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if and .Values.global.federation.enabled (not .Values.global.tls.enabled) }}{{ fail "If global.federation.enabled is true, global.tls.enabled must be true because federation is only supported with TLS enabled" }}{{ end }} {{- if and .Values.global.federation.enabled (not .Values.meshGateway.enabled) }}{{ fail "If global.federation.enabled is true, meshGateway.enabled must be true because mesh gateways are required for federation" }}{{ end }} +{{- if and .Values.server.serverCert.secretName (not .Values.global.tls.caCert.secretName) }}{{ fail "If server.serverCert.secretName is provided, global.tls.caCert must also be provided" }}{{ end }} {{- if .Values.server.disableFsGroupSecurityContext }}{{ fail "server.disableFsGroupSecurityContext has been removed. Please use global.openshift.enabled instead." }}{{ end }} {{- if .Values.server.bootstrapExpect }}{{ if lt (int .Values.server.bootstrapExpect) (int .Values.server.replicas) }}{{ fail "server.bootstrapExpect cannot be less than server.replicas" }}{{ end }}{{ end }} {{- if (and (and .Values.global.tls.enabled .Values.global.tls.httpsOnly) (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics))}}{{ fail "global.metrics.enableAgentMetrics cannot be enabled if TLS (HTTPS only) is enabled" }}{{ end -}} @@ -95,7 +96,11 @@ spec: path: tls.crt - name: consul-server-cert secret: + {{- if .Values.server.serverCert.secretName }} + secretName: {{ .Values.server.serverCert.secretName }} + {{- else }} secretName: {{ template "consul.fullname" . }}-server-cert + {{- end }} {{- end }} {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} - name: consul-license diff --git a/templates/tls-init-cleanup-job.yaml b/templates/tls-init-cleanup-job.yaml index dc0d3aae..77f4dd59 100644 --- a/templates/tls-init-cleanup-job.yaml +++ b/templates/tls-init-cleanup-job.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.global.tls.enabled }} +{{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} # tls-init-cleanup job deletes Kubernetes secrets created by tls-init apiVersion: batch/v1 kind: Job diff --git a/templates/tls-init-cleanup-podsecuritypolicy.yaml b/templates/tls-init-cleanup-podsecuritypolicy.yaml index 7d32091b..d8946a4a 100644 --- a/templates/tls-init-cleanup-podsecuritypolicy.yaml +++ b/templates/tls-init-cleanup-podsecuritypolicy.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if (and .Values.global.tls.enabled .Values.global.enablePodSecurityPolicies) }} +{{- if (and (and .Values.global.tls.enabled .Values.global.enablePodSecurityPolicies) (not .Values.server.serverCert.secretName)) }} apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: diff --git a/templates/tls-init-cleanup-role.yaml b/templates/tls-init-cleanup-role.yaml index d090eb1e..39221449 100644 --- a/templates/tls-init-cleanup-role.yaml +++ b/templates/tls-init-cleanup-role.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.global.tls.enabled }} +{{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: diff --git a/templates/tls-init-cleanup-rolebinding.yaml b/templates/tls-init-cleanup-rolebinding.yaml index ac720b25..c02f4d2e 100644 --- a/templates/tls-init-cleanup-rolebinding.yaml +++ b/templates/tls-init-cleanup-rolebinding.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.global.tls.enabled }} +{{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/templates/tls-init-cleanup-serviceaccount.yaml b/templates/tls-init-cleanup-serviceaccount.yaml index 68c856be..f26d1412 100644 --- a/templates/tls-init-cleanup-serviceaccount.yaml +++ b/templates/tls-init-cleanup-serviceaccount.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.global.tls.enabled }} +{{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/templates/tls-init-job.yaml b/templates/tls-init-job.yaml index c402cb1f..387c0f0b 100644 --- a/templates/tls-init-job.yaml +++ b/templates/tls-init-job.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.global.tls.enabled }} +{{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} # tls-init job generate Consul cluster CA and certificates for the Consul servers # and creates Kubernetes secrets for them. apiVersion: batch/v1 diff --git a/templates/tls-init-podsecuritypolicy.yaml b/templates/tls-init-podsecuritypolicy.yaml index 30854bfc..fda254b0 100644 --- a/templates/tls-init-podsecuritypolicy.yaml +++ b/templates/tls-init-podsecuritypolicy.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if (and .Values.global.tls.enabled .Values.global.enablePodSecurityPolicies) }} +{{- if (and (and .Values.global.tls.enabled .Values.global.enablePodSecurityPolicies) (not .Values.server.serverCert.secretName)) }} apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: diff --git a/templates/tls-init-role.yaml b/templates/tls-init-role.yaml index 64a44eeb..5a27d8b4 100644 --- a/templates/tls-init-role.yaml +++ b/templates/tls-init-role.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.global.tls.enabled }} +{{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: diff --git a/templates/tls-init-rolebinding.yaml b/templates/tls-init-rolebinding.yaml index 3f7ced2c..3ac92e73 100644 --- a/templates/tls-init-rolebinding.yaml +++ b/templates/tls-init-rolebinding.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.global.tls.enabled }} +{{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/templates/tls-init-serviceaccount.yaml b/templates/tls-init-serviceaccount.yaml index 701a2896..e8b2d94a 100644 --- a/templates/tls-init-serviceaccount.yaml +++ b/templates/tls-init-serviceaccount.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.global.tls.enabled }} +{{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/test/unit/server-statefulset.bats b/test/unit/server-statefulset.bats index 87ce61e4..fe06c66c 100755 --- a/test/unit/server-statefulset.bats +++ b/test/unit/server-statefulset.bats @@ -160,6 +160,46 @@ load _helpers [ "${actual}" = "foo" ] } +#-------------------------------------------------------------------- +# serverCert + +@test "server/StatefulSet: consul-server-cert uses default cert when serverCert.secretName not set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.tls.enabled=true' \ + --set 'server.serverCert.secretName=null' \ + . | tee /dev/stderr ) + + local actual=$(echo "$object" | + yq -r '.spec.template.spec.volumes[2].secret.secretName' | tee /dev/stderr) + [ "${actual}" = "RELEASE-NAME-consul-server-cert" ] +} + +@test "server/StatefulSet: consul-server-cert uses serverCert.secretName when serverCert (and caCert) are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=ca-cert' \ + --set 'server.serverCert.secretName=server-cert' \ + . | tee /dev/stderr ) + + local actual=$(echo "$object" | + yq -r '.spec.template.spec.volumes[2].secret.secretName' | tee /dev/stderr) + [ "${actual}" = "server-cert" ] +} + +@test "server/StatefulSet: when server.serverCert.secretName!=null and global.tls.caCert.secretName=null, fail" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.tls.enabled=true' \ + --set 'server.serverCert.secretName=server-cert' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "If server.serverCert.secretName is provided, global.tls.caCert must also be provided" ]] +} #-------------------------------------------------------------------- # exposeGossipAndRPCPorts diff --git a/test/unit/tls-init-cleanup-job.bats b/test/unit/tls-init-cleanup-job.bats index eaa28175..d75abf7d 100644 --- a/test/unit/tls-init-cleanup-job.bats +++ b/test/unit/tls-init-cleanup-job.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInitCleanup/Job: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-job.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInitCleanup/Job: disabled with global.enabled=false" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-cleanup-podsecuritypolicy.bats b/test/unit/tls-init-cleanup-podsecuritypolicy.bats index 0cb844a8..34d747ae 100644 --- a/test/unit/tls-init-cleanup-podsecuritypolicy.bats +++ b/test/unit/tls-init-cleanup-podsecuritypolicy.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInitCleanup/PodSecurityPolicy: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-podsecuritypolicy.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInitCleanup/PodSecurityPolicy: disabled by default with TLS enabled" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-cleanup-role.bats b/test/unit/tls-init-cleanup-role.bats index 8974db6d..ad3ca7bb 100644 --- a/test/unit/tls-init-cleanup-role.bats +++ b/test/unit/tls-init-cleanup-role.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInitCleanup/Role: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-role.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInitCleanup/Role: disabled with global.enabled=false" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-cleanup-rolebinding.bats b/test/unit/tls-init-cleanup-rolebinding.bats index 5c5190ab..5fd3632e 100644 --- a/test/unit/tls-init-cleanup-rolebinding.bats +++ b/test/unit/tls-init-cleanup-rolebinding.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInitCleanup/RoleBinding: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-rolebinding.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInitCleanup/RoleBinding: disabled with global.enabled=false" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-cleanup-serviceaccount.bats b/test/unit/tls-init-cleanup-serviceaccount.bats index 35c0e039..d2a89e4e 100644 --- a/test/unit/tls-init-cleanup-serviceaccount.bats +++ b/test/unit/tls-init-cleanup-serviceaccount.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInitCleanup/ServiceAccount: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-serviceaccount.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInitCleanup/ServiceAccount: disabled with global.enabled=false" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-job.bats b/test/unit/tls-init-job.bats index 9e149abf..9c751fa3 100644 --- a/test/unit/tls-init-job.bats +++ b/test/unit/tls-init-job.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInit/Job: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-job.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInit/Job: disabled with global.enabled=false" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-podsecuritypolicy.bats b/test/unit/tls-init-podsecuritypolicy.bats index c439d68f..5ec0729d 100644 --- a/test/unit/tls-init-podsecuritypolicy.bats +++ b/test/unit/tls-init-podsecuritypolicy.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInit/PodSecurityPolicy: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-podsecuritypolicy.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInit/PodSecurityPolicy: disabled by default with TLS enabled" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-role.bats b/test/unit/tls-init-role.bats index 1b6bf297..fe601be9 100644 --- a/test/unit/tls-init-role.bats +++ b/test/unit/tls-init-role.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInit/Role: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-role.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInit/Role: disabled with global.enabled=false" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-rolebinding.bats b/test/unit/tls-init-rolebinding.bats index a63c01a9..cac2a97f 100644 --- a/test/unit/tls-init-rolebinding.bats +++ b/test/unit/tls-init-rolebinding.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInit/RoleBinding: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-rolebinding.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInit/RoleBinding: disabled with global.enabled=false" { cd `chart_dir` assert_empty helm template \ diff --git a/test/unit/tls-init-serviceaccount.bats b/test/unit/tls-init-serviceaccount.bats index a49d8efc..9eb3560b 100644 --- a/test/unit/tls-init-serviceaccount.bats +++ b/test/unit/tls-init-serviceaccount.bats @@ -9,6 +9,17 @@ load _helpers . } +@test "tlsInit/ServiceAccount: disabled with global.tls.enabled=true and server.serverCert.secretName!=null" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-serviceaccount.yaml \ + --set 'global.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'server.serverCert.secretName=test' \ + . +} + @test "tlsInit/ServiceAccount: disabled with global.enabled=false" { cd `chart_dir` assert_empty helm template \ diff --git a/values.yaml b/values.yaml index 3c73dbbe..c49ff371 100644 --- a/values.yaml +++ b/values.yaml @@ -345,6 +345,34 @@ server: # Manages license autoload. Required in Consul 1.10.0+, 1.9.7+ and 1.8.12+. enableLicenseAutoload: true + # A Kubernetes secret containing a certificate & key for the server agents to use + # for TLS communication within the Consul cluster. Cert needs to be provided with + # additional DNS name SANs so that it will work within the Kubernetes cluster: + # + # ```bash + # consul tls cert create -server -days=730 -domain=consul -ca=consul-agent-ca.pem \ + # -key=consul-agent-ca-key.pem -dc={{datacenter}} \ + # -additional-dnsname="{{fullname}}-server" \ + # -additional-dnsname="*.{{fullname}}-server" \ + # -additional-dnsname="*.{{fullname}}-server.{{namespace}}" \ + # -additional-dnsname="*.{{fullname}}-server.{{namespace}}.svc" \ + # -additional-dnsname="*.server.{{datacenter}}.{{domain}}" \ + # -additional-dnsname="server.{{datacenter}}.{{domain}}" + # ``` + # + # If you have generated the + # server-cert yourself with the consul CLI, you could use the following command + # to create the secret in Kubernetes: + # + # ```bash + # kubectl create secret generic consul-server-cert \ + # --from-file='tls.crt=./dc1-server-consul-0.pem' + # --from-file='tls.key=./dc1-server-consul-0-key.pem' + # ``` + serverCert: + # The name of the Kubernetes secret. + secretName: null + # Exposes the servers' gossip and RPC ports as hostPorts. To enable a client # agent outside of the k8s cluster to join the datacenter, you would need to # enable `server.exposeGossipAndRPCPorts`, `client.exposeGossipPorts`, and @@ -725,7 +753,7 @@ client: # required for Connect. grpc: true - # nodeMeta specifies an arbitrary metadata key/value pair to associate with the node + # nodeMeta specifies an arbitrary metadata key/value pair to associate with the node # (see https://www.consul.io/docs/agent/options.html#_node_meta) nodeMeta: pod-name: ${HOSTNAME}