From 9d7156ddcd0ef9e059413bef124fb94801fb0e1e Mon Sep 17 00:00:00 2001 From: Phil Gebhardt Date: Fri, 30 Jan 2026 18:53:56 -0800 Subject: [PATCH] tls: add client identity configuration for mTLS ## Background An upcoming release of Gremlin and Chao will support configuring a client identity for TLS, facilitating mutual TLS (mTLS) ## Change * Expose `chao.tls.identity` and `gremlin.tls.identity` objects for configuring a client identity certificate and private key * When enabled, add generation for chao and gremlin secrets to hold certificate and private key data # Test - [x] unit tests for `remoteSecret` - [x] unit tests for `createSecret` - [x] unit tests for `existingSecret` - [x] unit tests for multiple configurations --- gremlin-integrations/Chart.yaml | 4 +- gremlin-integrations/templates/_helpers.tpl | 85 +++++++ .../templates/deployment.yaml | 9 + .../secret-gremlin-tls-identity.yaml | 18 ++ .../tests/deployment_tls_test.yaml | 208 +++++++++++++++++ .../secret_gremlin_tls_identity_test.yaml | 101 +++++++++ gremlin-integrations/values.yaml | 53 +++++ gremlin/Chart.yaml | 4 +- gremlin/templates/_helpers.tpl | 170 ++++++++++++++ gremlin/templates/chao-deployment.yaml | 9 + gremlin/templates/daemonset.yaml | 9 + .../templates/secret-chao-tls-identity.yaml | 18 ++ .../secret-gremlin-tls-identity.yaml | 18 ++ gremlin/tests/chao_deployment_test.yaml | 209 ++++++++++++++++++ gremlin/tests/daemonset_test.yaml | 204 +++++++++++++++++ .../tests/secret_chao_tls_identity_test.yaml | 101 +++++++++ .../secret_gremlin_tls_identity_test.yaml | 101 +++++++++ gremlin/values.yaml | 107 +++++++++ 18 files changed, 1424 insertions(+), 4 deletions(-) create mode 100644 gremlin-integrations/templates/secret-gremlin-tls-identity.yaml create mode 100644 gremlin-integrations/tests/deployment_tls_test.yaml create mode 100644 gremlin-integrations/tests/secret_gremlin_tls_identity_test.yaml create mode 100644 gremlin/templates/secret-chao-tls-identity.yaml create mode 100644 gremlin/templates/secret-gremlin-tls-identity.yaml create mode 100644 gremlin/tests/secret_chao_tls_identity_test.yaml create mode 100644 gremlin/tests/secret_gremlin_tls_identity_test.yaml diff --git a/gremlin-integrations/Chart.yaml b/gremlin-integrations/Chart.yaml index a3b0dac..c4239cd 100644 --- a/gremlin-integrations/Chart.yaml +++ b/gremlin-integrations/Chart.yaml @@ -15,13 +15,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.2 +version: 0.2.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.0.2" +appVersion: "0.4.0" home: https://www.gremlin.com maintainers: - name: Gremlin Development diff --git a/gremlin-integrations/templates/_helpers.tpl b/gremlin-integrations/templates/_helpers.tpl index dc13a32..7598a85 100644 --- a/gremlin-integrations/templates/_helpers.tpl +++ b/gremlin-integrations/templates/_helpers.tpl @@ -113,3 +113,88 @@ Create chart name and version as used by the chart label. {{- define "gremlin.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- end -}} + +{{/* +gremlinTlsIdentityValidate fails if more than one identity strategy is fully configured for gremlin +*/}} +{{- define "gremlinTlsIdentityValidate" -}} +{{- $remoteSecret := and .Values.gremlin.tls.identity.remoteSecret.cert .Values.gremlin.tls.identity.remoteSecret.key -}} +{{- $createSecret := and .Values.gremlin.tls.identity.createSecret.name .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key -}} +{{- $existingSecret := and .Values.gremlin.tls.identity.existingSecret.name .Values.gremlin.tls.identity.existingSecret.cert .Values.gremlin.tls.identity.existingSecret.key -}} +{{- $count := 0 -}} +{{- if $remoteSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if $createSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if $existingSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if gt (int $count) 1 -}} +{{- fail "gremlin.tls.identity: only one of remoteSecret, createSecret, or existingSecret should be fully configured" -}} +{{- end -}} +{{- end -}} + +{{/* +gremlinTlsIdentityEnv returns the environment variables needed to configure TLS client identity +When remoteSecret is configured + - sets GREMLIN_TLS_IDENTITY_CERTIFICATE and GREMLIN_TLS_IDENTITY_PRIVATE_KEY to their respective `cert` and `key` values +When createSecret or existingSecret are configured + - sets GREMLIN_TLS_IDENTITY_CERTIFICATE and GREMLIN_TLS_IDENTITY_PRIVATE_KEY to their respective file paths, mounted by gremlinTlsIdentityVolumeMounts +*/}} +{{- define "gremlinTlsIdentityEnv" -}} +{{- if .Values.gremlin.tls.identity.enabled -}} +{{- include "gremlinTlsIdentityValidate" . -}} +{{- if and .Values.gremlin.tls.identity.remoteSecret.cert .Values.gremlin.tls.identity.remoteSecret.key -}} +- name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: {{ .Values.gremlin.tls.identity.remoteSecret.cert | quote }} +- name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: {{ .Values.gremlin.tls.identity.remoteSecret.key | quote }} +{{- else if and .Values.gremlin.tls.identity.createSecret.name .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key -}} +- name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/cert +- name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/key +{{- else if .Values.gremlin.tls.identity.existingSecret.name -}} +- name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/{{ .Values.gremlin.tls.identity.existingSecret.cert }} +- name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/{{ .Values.gremlin.tls.identity.existingSecret.key }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +gremlinTlsIdentityVolumeMounts returns the mounts needed to access TLS client identity files +When createSecret or existingSecret are configured + - mounts to designated secret files under /var/lib/gremlin/tls/identity +*/}} +{{- define "gremlinTlsIdentityVolumeMounts" -}} +{{- if .Values.gremlin.tls.identity.enabled -}} +{{- include "gremlinTlsIdentityValidate" . -}} +{{- if and .Values.gremlin.tls.identity.createSecret.name .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key -}} +- name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true +{{- else if .Values.gremlin.tls.identity.existingSecret.name -}} +- name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +gremlinTlsIdentityVolumes returns the volumes that contain TLS client identity files +When createSecret or existingSecret are configured + - defines the volume associated with the designated secret +*/}} +{{- define "gremlinTlsIdentityVolumes" -}} +{{- if .Values.gremlin.tls.identity.enabled -}} +{{- include "gremlinTlsIdentityValidate" . -}} +{{- if and .Values.gremlin.tls.identity.createSecret.name .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key -}} +- name: gremlin-tls-identity + secret: + secretName: {{ .Values.gremlin.tls.identity.createSecret.name }} +{{- else if .Values.gremlin.tls.identity.existingSecret.name -}} +- name: gremlin-tls-identity + secret: + secretName: {{ .Values.gremlin.tls.identity.existingSecret.name }} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/gremlin-integrations/templates/deployment.yaml b/gremlin-integrations/templates/deployment.yaml index 79e2492..7dad757 100644 --- a/gremlin-integrations/templates/deployment.yaml +++ b/gremlin-integrations/templates/deployment.yaml @@ -86,6 +86,9 @@ spec: - name: SSL_CERT_DIR value: {{ .Values.ssl.certDir }} {{- end }} + {{- if include "gremlinTlsIdentityEnv" . }} + {{- include "gremlinTlsIdentityEnv" . | nindent 12 }} + {{- end }} {{- with .Values.gremlin.extraEnv }} {{- toYaml . | nindent 12 }} {{- end }} @@ -100,6 +103,9 @@ spec: mountPath: /etc/gremlin/ssl readOnly: true {{- end }} + {{- if include "gremlinTlsIdentityVolumeMounts" . }} + {{- include "gremlinTlsIdentityVolumeMounts" . | nindent 12 }} + {{- end }} volumes: {{- if (eq (include "gremlin.secretType" .) "certificate") }} - name: gremlin-cert @@ -111,6 +117,9 @@ spec: secret: secretName: integrations-ssl-cert-file {{ end }} + {{- if include "gremlinTlsIdentityVolumes" . }} + {{- include "gremlinTlsIdentityVolumes" . | nindent 8 }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/gremlin-integrations/templates/secret-gremlin-tls-identity.yaml b/gremlin-integrations/templates/secret-gremlin-tls-identity.yaml new file mode 100644 index 0000000..edb1021 --- /dev/null +++ b/gremlin-integrations/templates/secret-gremlin-tls-identity.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.gremlin.tls.identity.enabled .Values.gremlin.tls.identity.createSecret.name (and .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.gremlin.tls.identity.createSecret.name }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "gremlin.name" . }} + helm.sh/chart: {{ include "gremlin.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + version: v1 +type: kubernetes.io/Opaque +data: + cert: {{ .Values.gremlin.tls.identity.createSecret.cert | toString | b64enc }} + key: {{ .Values.gremlin.tls.identity.createSecret.key | toString | b64enc }} +{{- end }} diff --git a/gremlin-integrations/tests/deployment_tls_test.yaml b/gremlin-integrations/tests/deployment_tls_test.yaml new file mode 100644 index 0000000..3563b6c --- /dev/null +++ b/gremlin-integrations/tests/deployment_tls_test.yaml @@ -0,0 +1,208 @@ +suite: "Gremlin Integrations Deployment TLS Identity Tests" +templates: + - "templates/deployment.yaml" + +tests: + # gremlin.tls.identity tests + + - it: should not include TLS identity env vars when tls identity is not enabled + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + any: true + - notContains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + any: true + + - it: should set TLS identity env vars to ARN values when remoteSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + gremlin.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + + - it: should not mount TLS identity volumes when remoteSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + gremlin.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true + - notContains: + path: spec.template.spec.volumes + content: + name: gremlin-tls-identity + any: true + + - it: should set TLS identity env vars to file paths when createSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.createSecret.name: gremlin-tls-identity + gremlin.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + gremlin.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/cert + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/key + + - it: should mount TLS identity volume when createSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.createSecret.name: gremlin-tls-identity + gremlin.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + gremlin.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: gremlin-tls-identity + secret: + secretName: gremlin-tls-identity + + - it: should set TLS identity env vars to file paths when existingSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.existingSecret.name: my-existing-secret + gremlin.tls.identity.existingSecret.cert: tls.crt + gremlin.tls.identity.existingSecret.key: tls.key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/tls.crt + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/tls.key + + - it: should set TLS identity env vars to file paths when existingSecret is customized + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.existingSecret.name: my-existing-secret + gremlin.tls.identity.existingSecret.cert: custom.crt + gremlin.tls.identity.existingSecret.key: custom.key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/custom.crt + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/custom.key + + - it: should mount TLS identity volume from existingSecret when configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.existingSecret.name: my-existing-secret + gremlin.tls.identity.existingSecret.cert: tls.crt + gremlin.tls.identity.existingSecret.key: tls.key + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: gremlin-tls-identity + secret: + secretName: my-existing-secret + + - it: should fail when multiple TLS identity strategies are configured for gremlin + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + gremlin.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + gremlin.tls.identity.createSecret.name: gremlin-tls-identity + gremlin.tls.identity.createSecret.cert: "dummy-cert" + gremlin.tls.identity.createSecret.key: "dummy-key" + asserts: + - failedTemplate: + errorMessage: "gremlin.tls.identity: only one of remoteSecret, createSecret, or existingSecret should be fully configured" diff --git a/gremlin-integrations/tests/secret_gremlin_tls_identity_test.yaml b/gremlin-integrations/tests/secret_gremlin_tls_identity_test.yaml new file mode 100644 index 0000000..220f741 --- /dev/null +++ b/gremlin-integrations/tests/secret_gremlin_tls_identity_test.yaml @@ -0,0 +1,101 @@ +suite: Test gremlin TLS identity secret +templates: + - secret-gremlin-tls-identity.yaml +release: + name: my-release + namespace: my-namespace + revision: 1 + upgrade: true +tests: + - it: should not create a secret when tls identity is not enabled + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when enabled but no cert/key provided + set: + gremlin.tls.identity.enabled: true + asserts: + - hasDocuments: + count: 0 + + - it: should create a secret when createSecret strategy is fully configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.createSecret.name: gremlin-tls-identity + gremlin.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + gremlin.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - isKind: + of: Secret + - equal: + path: metadata.name + value: gremlin-tls-identity + - equal: + path: metadata.namespace + value: my-namespace + - equal: + path: type + value: kubernetes.io/Opaque + + - it: should use a custom secret name when specified + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.createSecret.name: my-custom-tls-secret + gremlin.tls.identity.createSecret.cert: "dummy-cert" + gremlin.tls.identity.createSecret.key: "dummy-key" + asserts: + - equal: + path: metadata.name + value: my-custom-tls-secret + + - it: should not create a secret when remoteSecret strategy is used + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + gremlin.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when identity is disabled even with createSecret values + set: + gremlin.tls.identity.enabled: false + gremlin.tls.identity.createSecret.name: my-custom-tls-secret + gremlin.tls.identity.createSecret.cert: "dummy-cert" + gremlin.tls.identity.createSecret.key: "dummy-key" + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when existingSecret strategy is used + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.existingSecret.name: my-existing-secret + asserts: + - hasDocuments: + count: 0 diff --git a/gremlin-integrations/values.yaml b/gremlin-integrations/values.yaml index 9ce7463..0201f9f 100644 --- a/gremlin-integrations/values.yaml +++ b/gremlin-integrations/values.yaml @@ -79,6 +79,59 @@ gremlin: # api.gremlin.com. This value is ignored when blank or absent. url: + # gremlin.tls - + # A collection of TLS configurations specific to the Gremlin Integrations Deployment. + tls: + # gremlin.tls.identity - + # Configuration items for configuring the TLS identity of the Gremlin HTTP client for mTLS. + # Identity values are made up of + # - `cert` portion, containing the leaf certificate for the client (plus any intermediate certificates) + # - `key` portion, containing the private key for the client + # + # These values can be supplied in three different strategies: + # - `remoteSecret`: a collection of ARN values for AWS Secrets Manager + # - `createSecret`: content supplied directly to this chart for which a new Kubernetes secret will be created + # - `existingSecret`: a reference to an existing Kubernetes secret (e.g. created from cert-manager) + # + # Only one of the above strategies should be fully configured. A strategy is not used until all of its fields are configured. + identity: + # gremlin.tls.identity.enabled - + # Decides whether the Gremlin Integrations Deployment should be configured for a TLS identity + enabled: false + # gremlin.tls.identity.remoteSecret - + # The remoteSecret strategy accepts `cert` and `key` strings in the form of ARN values for AWS Secrets Manager + remoteSecret: + # gremlin.tls.identity.remoteSecret.cert - + # The ARN for the identity certificate + cert: "" + # gremlin.tls.identity.remoteSecret.key - + # The ARN for the identity private key + key: "" + # gremlin.tls.identity.createSecret - + # The createSecret strategy accepts PEM encoded certificate and private key content to create a new Kubernetes secret + createSecret: + # gremlin.tls.identity.createSecret.name - + # The name of the new secret + name: "gremlin-tls-identity" + # gremlin.tls.identity.createSecret.cert - + # The PEM-encoded certificate (expected to be a multi-line string) + cert: "" + # gremlin.tls.identity.createSecret.key - + # The PEM-encoded private key (expected to be a multi-line string) + key: "" + # gremlin.tls.identity.existingSecret - + # The existingSecret strategy accepts a reference to an existing Kubernetes secret + existingSecret: + # gremlin.tls.identity.existingSecret.name - + # The name of the existing secret + name: "" + # gremlin.tls.identity.existingSecret.cert - + # The name of the key inside the existing secret that maps to the certificate value + cert: "tls.crt" + # gremlin.tls.identity.existingSecret.key - + # The name of the key inside the existing secret that maps to the private key value + key: "tls.key" + # gremlin.extraEnv # Specify any arbitrary environment variables to pass to the Gremlin Integrations Agent deployment extraEnv: [] diff --git a/gremlin/Chart.yaml b/gremlin/Chart.yaml index 68de2eb..ffb7478 100644 --- a/gremlin/Chart.yaml +++ b/gremlin/Chart.yaml @@ -1,5 +1,5 @@ name: gremlin -version: 0.24.3 +version: 0.25.0 description: The Gremlin Inc client application apiVersion: v1 home: https://www.gremlin.com @@ -7,4 +7,4 @@ maintainers: - name: Gremlin Development email: dev@gremlin.com annotations: - minimumAppVersion: 2.44.0 + minimumAppVersion: 2.66.0 diff --git a/gremlin/templates/_helpers.tpl b/gremlin/templates/_helpers.tpl index d155859..5aebf27 100644 --- a/gremlin/templates/_helpers.tpl +++ b/gremlin/templates/_helpers.tpl @@ -142,3 +142,173 @@ Create a computed value for the intended Gremlin secret type which can either be {{- "https://api.gremlin.com/v1" -}} {{- end -}} {{- end -}} + +{{/* +gremlinTlsIdentityValidate fails if more than one identity strategy is fully configured for gremlin +*/}} +{{- define "gremlinTlsIdentityValidate" -}} +{{- $remoteSecret := and .Values.gremlin.tls.identity.remoteSecret.cert .Values.gremlin.tls.identity.remoteSecret.key -}} +{{- $createSecret := and .Values.gremlin.tls.identity.createSecret.name .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key -}} +{{- $existingSecret := and .Values.gremlin.tls.identity.existingSecret.name .Values.gremlin.tls.identity.existingSecret.cert .Values.gremlin.tls.identity.existingSecret.key -}} +{{- $count := 0 -}} +{{- if $remoteSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if $createSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if $existingSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if gt (int $count) 1 -}} +{{- fail "gremlin.tls.identity: only one of remoteSecret, createSecret, or existingSecret should be fully configured" -}} +{{- end -}} +{{- end -}} + +{{/* +chaoTlsIdentityValidate fails if more than one identity strategy is fully configured for chao +*/}} +{{- define "chaoTlsIdentityValidate" -}} +{{- $remoteSecret := and .Values.chao.tls.identity.remoteSecret.cert .Values.chao.tls.identity.remoteSecret.key -}} +{{- $createSecret := and .Values.chao.tls.identity.createSecret.name .Values.chao.tls.identity.createSecret.cert .Values.chao.tls.identity.createSecret.key -}} +{{- $existingSecret := and .Values.chao.tls.identity.existingSecret.name .Values.chao.tls.identity.existingSecret.cert .Values.chao.tls.identity.existingSecret.key -}} +{{- $count := 0 -}} +{{- if $remoteSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if $createSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if $existingSecret }}{{- $count = add $count 1 -}}{{- end -}} +{{- if gt (int $count) 1 -}} +{{- fail "chao.tls.identity: only one of remoteSecret, createSecret, or existingSecret should be fully configured" -}} +{{- end -}} +{{- end -}} + +{{/* +gremlinTlsIdentityEnv returns the environment variables needed to configure TLS client identity +When remoteSecret is configured + - sets GREMLIN_TLS_IDENTITY_CERTIFICATE and GREMLIN_TLS_IDENTITY_PRIVATE_KEY to their respective `cert` and `key` values +When createSecret or existingSecret are configured + - sets GREMLIN_TLS_IDENTITY_CERTIFICATE and GREMLIN_TLS_IDENTITY_PRIVATE_KEY to their respective file paths, mounted by gremlinTlsIdentityVolumeMounts +*/}} +{{- define "gremlinTlsIdentityEnv" -}} +{{- if .Values.gremlin.tls.identity.enabled -}} +{{- include "gremlinTlsIdentityValidate" . -}} +{{- if and .Values.gremlin.tls.identity.remoteSecret.cert .Values.gremlin.tls.identity.remoteSecret.key -}} +- name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: {{ .Values.gremlin.tls.identity.remoteSecret.cert | quote }} +- name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: {{ .Values.gremlin.tls.identity.remoteSecret.key | quote }} +{{- else if and .Values.gremlin.tls.identity.createSecret.name .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key -}} +- name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/cert +- name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/key +{{- else if .Values.gremlin.tls.identity.existingSecret.name -}} +- name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/{{ .Values.gremlin.tls.identity.existingSecret.cert }} +- name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/{{ .Values.gremlin.tls.identity.existingSecret.key }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +gremlinTlsIdentityVolumeMounts returns the mounts needed to access TLS client identity files +When createSecret or existingSecret are configured + - mounts to designated secret files under /var/lib/gremlin/tls/identity +*/}} +{{- define "gremlinTlsIdentityVolumeMounts" -}} +{{- if .Values.gremlin.tls.identity.enabled -}} +{{- include "gremlinTlsIdentityValidate" . -}} +{{- if and .Values.gremlin.tls.identity.createSecret.name .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key -}} +- name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true +{{- else if .Values.gremlin.tls.identity.existingSecret.name -}} +- name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +gremlinTlsIdentityVolumes returns the volumes that contain TLS client identity files +When createSecret or existingSecret are configured + - defines the volume associated with the designated secret +*/}} +{{- define "gremlinTlsIdentityVolumes" -}} +{{- if .Values.gremlin.tls.identity.enabled -}} +{{- include "gremlinTlsIdentityValidate" . -}} +{{- if and .Values.gremlin.tls.identity.createSecret.name .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key -}} +- name: gremlin-tls-identity + secret: + secretName: {{ .Values.gremlin.tls.identity.createSecret.name }} +{{- else if .Values.gremlin.tls.identity.existingSecret.name -}} +- name: gremlin-tls-identity + secret: + secretName: {{ .Values.gremlin.tls.identity.existingSecret.name }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +chaoTlsIdentityArgs returns the chao cli arguments needed to configure TLS client identity +When remoteSecret is configured + - sets -tls_identity_cert and -tls_identity_private_key to their respective `cert` and `key` values +When createSecret or existingSecret are configured + - sets -tls_identity_cert and -tls_identity_private_key to their respective file paths, mounted by chaoTlsIdentityVolumeMounts +*/}} +{{- define "chaoTlsIdentityArgs" -}} +{{- if .Values.chao.tls.identity.enabled -}} +{{- include "chaoTlsIdentityValidate" . -}} +{{- if and .Values.chao.tls.identity.remoteSecret.cert .Values.chao.tls.identity.remoteSecret.key -}} +- "-tls_identity_cert" +- {{ .Values.chao.tls.identity.remoteSecret.cert | quote }} +- "-tls_identity_key" +- {{ .Values.chao.tls.identity.remoteSecret.key | quote }} +{{- else if and .Values.chao.tls.identity.createSecret.name .Values.chao.tls.identity.createSecret.cert .Values.chao.tls.identity.createSecret.key -}} +- "-tls_identity_cert" +- "/var/lib/gremlin/tls/identity/cert" +- "-tls_identity_key" +- "/var/lib/gremlin/tls/identity/key" +{{- else if .Values.chao.tls.identity.existingSecret.name -}} +- "-tls_identity_cert" +- "/var/lib/gremlin/tls/identity/{{ .Values.chao.tls.identity.existingSecret.cert }}" +- "-tls_identity_key" +- "/var/lib/gremlin/tls/identity/{{ .Values.chao.tls.identity.existingSecret.key }}" +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +chaoTlsIdentityVolumes returns the volumes that contain TLS client identity files +When createSecret or existingSecret are configured + - defines the volume associated with the designated secret +*/}} +{{- define "chaoTlsIdentityVolumeMounts" -}} +{{- if .Values.chao.tls.identity.enabled -}} +{{- include "chaoTlsIdentityValidate" . -}} +{{- if and .Values.chao.tls.identity.createSecret.name .Values.chao.tls.identity.createSecret.cert .Values.chao.tls.identity.createSecret.key -}} +- name: chao-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true +{{- else if .Values.chao.tls.identity.existingSecret.name -}} +- name: chao-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +chaoTlsIdentityVolumes returns the volumes that contain TLS client identity files +When createSecret or existingSecret are configured + - defines the volume associated with the designated secret +*/}} +{{- define "chaoTlsIdentityVolumes" -}} +{{- if .Values.chao.tls.identity.enabled -}} +{{- include "chaoTlsIdentityValidate" . -}} +{{- if and .Values.chao.tls.identity.createSecret.name .Values.chao.tls.identity.createSecret.cert .Values.chao.tls.identity.createSecret.key -}} +- name: chao-tls-identity + secret: + secretName: {{ .Values.chao.tls.identity.createSecret.name }} +{{- else if .Values.chao.tls.identity.existingSecret.name -}} +- name: chao-tls-identity + secret: + secretName: {{ .Values.chao.tls.identity.existingSecret.name }} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/gremlin/templates/chao-deployment.yaml b/gremlin/templates/chao-deployment.yaml index e7bd061..58ec101 100644 --- a/gremlin/templates/chao-deployment.yaml +++ b/gremlin/templates/chao-deployment.yaml @@ -124,6 +124,9 @@ spec: - "-namespaces" - "{{ join "," .Values.chao.namespaces }}" {{- end}} + {{- if include "chaoTlsIdentityArgs" . }} + {{- include "chaoTlsIdentityArgs" . | nindent 12 }} + {{- end }} imagePullPolicy: {{ .Values.chaoimage.pullPolicy }} name: chao {{- if (or ((eq (include "gremlin.secretType" .) "certificate")) .Values.ssl.certFile) }} @@ -138,6 +141,9 @@ spec: - name: ssl-cert-file mountPath: /etc/gremlin/ssl readOnly: true +{{- end }} +{{- if include "chaoTlsIdentityVolumeMounts" . }} + {{- include "chaoTlsIdentityVolumeMounts" . | nindent 10 }} {{- end }} volumes: - name: gremlin-cert @@ -148,6 +154,9 @@ spec: secret: secretName: ssl-cert-file {{ end }} +{{- if include "chaoTlsIdentityVolumes" . }} + {{- include "chaoTlsIdentityVolumes" . | nindent 6 }} +{{- end }} {{- if .Values.chao.priorityClassName }} priorityClassName: {{ .Values.chao.priorityClassName }} {{- end }} diff --git a/gremlin/templates/daemonset.yaml b/gremlin/templates/daemonset.yaml index 893c8d7..a928569 100644 --- a/gremlin/templates/daemonset.yaml +++ b/gremlin/templates/daemonset.yaml @@ -154,6 +154,9 @@ spec: - name: SSL_CERT_DIR value: {{ .Values.ssl.certDir }} {{- end }} + {{- if include "gremlinTlsIdentityEnv" . }} + {{- include "gremlinTlsIdentityEnv" . | nindent 10 }} + {{- end }} {{- with .Values.gremlin.extraEnv }} {{- toYaml . | nindent 10 }} {{- end }} @@ -183,6 +186,9 @@ spec: mountPath: /etc/gremlin/ssl readOnly: true {{- end }} + {{- if include "gremlinTlsIdentityVolumeMounts" . }} + {{- include "gremlinTlsIdentityVolumeMounts" . | nindent 10 }} + {{- end }} volumes: - name: cgroup-root hostPath: @@ -220,6 +226,9 @@ spec: secret: secretName: ssl-cert-file {{- end }} + {{- if include "gremlinTlsIdentityVolumes" . }} + {{- include "gremlinTlsIdentityVolumes" . | nindent 8 }} + {{- end }} {{- if .Values.gremlin.priorityClassName }} priorityClassName: {{ .Values.gremlin.priorityClassName }} {{- end }} diff --git a/gremlin/templates/secret-chao-tls-identity.yaml b/gremlin/templates/secret-chao-tls-identity.yaml new file mode 100644 index 0000000..d5dfbdc --- /dev/null +++ b/gremlin/templates/secret-chao-tls-identity.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.chao.tls.identity.enabled .Values.chao.tls.identity.createSecret.name (and .Values.chao.tls.identity.createSecret.cert .Values.chao.tls.identity.createSecret.key) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.chao.tls.identity.createSecret.name }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "gremlin.name" . }} + helm.sh/chart: {{ include "gremlin.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + version: v1 +type: kubernetes.io/Opaque +data: + cert: {{ .Values.chao.tls.identity.createSecret.cert | toString | b64enc }} + key: {{ .Values.chao.tls.identity.createSecret.key | toString | b64enc }} +{{- end }} diff --git a/gremlin/templates/secret-gremlin-tls-identity.yaml b/gremlin/templates/secret-gremlin-tls-identity.yaml new file mode 100644 index 0000000..edb1021 --- /dev/null +++ b/gremlin/templates/secret-gremlin-tls-identity.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.gremlin.tls.identity.enabled .Values.gremlin.tls.identity.createSecret.name (and .Values.gremlin.tls.identity.createSecret.cert .Values.gremlin.tls.identity.createSecret.key) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.gremlin.tls.identity.createSecret.name }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "gremlin.name" . }} + helm.sh/chart: {{ include "gremlin.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + version: v1 +type: kubernetes.io/Opaque +data: + cert: {{ .Values.gremlin.tls.identity.createSecret.cert | toString | b64enc }} + key: {{ .Values.gremlin.tls.identity.createSecret.key | toString | b64enc }} +{{- end }} diff --git a/gremlin/tests/chao_deployment_test.yaml b/gremlin/tests/chao_deployment_test.yaml index f71add3..a8b8e55 100644 --- a/gremlin/tests/chao_deployment_test.yaml +++ b/gremlin/tests/chao_deployment_test.yaml @@ -163,3 +163,212 @@ tests: - equal: path: spec.template.spec.volumes[0].secret.secretName value: "my-custom-secret" + + # chao.tls.identity tests + + - it: should not include TLS identity args when tls identity is not enabled + set: + chao.create: true + asserts: + - notContains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_cert" + + - it: should set TLS identity args to ARN values when remoteSecret is configured + set: + chao.create: true + chao.tls.identity.enabled: true + chao.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + chao.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_cert" + - contains: + path: spec.template.spec.containers[0].args + content: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + - contains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_key" + - contains: + path: spec.template.spec.containers[0].args + content: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + + - it: should not mount TLS identity volumes when remoteSecret is configured + set: + chao.create: true + chao.tls.identity.enabled: true + chao.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + chao.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - notContains: + path: spec.template.spec.volumes + content: + name: chao-tls-identity + any: true + + - it: should set TLS identity args to file paths when createSecret is configured + set: + chao.create: true + chao.tls.identity.enabled: true + chao.tls.identity.createSecret.name: chao-tls-identity + chao.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + chao.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_cert" + - contains: + path: spec.template.spec.containers[0].args + content: "/var/lib/gremlin/tls/identity/cert" + - contains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_key" + - contains: + path: spec.template.spec.containers[0].args + content: "/var/lib/gremlin/tls/identity/key" + + - it: should mount TLS identity volume when createSecret is configured + set: + chao.create: true + chao.tls.identity.enabled: true + chao.tls.identity.createSecret.name: chao-tls-identity + chao.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + chao.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: chao-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: chao-tls-identity + secret: + secretName: chao-tls-identity + + - it: should set TLS identity args to file paths when existingSecret is configured + set: + chao.create: true + chao.tls.identity.enabled: true + chao.tls.identity.existingSecret.name: my-existing-secret + chao.tls.identity.existingSecret.cert: tls.crt + chao.tls.identity.existingSecret.key: tls.key + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_cert" + - contains: + path: spec.template.spec.containers[0].args + content: "/var/lib/gremlin/tls/identity/tls.crt" + - contains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_key" + - contains: + path: spec.template.spec.containers[0].args + content: "/var/lib/gremlin/tls/identity/tls.key" + + - it: should set TLS identity args to file paths when existingSecret is customized + set: + chao.create: true + chao.tls.identity.enabled: true + chao.tls.identity.existingSecret.name: my-existing-secret + chao.tls.identity.existingSecret.cert: custom.crt + chao.tls.identity.existingSecret.key: custom.key + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_cert" + - contains: + path: spec.template.spec.containers[0].args + content: "/var/lib/gremlin/tls/identity/custom.crt" + - contains: + path: spec.template.spec.containers[0].args + content: "-tls_identity_key" + - contains: + path: spec.template.spec.containers[0].args + content: "/var/lib/gremlin/tls/identity/custom.key" + + - it: should mount TLS identity volume from existingSecret when configured + set: + chao.create: true + chao.tls.identity.enabled: true + chao.tls.identity.existingSecret.name: my-existing-secret + chao.tls.identity.existingSecret.cert: tls.crt + chao.tls.identity.existingSecret.key: tls.key + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: chao-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: chao-tls-identity + secret: + secretName: my-existing-secret + + - it: should fail when multiple TLS identity strategies are configured for chao + set: + chao.create: true + chao.tls.identity.enabled: true + chao.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + chao.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + chao.tls.identity.createSecret.name: chao-tls-identity + chao.tls.identity.createSecret.cert: "dummy-cert" + chao.tls.identity.createSecret.key: "dummy-key" + asserts: + - failedTemplate: + errorMessage: "chao.tls.identity: only one of remoteSecret, createSecret, or existingSecret should be fully configured" diff --git a/gremlin/tests/daemonset_test.yaml b/gremlin/tests/daemonset_test.yaml index 5483554..57b47e6 100644 --- a/gremlin/tests/daemonset_test.yaml +++ b/gremlin/tests/daemonset_test.yaml @@ -275,3 +275,207 @@ tests: content: name: GREMLIN_PUSH_ZONE_CIDR_TAGS value: "false" + + # gremlin.tls.identity tests + + - it: should not include TLS identity env vars when tls identity is not enabled + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + any: true + - notContains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + any: true + + - it: should set TLS identity env vars to ARN values when remoteSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + gremlin.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + + - it: should not mount TLS identity volumes when remoteSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + gremlin.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true + - notContains: + path: spec.template.spec.volumes + content: + name: gremlin-tls-identity + any: true + + - it: should set TLS identity env vars to file paths when createSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.createSecret.name: gremlin-tls-identity + gremlin.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + gremlin.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/cert + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/key + + - it: should mount TLS identity volume when createSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.createSecret.name: gremlin-tls-identity + gremlin.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + gremlin.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: gremlin-tls-identity + secret: + secretName: gremlin-tls-identity + + - it: should set TLS identity env vars to file paths when existingSecret is configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.existingSecret.name: my-existing-secret + gremlin.tls.identity.existingSecret.cert: tls.crt + gremlin.tls.identity.existingSecret.key: tls.key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/tls.crt + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/tls.key + + - it: should set TLS identity env vars to file paths when existingSecret is customized + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.existingSecret.name: my-existing-secret + gremlin.tls.identity.existingSecret.cert: custom.crt + gremlin.tls.identity.existingSecret.key: custom.key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_CERTIFICATE + value: /var/lib/gremlin/tls/identity/custom.crt + - contains: + path: spec.template.spec.containers[0].env + content: + name: GREMLIN_TLS_IDENTITY_PRIVATE_KEY + value: /var/lib/gremlin/tls/identity/custom.key + + - it: should mount TLS identity volume from existingSecret when configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.existingSecret.name: my-existing-secret + gremlin.tls.identity.existingSecret.cert: tls.crt + gremlin.tls.identity.existingSecret.key: tls.key + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: gremlin-tls-identity + mountPath: /var/lib/gremlin/tls/identity + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: gremlin-tls-identity + secret: + secretName: my-existing-secret + + - it: should fail when multiple TLS identity strategies are configured for gremlin + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + gremlin.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + gremlin.tls.identity.createSecret.name: gremlin-tls-identity + gremlin.tls.identity.createSecret.cert: "dummy-cert" + gremlin.tls.identity.createSecret.key: "dummy-key" + asserts: + - failedTemplate: + errorMessage: "gremlin.tls.identity: only one of remoteSecret, createSecret, or existingSecret should be fully configured" diff --git a/gremlin/tests/secret_chao_tls_identity_test.yaml b/gremlin/tests/secret_chao_tls_identity_test.yaml new file mode 100644 index 0000000..8fd2fe6 --- /dev/null +++ b/gremlin/tests/secret_chao_tls_identity_test.yaml @@ -0,0 +1,101 @@ +suite: Test chao TLS identity secret +templates: + - secret-chao-tls-identity.yaml +release: + name: my-release + namespace: my-namespace + revision: 1 + upgrade: true +tests: + - it: should not create a secret when tls identity is not enabled + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when enabled but no cert/key provided + set: + chao.tls.identity.enabled: true + asserts: + - hasDocuments: + count: 0 + + - it: should create a secret when createSecret strategy is fully configured + set: + chao.tls.identity.enabled: true + chao.tls.identity.createSecret.name: chao-tls-identity + chao.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + chao.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - isKind: + of: Secret + - equal: + path: metadata.name + value: chao-tls-identity + - equal: + path: metadata.namespace + value: my-namespace + - equal: + path: type + value: kubernetes.io/Opaque + + - it: should use a custom secret name when specified + set: + chao.tls.identity.enabled: true + chao.tls.identity.createSecret.name: my-custom-tls-secret + chao.tls.identity.createSecret.cert: "dummy-cert" + chao.tls.identity.createSecret.key: "dummy-key" + asserts: + - equal: + path: metadata.name + value: my-custom-tls-secret + + - it: should not create a secret when remoteSecret strategy is used + set: + chao.tls.identity.enabled: true + chao.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + chao.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when existingSecret strategy is used + set: + chao.tls.identity.enabled: true + chao.tls.identity.existingSecret.name: my-existing-secret + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when not enabled + set: + chao.tls.identity.enabled: false + chao.tls.identity.createSecret.name: my-custom-tls-secret + chao.tls.identity.createSecret.cert: "dummy-cert" + chao.tls.identity.createSecret.key: "dummy-key" + asserts: + - hasDocuments: + count: 0 diff --git a/gremlin/tests/secret_gremlin_tls_identity_test.yaml b/gremlin/tests/secret_gremlin_tls_identity_test.yaml new file mode 100644 index 0000000..923c992 --- /dev/null +++ b/gremlin/tests/secret_gremlin_tls_identity_test.yaml @@ -0,0 +1,101 @@ +suite: Test gremlin TLS identity secret +templates: + - secret-gremlin-tls-identity.yaml +release: + name: my-release + namespace: my-namespace + revision: 1 + upgrade: true +tests: + - it: should not create a secret when tls identity is not enabled + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when enabled but no cert/key provided + set: + gremlin.tls.identity.enabled: true + asserts: + - hasDocuments: + count: 0 + + - it: should create a secret when createSecret strategy is fully configured + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.createSecret.name: gremlin-tls-identity + gremlin.tls.identity.createSecret.cert: | + -----BEGIN CERTIFICATE----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END CERTIFICATE----- + gremlin.tls.identity.createSecret.key: + -----BEGIN PRIVATE KEY----- + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111111111111111111111111111111111111 + 11111111111111111111111111111111111111111111111111== + -----END PRIVATE KEY----- + asserts: + - isKind: + of: Secret + - equal: + path: metadata.name + value: gremlin-tls-identity + - equal: + path: metadata.namespace + value: my-namespace + - equal: + path: type + value: kubernetes.io/Opaque + + - it: should use a custom secret name when specified + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.createSecret.name: my-custom-tls-secret + gremlin.tls.identity.createSecret.cert: "dummy-cert" + gremlin.tls.identity.createSecret.key: "dummy-key" + asserts: + - equal: + path: metadata.name + value: my-custom-tls-secret + + - it: should not create a secret when remoteSecret strategy is used + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.remoteSecret.cert: "arn:aws:secretsmanager:us-east-1:123456789:secret:cert" + gremlin.tls.identity.remoteSecret.key: "arn:aws:secretsmanager:us-east-1:123456789:secret:key" + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when not enabled + set: + gremlin.tls.identity.enabled: false + gremlin.tls.identity.createSecret.name: my-custom-tls-secret + gremlin.tls.identity.createSecret.cert: "dummy-cert" + gremlin.tls.identity.createSecret.key: "dummy-key" + asserts: + - hasDocuments: + count: 0 + + - it: should not create a secret when existingSecret strategy is used + set: + gremlin.tls.identity.enabled: true + gremlin.tls.identity.existingSecret.name: my-existing-secret + asserts: + - hasDocuments: + count: 0 diff --git a/gremlin/values.yaml b/gremlin/values.yaml index 12ab486..449c9ff 100644 --- a/gremlin/values.yaml +++ b/gremlin/values.yaml @@ -290,6 +290,59 @@ gremlin: pushCIDRTags: enabled: true + # gremlin.tls - + # A collection of TLS configurations specific to the Gremlin Daemonset. + tls: + # gremlin.tls.identity - + # Configuration items for configuring the TLS identity of the Gremlin HTTP client for mTLS. + # Identity values are made up of + # - `cert` portion, containing the leaf certificate for the client (plus any intermediate certificates) + # - `key` portion, containing the private key for the client + # + # These values can be supplied in three different strategies: + # - `remoteSecret`: a collection of ARN values for AWS Secrets Manager + # - `createSecret`: content supplied directly to this chart for which a new Kubernetes secret will be created + # - `existingSecret`: a reference to an existing Kubernetes secret (e.g. created from cert-manager) + # + # Only one of the above strategies should be fully configured. A strategy is not used until all of its fields are configured. + identity: + # gremlin.tls.identity.enabled - + # Decides whether the Gremlin Daemonset should be configured for a TLS identity + enabled: false + # gremlin.tls.identity.remoteSecret - + # The remoteSecret strategy accepts `cert` and `key` strings in the form of ARN values for AWS Secrets Manager + remoteSecret: + # gremlin.tls.identity.remoteSecret.cert - + # The ARN for the identity certificate + cert: "" + # gremlin.tls.identity.remoteSecret.key - + # The ARN for the identity private key + key: "" + # gremlin.tls.identity.createSecret - + # The createSecret strategy accepts PEM encoded certificate and private key content to create a new Kubernetes secret + createSecret: + # gremlin.tls.identity.createSecret.name - + # The name of the new secret + name: "gremlin-tls-identity" + # gremlin.tls.identity.createSecret.cert - + # The PEM-encoded certificate (expected to be a multi-line string) + cert: "" + # gremlin.tls.identity.createSecret.key - + # The PEM-encoded private key (expected to be a multi-line string) + key: "" + # gremlin.tls.identity.existingSecret - + # The existingSecret strategy accepts a reference to an existing Kubernetes secret + existingSecret: + # gremlin.tls.identity.existingSecret.name - + # The name of the existing secret + name: "" + # gremlin.tls.identity.existingSecret.cert - + # The name of the key inside the existing secret that maps to the certificate value + cert: "tls.crt" + # gremlin.tls.identity.existingSecret.key - + # The name of the key inside the existing secret that maps to the private key value + key: "tls.key" + chao: # chao.create @@ -332,6 +385,60 @@ chao: # list of namespaces for Gremlin to watch for attacking namespaces: [] + + # chao.tls - + # A collection of TLS configurations specific to the Chao Deployment. + tls: + # chao.tls.identity - + # Configuration items for configuring the TLS identity of the Gremlin HTTP client for mTLS. + # Identity values are made up of + # - `cert` portion, containing the leaf certificate for the client (plus any intermediate certificates) + # - `key` portion, containing the private key for the client + # + # These values can be supplied in three different strategies: + # - `remoteSecret`: a collection of ARN values for AWS Secrets Manager + # - `createSecret`: content supplied directly to this chart for which a new Kubernetes secret will be created + # - `existingSecret`: a reference to an existing Kubernetes secret (e.g. created from cert-manager) + # + # Only one of the above strategies should be fully configured. A strategy is not used until all of its fields are configured. + identity: + # chao.tls.identity.enabled - + # Decides whether the Chao Deployment should be configured for a TLS identity + enabled: false + # chao.tls.identity.remoteSecret - + # The remoteSecret strategy accepts `cert` and `key` strings in the form of ARN values for AWS Secrets Manager + remoteSecret: + # chao.tls.identity.remoteSecret.cert - + # The ARN for the identity certificate + cert: "" + # chao.tls.identity.remoteSecret.key - + # The ARN for the identity private key + key: "" + # chao.tls.identity.createSecret - + # The createSecret strategy accepts PEM encoded certificate and private key content to create a new Kubernetes secret + createSecret: + # chao.tls.identity.createSecret.name - + # The name of the new secret + name: "chao-tls-identity" + # chao.tls.identity.createSecret.cert - + # The PEM-encoded certificate (expected to be a multi-line string) + cert: "" + # chao.tls.identity.createSecret.key - + # The PEM-encoded private key (expected to be a multi-line string) + key: "" + # chao.tls.identity.existingSecret - + # The existingSecret strategy accepts a reference to an existing Kubernetes secret + existingSecret: + # chao.tls.identity.existingSecret.name - + # The name of the existing secret + name: "" + # chao.tls.identity.existingSecret.cert - + # The name of the key inside the existing secret that maps to the certificate value + cert: "tls.crt" + # chao.tls.identity.existingSecret.key - + # The name of the key inside the existing secret that maps to the private key value + key: "tls.key" + ssl: # ssl.certFile - # Add a certificate file to Gremlin's set of certificate authorities. This argument expects a file containing the