Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically Generate and Use Gossip Encryption Key #738

Merged
merged 60 commits into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
3f046cf
Add global.gossipEncryption.autogenerate to values.yaml
Sep 9, 2021
3691852
Add description of key autogen
Sep 9, 2021
dafd4b2
Add initial autogen-encryption-job yaml
Sep 9, 2021
34c6b1e
Fix run condition on autogen
Sep 9, 2021
bce6ed7
autogen is false by default
Sep 14, 2021
f1d4bcc
Set secretName/Key correctly, flesh out curling k8s a bit
Sep 14, 2021
7ac9c93
Add some basic bats tests
Sep 14, 2021
c864232
Add tests for user set values for secretName and secretKey
Sep 14, 2021
78b6af9
Beef up comment for gossip encryption
Sep 15, 2021
27d45ee
Add notes
Sep 16, 2021
e51616f
Update values.yaml to include autoGenerate
Sep 16, 2021
7133cbe
Add gossip-encryption-autogen-job.yaml
Sep 17, 2021
0bcb7bf
Port over autogen-encryption-job to gossip-encryption-autogen-job
Sep 17, 2021
7392443
Rename autogen-encryption-job.bats to gossip-encryption-autogen-job.bats
Sep 17, 2021
886c061
Remove change made to statefulset
Sep 20, 2021
fbb9adf
Add check that secretName and secretKey are not set
Sep 20, 2021
f77814d
Fix test failures
Sep 20, 2021
2a6ea41
Set GOSSIP_KEY properly in server statefulset
Sep 20, 2021
40e7a4d
Remove setting secretName and secretKey for autogen
Sep 20, 2021
0a4c0d6
Check if secret exists via 200 resp
Sep 20, 2021
424dba0
Add gossip autogen to client daemonset
Sep 21, 2021
623d477
Send the key to secrets
Sep 22, 2021
ccc94c9
Base64 encrypt consul key
Sep 22, 2021
23421de
Add podsecuritypolicy, role, rolebinding, and SA
Sep 22, 2021
03c5994
Rename -gossip-encryption-autogen to -gossip-encryption-autogenerate
Sep 22, 2021
29bca86
Rename *-autogen-* to *-autogeneration-*
Sep 23, 2021
b0643c0
Remove text about respecting user set secretName and secretKey for au…
Sep 23, 2021
3cd99af
Rename gossip-encryption-autogen to gossip-encryption-autogeneration
Sep 23, 2021
ab1181c
Add some great tests!
Sep 23, 2021
a65551c
Update changelog
Sep 23, 2021
2b2fd1d
Fix filename reference in job bats file
Sep 24, 2021
7bf6e51
Update charts/consul/templates/gossip-encryption-autogeneration-job.yaml
Sep 24, 2021
003096a
Update charts/consul/test/unit/gossip-encryption-autogeneration-job.bats
Sep 24, 2021
ad03ca6
Don't do the pre-check, but don't replace the current secret
Sep 24, 2021
cc90ccb
Update charts/consul/test/unit/gossip-encryption-autogeneration-job.bats
Sep 24, 2021
3d0dcd8
Only give role create and get perms
Sep 24, 2021
33d24aa
Update charts/consul/test/unit/gossip-encryption-autogeneration-podse…
Sep 24, 2021
ab54f29
Update charts/consul/values.yaml
Sep 24, 2021
0849dc2
Return kubectl command to what it was
Sep 24, 2021
d222cc3
Test that GOSSIP_KEY gets passed in on the encrypt flag
Sep 24, 2021
6a7708b
Autogen job does not run as root
Sep 24, 2021
5e634cc
Add check that gossip encryption is getting set
Sep 29, 2021
b4a1ea4
Fix test for gossip encryption in acceptance tests
Sep 30, 2021
b5d77c1
Merge branch 'main' into autogen-gossip
Sep 30, 2021
1b12bc6
Update charts/consul/test/acceptance/tests/basic/basic_test.go
Sep 30, 2021
423f958
Rename s/autogeneration/autogenerate/ for gossip-encryption-autogener…
Sep 30, 2021
b611841
Use correct filename in bats
Sep 30, 2021
9192f9e
Rename podsecuritypolicy test to be correct
Sep 30, 2021
7fcb757
Change v1 to metaV1
Sep 30, 2021
3e6e476
Update charts/consul/test/acceptance/tests/basic/basic_test.go
Sep 30, 2021
7cd2182
Test the other keyring value
Sep 30, 2021
cbaefe6
Merge branch 'autogen-gossip' of https://github.com/hashicorp/consul-…
Sep 30, 2021
5656890
Remove arbitrary test
Sep 30, 2021
58163fc
Remove document separator
Sep 30, 2021
a0a6cec
Remove temp dir from job
Sep 30, 2021
f6fcaa5
Remove get perm from autogenerate role
Sep 30, 2021
4627225
Add -encrypt flag test for client-daemonset
Oct 1, 2021
2f40add
Change autogen to a feature in the CHANGELOG
Oct 1, 2021
487288f
Update comment on values.yaml
Oct 1, 2021
b879bba
Update charts/consul/test/acceptance/tests/basic/basic_test.go
Oct 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ IMPROVEMENTS:
* Control Plane
* Upgrade Docker image Alpine version from 3.13 to 3.14. [[GH-737](https://github.com/hashicorp/consul-k8s/pull/737)]
* Helm Chart
* Add automatic generation of gossip encryption with `global.gossipEncryption.autoGenerate=true` [[GH-738](https://github.com/hashicorp/consul-k8s/pull/738)]
t-eckert marked this conversation as resolved.
Show resolved Hide resolved
* Enable adding extra containers to server and client Pods. [[GH-749](https://github.com/hashicorp/consul-k8s/pull/749)]

## 0.34.1 (September 17, 2021)
Expand Down
9 changes: 7 additions & 2 deletions charts/consul/templates/client-daemonset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,17 @@ spec:
fieldPath: status.podIP
- name: CONSUL_DISABLE_PERM_MGMT
value: "true"
{{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }}
{{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }}
- name: GOSSIP_KEY
valueFrom:
secretKeyRef:
{{- if .Values.global.gossipEncryption.autoGenerate }}
name: {{ template "consul.fullname" . }}-gossip-encryption-key
key: key
{{- else if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }}
name: {{ .Values.global.gossipEncryption.secretName }}
key: {{ .Values.global.gossipEncryption.secretKey }}
{{- end }}
{{- end }}
{{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload (not .Values.global.acls.manageSystemACLs)) }}
- name: CONSUL_LICENSE_PATH
Expand Down Expand Up @@ -252,7 +257,7 @@ spec:
{{- end }}
-datacenter={{ .Values.global.datacenter }} \
-data-dir=/consul/data \
{{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }}
{{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }}
-encrypt="${GOSSIP_KEY}" \
{{- end }}
{{- if .Values.client.join }}
Expand Down
73 changes: 73 additions & 0 deletions charts/consul/templates/gossip-encryption-autogenerate-job.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{{- if .Values.global.gossipEncryption.autoGenerate }}
{{- if (or .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }}
{{ fail "If global.gossipEncryption.autoGenerate is true, global.gossipEncryption.secretName and global.gossipEncryption.secretKey must not be set." }}
{{ end }}
---
# automatically generate encryption key for gossip protocol and save it in Kubernetes secret
apiVersion: batch/v1
kind: Job
metadata:
name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation
spec:
template:
metadata:
name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
release: {{ .Release.Name }}
component: gossip-encryption-autogeneneration
annotations:
"consul.hashicorp.com/connect-inject": "false"
spec:
restartPolicy: Never
serviceAccountName: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
securityContext:
runAsNonRoot: true
runAsGroup: 1000
runAsUser: 100
fsGroup: 1000
containers:
- name: gossip-encryption-autogen
image: "{{ .Values.global.image }}"
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
workingDir: /tmp
# We're using POST requests below to create secrets via Kubernetes API.
# Note that in the subsequent runs of the job, POST requests will
# return a 409 because these secrets would already exist;
# we are ignoring these response codes.
command:
- "/bin/sh"
- "-ec"
- |
secretName={{ template "consul.fullname" . }}-gossip-encryption-key
secretKey=key
keyValue=$(consul keygen | base64)
curl -s -X POST --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
t-eckert marked this conversation as resolved.
Show resolved Hide resolved
https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}/api/v1/namespaces/${NAMESPACE}/secrets \
-H "Authorization: Bearer $( cat /var/run/secrets/kubernetes.io/serviceaccount/token )" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d "{ \"kind\": \"Secret\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"${secretName}\", \"namespace\": \"${NAMESPACE}\" }, \"type\": \"Opaque\", \"data\": { \"${secretKey}\": \"${keyValue}\" }}" > /dev/null
resources:
requests:
memory: "50Mi"
cpu: "50m"
limits:
memory: "50Mi"
cpu: "50m"
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{{- if .Values.global.gossipEncryption.autoGenerate }}
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-delete-policy": before-hook-creation
spec:
privileged: false
# Required to prevent escalations to root.
allowPrivilegeEscalation: false
# This is redundant with non-root + disallow privilege escalation,
# but we can provide it for defense in depth.
requiredDropCapabilities:
- ALL
# Allow core volume types.
volumes:
- 'secret'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
readOnlyRootFilesystem: false
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{{- if .Values.global.gossipEncryption.autoGenerate }}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-delete-policy": before-hook-creation
rules:
- apiGroups: [""]
resources:
- secrets
verbs:
- create
- get
{{- if .Values.global.enablePodSecurityPolicies }}
- apiGroups: ["policy"]
resources:
- podsecuritypolicies
verbs:
- use
resourceNames:
- {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{- if .Values.global.gossipEncryption.autoGenerate }}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-delete-policy": before-hook-creation
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
subjects:
- kind: ServiceAccount
name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{{- if .Values.global.gossipEncryption.autoGenerate }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-delete-policy": before-hook-creation
{{- with .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- range . }}
- name: {{ .name }}
{{- end }}
{{- end }}
{{- end }}
9 changes: 7 additions & 2 deletions charts/consul/templates/server-statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,17 @@ spec:
fieldPath: metadata.namespace
- name: CONSUL_DISABLE_PERM_MGMT
value: "true"
{{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }}
{{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }}
- name: GOSSIP_KEY
valueFrom:
secretKeyRef:
{{- if .Values.global.gossipEncryption.autoGenerate }}
name: {{ template "consul.fullname" . }}-gossip-encryption-key
key: key
{{- else if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }}
name: {{ .Values.global.gossipEncryption.secretName }}
key: {{ .Values.global.gossipEncryption.secretKey }}
{{- end }}
{{- end }}
{{- if .Values.global.tls.enabled }}
- name: CONSUL_HTTP_ADDR
Expand Down Expand Up @@ -223,7 +228,7 @@ spec:
-datacenter={{ .Values.global.datacenter }} \
-data-dir=/consul/data \
-domain={{ .Values.global.domain }} \
{{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }}
{{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }}
-encrypt="${GOSSIP_KEY}" \
{{- end }}
{{- if .Values.server.connect }}
Expand Down
27 changes: 24 additions & 3 deletions charts/consul/test/acceptance/tests/basic/basic_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package basic

import (
"context"
"fmt"
"strconv"
"strings"
"testing"

"github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul"
"github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers"
"github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger"
"github.com/hashicorp/consul/api"
"github.com/stretchr/testify/require"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
t-eckert marked this conversation as resolved.
Show resolved Hide resolved
)

// Test that the basic installation, i.e. just
Expand Down Expand Up @@ -39,9 +42,10 @@ func TestBasicInstallation(t *testing.T) {
t.Run(name, func(t *testing.T) {
releaseName := helpers.RandomName()
helmValues := map[string]string{
"global.acls.manageSystemACLs": strconv.FormatBool(c.secure),
"global.tls.enabled": strconv.FormatBool(c.secure),
"global.tls.enableAutoEncrypt": strconv.FormatBool(c.autoEncrypt),
"global.acls.manageSystemACLs": strconv.FormatBool(c.secure),
"global.tls.enabled": strconv.FormatBool(c.secure),
"global.gossipEncryption.autoGenerate": strconv.FormatBool(c.secure),
"global.tls.enableAutoEncrypt": strconv.FormatBool(c.autoEncrypt),
}
consulCluster := consul.NewHelmCluster(t, helmValues, suite.Environment().DefaultContext(t), suite.Config(), releaseName)

Expand All @@ -63,6 +67,23 @@ func TestBasicInstallation(t *testing.T) {
kv, _, err := client.KV().Get(randomKey, nil)
require.NoError(t, err)
require.Equal(t, kv.Value, randomValue)

// Check that autogenerated gossip encryption key is being used
if c.secure {
secretName := fmt.Sprintf("%s-consul-gossip-encryption-key", releaseName)
secretKey := "key"

keyring, err := client.Operator().KeyringList(nil)
require.NoError(t, err)

testContext := suite.Environment().DefaultContext(t)
secret, err := testContext.KubernetesClient(t).CoreV1().Secrets(testContext.KubectlOptions(t).Namespace).Get(context.Background(), secretName, v1.GetOptions{})
require.NoError(t, err)
gossipEncryptionKey := strings.TrimSpace(string(secret.Data[secretKey]))

require.Len(t, keyring, 2)
require.Contains(t, keyring[0].Keys, gossipEncryptionKey)
t-eckert marked this conversation as resolved.
Show resolved Hide resolved
t-eckert marked this conversation as resolved.
Show resolved Hide resolved
}
})
}
}
20 changes: 20 additions & 0 deletions charts/consul/test/unit/client-daemonset.bats
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,26 @@ load _helpers
[ "${actual}" = "" ]
}

@test "client/DaemonSet: gossip encryption autogeneration properly sets secretName and secretKey" {
cd `chart_dir`
local actual=$(helm template \
-s templates/client-daemonset.yaml \
--set 'global.gossipEncryption.autoGenerate=true' \
. | tee /dev/stderr |
yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY") | .valueFrom.secretKeyRef | [.name=="RELEASE-NAME-consul-gossip-encryption-key", .key="key"] | all' | tee /dev/stderr)
[ "${actual}" = "true" ]
t-eckert marked this conversation as resolved.
Show resolved Hide resolved
}

@test "client/DaemonSet: gossip encryption key is passed in via the -encrypt flag" {
cd `chart_dir`
local actual=$(helm template \
-s templates/client-daemonset.yaml \
--set 'global.gossipEncryption.autoGenerate=true' \
. | tee /dev/stderr |
yq '.spec.template.spec.containers[] | select(.name=="consul") | .command | any(contains("-encrypt=\"${GOSSIP_KEY}\""))' | tee /dev/stderr)
[ "${actual}" = "true" ]
}

t-eckert marked this conversation as resolved.
Show resolved Hide resolved
@test "client/DaemonSet: gossip encryption disabled in client DaemonSet when secretName is missing" {
cd `chart_dir`
local actual=$(helm template \
Expand Down
Loading