Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How not to overwrite randomly generated secrets in Helm templates

I want to generate a password in a Helm template, this is easy to do using the randAlphaNum function. However the password will be changed when the release is upgraded. Is there a way to check if a password was previously generated and then use the existing value? Something like this:

apiVersion: v1
kind: Secret
metadata:
  name: db-details
data:
  {{ if .Secrets.db-details.db-password }}
  db-password:  {{ .Secrets.db-details.db-password | b64enc }}
  {{ else }}
  db-password: {{ randAlphaNum 20 | b64enc }}
  {{ end }}
like image 506
Mikhail Janowski Avatar asked May 16 '19 13:05

Mikhail Janowski


3 Answers

You can build on shaunc's idea to use the lookup function to fix the original poster's code like this:

apiVersion: v1
kind: Secret
metadata:
  name: db-details
data:
  {{- if .Release.IsInstall }}
  db-password: {{ randAlphaNum 20 | b64enc }}
  {{ else }}
  # `index` function is necessary because the property name contains a dash.
  # Otherwise (...).data.db_password would have worked too.
  db-password:  {{ index (lookup "v1" "Secret" .Release.Namespace "db-details").data "db-password" }}
  {{ end }}

Only creating the Secret when it doesn't yet exist won't work because Helm will delete objects that are no longer defined during the upgrade.

Using an annotation to keep the object around has the disadvantage that it will not be deleted when you delete the release with helm delete ....

like image 123
Jan Dubois Avatar answered Oct 17 '22 23:10

Jan Dubois


I've got a lot of trouble with the answers from Jan Dubois and shaunc. So I built a combined solution.

The downside of Jan's answer: It leads to errors, when it is used with --dry-run.
The downside of shaunc's answer: It won't work, because the resources will be deleted on helm upgrade.

Here is my code:

# store the secret-name as var
# in my case, the name was very long and containing a lot of fields
# so it helps me a lot
{{- $secret_name := "your-secret-name" -}}

apiVersion: v1
kind: Secret
metadata:
  name: {{ $secret_name }}

data:
  # try to get the old secret
  # keep in mind, that a dry-run only returns an empty map 
  {{- $old_sec := lookup "v1" "Secret" .Release.Namespace $secret_name }}

  # check, if a secret is already set
  {{- if or (not $old_sec) (not $old_sec.data) }}
  # if not set, then generate a new password
  db-password: {{ randAlphaNum 20 | b64enc }}
  {{ else }}
  # if set, then use the old value
  db-password: {{ index $old_sec.data "db-password" }}
  {{ end }}
like image 9
akop Avatar answered Oct 17 '22 22:10

akop


It's still one of the biggest issues of Helm. As far as I understand no good solution is available yet (see https://github.com/helm/charts/issues/5167).

One dirty workaround is to create secret as pre-install hook. Obvious downside of this approach is that secret will not be deleted on helm delete.

apiVersion: v1
kind: Secret
metadata:
  name: {{ template "helm-random-secret.fullname" . }}
  annotations:
    "helm.sh/hook": "pre-install"
    "helm.sh/hook-delete-policy": "before-hook-creation"
  labels:
    app: {{ template "helm-random-secret.name" . }}
    chart: {{ template "helm-random-secret.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
data:
  some-password: {{ default (randAlphaNum 10) .Values.somePassword | b64enc | quote }}
like image 8
Vasili Angapov Avatar answered Oct 17 '22 23:10

Vasili Angapov