5

Imagine a secret like this:

apiVersion: v1
kind: Secret
metadata:
  name: {{ include "test-cicd.fullname" . }}
  labels:
    app.kubernetes.io/name: {{ include "test-cicd.name" . }}
    helm.sh/chart: {{ include "test-cicd.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
type: Opaque
data:
  secret.yaml: |
    {{ if eq .Values.env "prod" }}
    foo: bar-prod
    foo2: bar2_prod
    {{ else if eq .Values.evn "dev" }}
    foo: bar-dev
    {{ end }}

Is it possible to seal this using Kubeseal? Upon doing it now, I get invalid map key: map[interface {}]interface {}{"include \"test-cicd.fullname\" .":interface {}(nil)} which is probably because it is not a "valid" yaml file.

One thing that I tried was: 1. Removing the helm templating lines 2. Generating the sealedsecret 3. Templating the sealedsecret using helm

But by doing this, the sealedsecret could not be decrypted by the cluster-side operator on deployment time.

Milad
  • 608
  • 1
  • 6
  • 14
  • I'm not familiar with Kubeseal, but if you want to learn about alternative solutions you can check out my [recent post](https://learnk8s.io/kubernetes-secrets-in-git/). – Omer Levi Hevroni Oct 02 '19 at 06:31
  • 1
    Thanks @OmerLeviHevroni. I got the answer from `mkmik` on [GitHub](https://github.com/bitnami-labs/sealed-secrets/issues/277). – Milad Oct 03 '19 at 02:15
  • 3
    @Milad Could you please post the answer from GitHub here also? It would be helpful for other folks with the same issue. – Wytrzymały Wiktor Oct 03 '19 at 08:37
  • @Milad how about this setup? https://stackoverflow.com/questions/69564901/how-to-use-kubernetes-sealed-secrets-with-helm-templates – uberrebu Oct 14 '21 at 14:42

3 Answers3

14

mkmik gave an answer to my question on Github, so I'm quoting it here as well just for the records.


So, you're composing a secret value with client-side templating. Parts of your secret.yaml file are secret, yet parts must be templating directives (the if) and hence cannot be encrypted.

You have two options:

  1. you encrypt your secrets somehow using some client-side vault software, possibly with helm integration (e.g. https://github.com/futuresimple/helm-secrets). That requires every user (and CI environment) that applies that helm chart, to be able to decrypt the secrets.

  2. you re-factor your secrets so that secrets are "atomic", and use sealed-secrets to benefit from its "one-way encryption" approach, which allows your devops users (and CI automation) to apply the helm charts without ever seeing the secret values themselves.

The rest of this answer assumes you picked option (2)


Now, since you decided to use Helm, you have to deal with the fact that helm templates are not json/yaml files, but instead they are Go templates, and hence they cannot be manipulated by tools designed to manipulated structured data formats.

Luckily, kubeseal has a --raw command, that allows you to encrypt individual secret values and put them manually in whatever file format you're using to describe your k8s resources.

So, assuming you want to create a Helm template for SealedSecrets resource, which takes the name and label values as paramters, and also chooses which secrets to put also based on boolean prod/dev parameter, this example might work for you:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: {{ include "test-cicd.fullname" . }}
  annotations:
    # this is because the name is a deployment time parameter
    # consider also using "cluster-wide" if the namespace is also a parameter
    # please make sure you understand the implications, see README
    sealedsecrets.bitnami.com/namespace-wide: "true"
  labels:
    app.kubernetes.io/name: {{ include "test-cicd.name" . }}
    helm.sh/chart: {{ include "test-cicd.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
type: Opaque
spec:
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "test-cicd.name" . }}
        app.kubernetes.io/instance: {{ .Release.Name }}
        app.kubernetes.io/managed-by: {{ .Release.Service }}
  encryptedData:
    {{ if eq .Values.env "prod" }}
    foo: AgASNmKx2+QYbbhSxBE0KTa91sDBeNSaicvgBPW8Y/q/f806c7lKfF0mnxzEirjBsvF67C/Yp0fwSokIpKyy3gXtatg8rhf8uiQAA3VjJGkl5VYLcad0t6hKQyIfHsD7wrocm36uz9hpH30DRPWtL5qy4Z+zbzHj8AvEV+xTpBHCSyJPF2hyvHXTr6iQ6KJrAKy04MDwjyQzllN5OQJT2w4zhVgTxXSg/c7m50U/znbcJ1x5vWLXLSeiDRrsJEJeNoPQM8OHmosf5afSOTDWQ4IhG3srSBfDExSFGBIC41OT2CUUmCCtrc9o61LJruqshZ3PkiS7PqejytgwLpw/GEnj2oa/uNSStiP9oa9mCY6IUMujwjF9rKLIT456DlrnsS0bYXO2NmYwSfFX+KDbEhCIVFMbMupMSZp9Ol2DTim5SLIgIza/fj0CXaO3jGiltSQ0aM8gLSMK9n3c1V+X5hKmzMI3/Xd01QmhMmwqKp+oy21iidLJjtz67EiWyfIg1l7hiD5IIVlM9Gvg3k67zij5mOcXPkFnMmUQhQWxVKgAf4z8qEgprt03C+q+Wwwt25UDhQicpwoGtVQzU5ChJi09ja5LeW4RrvDf2B5KRp9HXoj1eu93MMl1Kcnx+X7uVT5OqQz28c4wOLT4FDItFzh8zREGZbiG/B3o1vI8MmwvxXj++pQ7SfBxoz9Xe8gmQ7BuXno=
    foo2: AgAkaTBYcESwogPiauZ15YbNldmk4a9esyYuR2GDt7hNcv+ycPLHmnsJcYs0hBtqucmrO3HbgCy/hQ6dMRCY12RA7w7XsFqNjZy3kavnhqwM6YkHntK2INwercRNQpO6B9bH6MxQTXcxfJbPqaPt30iTnTAhtpN47lueoyIoka4WWzwG/3PAikXhIlkTaq0hrclRJHRqg4z8Kmcaf5A/BRL2xX8syHbjA7MK9/OoK+zytv+LGrbLLHUtuhNNNQ2PG9u05rP6+59wRduQojEDtB9FTCa+daS+04/F4H1vi6XUNnjkK+Xna1T2Eavyuq2GieKj/7ig96et/4HoTAz44zwVhh8/pk0IFC8srcH3p+rFtZZmjvbURrFahEjFZbav3BDMBNhrU8SI3MDN0Abiyvz4vJJfSxIYcyLD1EQ507q7ZXrqYN/v1EiYgYUACi0JGxSWHB9TlCkZOAdCl+hroXEhBN2u5utLJ12njBQJ8ACNQDOYf+CmtV0y7foCZ6Aaap0pV7a8twyqK8c17kImzfi102Zel8ALfLAzdAXBV9c1+1pH76turnTCE33aSMQlaVF3VTmFQWqB8uIO/FQhZDPo8u/ki3L8J31nepup4/WE7i59IT0/9qGh2LKql4oAv6v4D7qtKziN6DvG7bsJlj14Dln0roiTfTWEEnBqdDER+GKZJlKayOWsPQdN0Wp+2KVfwLM=
    {{ else if eq .Values.evn "dev" }}
    foo: AgAkaTBYcESwogPi..........
    {{ end }}

An alternative approach would be to have two templates, one for prod and one for dev and use Helm templating logic to pick the right file depending on which environment you're deploying to.

Anyway, each of those base64 blobs can be produced with:

$ kubeseal --raw --scope namespace-wide --from-file=yoursecret.txt

Pro-tip, you can pipe the secret if it's not in a file:

$ echo -n yoursecret | kubeseal --raw --scope namespace-wide --from-file=/dev/stdin

Then you have to paste the output of that command into your Helm Go template.

Milad
  • 608
  • 1
  • 6
  • 14
  • 1
    It would be nice if kubeseal could encrypt Helm values.yaml files. e.g. https://github.com/markmclaren/sealed-secrets-file-encrypt – Mark McLaren Dec 13 '19 at 09:00
  • You can't find this, anywhere else on Internet. This is the way to use SealedSecrets with helm templates – Ghasem May 21 '21 at 15:58
  • hoe about this setup? https://stackoverflow.com/questions/69564901/how-to-use-kubernetes-sealed-secrets-with-helm-templates – uberrebu Oct 14 '21 at 14:42
  • You've error in kubeseal, when you are using --scope namespace-wide, you need to set additional flag --namespace, otherwise it wont to decrypted – Matthew Benjamin Jun 12 '22 at 22:09
2

My approach

  1. Use different .values.yml files for different environments
  2. Create .secrets.yml files to store secret values (include in .gitignore)
  3. Make a git pre-commit hook that uses kubeseal --raw to encrypt the individual secrets and then write them to the values file
  4. Store the values file in git.

I wrote a gist on this: https://gist.github.com/foogunlana/b75175b4ff62bc07258ea78274c698cd

Bo Ogunlana
  • 211
  • 2
  • 4
  • That's a great solution. Thank you for sharing. – Nicolas Forney May 26 '21 at 14:54
  • your solution is very hacky...you are pretty much having a bash script manipulate file content...check this setup out https://stackoverflow.com/questions/69564901/how-to-use-kubernetes-sealed-secrets-with-helm-templates – uberrebu Oct 15 '21 at 17:53
0

I would not put credentials from different environment into a single secret as it can be deployed into different cluster with different sealed controller.

Why don't you just separate secret files for each environment?

For seal a secret I use the following command:

kubeseal --name=name-of-the-config --controller-namespace=fluxcd \
       --controller-name=sealed-secrets  --format yaml \
      < secret.yaml > sealedsecret.yaml

You can detect the controller-name and controller-namespace of the helm release by:

kubectl get HelmRelease -A -o jsonpath="{.items[?(@.spec.chart@.name=='sealed-secrets')]}"
oliver nadj
  • 788
  • 7
  • 21
  • the question is referencing using `values-*.yaml` file for different environments...your solution does not address that – uberrebu Oct 15 '21 at 17:54