diff --git a/logstash/README.md b/logstash/README.md index 98afca4e4..2a1d84645 100644 --- a/logstash/README.md +++ b/logstash/README.md @@ -134,6 +134,7 @@ using `http.host: 127.0.0.1`, default probes should be disabled or overrided | `replicas` | Kubernetes replica count for the StatefulSet (i.e. how many pods) | `1` | | `resources` | Allows you to set the [resources][] for the StatefulSet | see [values.yaml][] | | `schedulerName` | Name of the [alternate scheduler][] | `""` | +| `secrets` | Allows you easily create a secret from as variables or file. For add secrets from file, add suffix `.filepath` to the key of secret key. The value will be encoded to base64. Useful for store certificates and other secrets. | See [values.yaml][] | | `secretMounts` | Allows you easily mount a secret as a file inside the StatefulSet. Useful for mounting certificates and other secrets. See [values.yaml][] for an example | `[]` | | `securityContext` | Allows you to set the [securityContext][] for the container | see [values.yaml][] | | `service` | Configurable [service][] to expose the Logstash service. | see [values.yaml][] | diff --git a/logstash/templates/secret.yaml b/logstash/templates/secret.yaml new file mode 100644 index 000000000..0abf78650 --- /dev/null +++ b/logstash/templates/secret.yaml @@ -0,0 +1,27 @@ +{{- if .Values.secrets }} +{{- $fullName := include "logstash.fullname" . -}} +{{- range .Values.secrets }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-%s" $fullName .name | quote }} + labels: + app: {{ $fullName | quote }} + chart: {{ $.Chart.Name | quote }} + heritage: {{ $.Release.Service | quote }} + release: {{ $.Release.Name | quote }} + {{- range $key, $value := $.Values.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} +data: +{{- range $key, $val := .value }} + {{- if hasSuffix "filepath" $key }} + {{ $key | replace ".filepath" "" }}: {{ $.Files.Get $val | b64enc | quote }} + {{ else }} + {{ $key }}: {{ $val | b64enc | quote }} + {{- end }} +{{- end }} +type: Opaque +{{- end }} +{{- end }} \ No newline at end of file diff --git a/logstash/tests/logstash_test.py b/logstash/tests/logstash_test.py index 7aa81e69f..513de1be0 100755 --- a/logstash/tests/logstash_test.py +++ b/logstash/tests/logstash_test.py @@ -1,10 +1,9 @@ +import base64 import os import sys sys.path.insert(1, os.path.join(sys.path[0], "../../helpers")) from helpers import helm_template -import yaml - name = "release-name-logstash" @@ -307,6 +306,151 @@ def test_adding_a_secret_mount_with_subpath(): } +def test_adding_a_secret(): + content = "LS1CRUdJTiBgUFJJVkFURSB" + config = """ +secrets: + - name: "env" + value: + ELASTICSEARCH_PASSWORD: {elk_pass} +""".format( + elk_pass=content + ) + content_b64 = base64.b64encode(content.encode("ascii")).decode("ascii") + + r = helm_template(config) + secret_name = name + "-env" + s = r["secret"][secret_name] + assert s["metadata"]["labels"]["app"] == name + assert len(r["secret"]) == 1 + assert len(s["data"]) == 1 + assert s["data"] == {"ELASTICSEARCH_PASSWORD": content_b64} + + +def test_adding_secret_from_file(): + content = """ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEApCt3ychnqZHsS +DylPFZn55xDaDcWco1oNFdBGzFjw+ +zkuMFMOv7ab+yOFwHeEeAAEkEgy1u +Da1vIscBs1K0kbEFRSqySLuNHWiJp +wK2cI/gJc+S9Qd9Qsn0XGjmjQ6P2p +ot2hvCOtnei998OmDSYORKBq2jiv/ +-----END RSA PRIVATE KEY----- +""" + config = """ +secrets: + - name: "tls" + value: + cert.key.filepath: "secrets/private.key" +""" + content_b64 = base64.b64encode(content.encode("ascii")).decode("ascii") + work_dir = os.path.join(os.path.abspath(os.getcwd()), "secrets") + filename = os.path.join(work_dir, "private.key") + os.makedirs(os.path.dirname(filename), exist_ok=True) + with open(filename, "w") as f: + f.write(content) + + with open(filename, "r") as f: + data = f.read() + assert data == content + + r = helm_template(config) + secret_name = name + "-tls" + s = r["secret"][secret_name] + assert s["metadata"]["labels"]["app"] == name + assert len(r["secret"]) == 1 + assert len(s["data"]) == 1 + assert s["data"] == { + "cert.key": content_b64, + } + + os.remove(filename) + os.rmdir(work_dir) + + +def test_adding_multiple_data_secret(): + content = { + "elk_pass": "LS1CRUdJTiBgUFJJVkFURSB", + "api_key": "ui2CsdUadTiBasRJRkl9tvNnw", + } + config = """ +secrets: + - name: "env" + value: + ELASTICSEARCH_PASSWORD: {elk_pass} + api_key: {api_key} +""".format( + elk_pass=content["elk_pass"], api_key=content["api_key"] + ) + content_b64 = { + "elk_pass": base64.b64encode(content["elk_pass"].encode("ascii")).decode( + "ascii" + ), + "api_key": base64.b64encode(content["api_key"].encode("ascii")).decode("ascii"), + } + + r = helm_template(config) + secret_name = name + "-env" + s = r["secret"][secret_name] + assert s["metadata"]["labels"]["app"] == name + assert len(r["secret"]) == 1 + assert len(s["data"]) == 2 + assert s["data"] == { + "ELASTICSEARCH_PASSWORD": content_b64["elk_pass"], + "api_key": content_b64["api_key"], + } + + +def test_adding_multiple_secrets(): + content = { + "elk_pass": "LS1CRUdJTiBgUFJJVkFURSB", + "cert_crt": "LS0tLS1CRUdJTiBlRJRALKJDDQVRFLS0tLS0K", + "cert_key": "LS0tLS1CRUdJTiBgUFJJVkFURSBLRVktLS0tLQo", + } + config = """ +secrets: + - name: "env" + value: + ELASTICSEARCH_PASSWORD: {elk_pass} + - name: "tls" + value: + cert.crt: {cert_crt} + cert.key: {cert_key} + +""".format( + elk_pass=content["elk_pass"], + cert_crt=content["cert_crt"], + cert_key=content["cert_key"], + ) + content_b64 = { + "elk_pass": base64.b64encode(content["elk_pass"].encode("ascii")).decode( + "ascii" + ), + "cert_crt": base64.b64encode(content["cert_crt"].encode("ascii")).decode( + "ascii" + ), + "cert_key": base64.b64encode(content["cert_key"].encode("ascii")).decode( + "ascii" + ), + } + + r = helm_template(config) + secret_names = {"env": name + "-env", "tls": name + "-tls"} + s_env = r["secret"][secret_names["env"]] + s_tls = r["secret"][secret_names["tls"]] + assert len(r["secret"]) == 2 + assert len(s_env["data"]) == 1 + assert s_env["data"] == { + "ELASTICSEARCH_PASSWORD": content_b64["elk_pass"], + } + assert len(s_tls["data"]) == 2 + assert s_tls["data"] == { + "cert.crt": content_b64["cert_crt"], + "cert.key": content_b64["cert_key"], + } + + def test_adding_image_pull_secrets(): config = """ imagePullSecrets: diff --git a/logstash/values.yaml b/logstash/values.yaml index 50e19544f..ca5126ce3 100755 --- a/logstash/values.yaml +++ b/logstash/values.yaml @@ -39,6 +39,23 @@ envFrom: [] # - configMapRef: # name: config-map +# Add sensitive data to k8s secrets +secrets: [] +# - name: "env" +# value: +# ELASTICSEARCH_PASSWORD: "LS1CRUdJTiBgUFJJVkFURSB" +# api_key: ui2CsdUadTiBasRJRkl9tvNnw +# - name: "tls" +# value: +# ca.crt: | +# LS0tLS1CRUdJT0K +# LS0tLS1CRUdJT0K +# LS0tLS1CRUdJT0K +# LS0tLS1CRUdJT0K +# cert.crt: "LS0tLS1CRUdJTiBlRJRklDQVRFLS0tLS0K" +# cert.key.filepath: "secrets.crt" # The path to file should be relative to the `values.yaml` file. + + # A list of secrets and their paths to mount inside the pod secretMounts: []