[COMMON] Optimize common secret template
[oom.git] / kubernetes / common / common / templates / _secret.tpl
1 {{/*
2 # Copyright © 2019 AT&T, Samsung Electronics
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #       http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 */}}
16
17 {{/*
18   For internal use only!
19
20   Generates a secret header with given name and desired labels.
21
22   The template takes two arguments:
23     - .global: environment (.)
24     - .name: name of the secret
25     - .annotations: annotations which should be used
26
27   Example call:
28     {{ include "common.secret._header" (dict "global" . "name" "myFancyName") }}
29 */}}
30 {{- define "common.secret._header" -}}
31 {{- $global := .global }}
32 {{- $name := .name }}
33 apiVersion: v1
34 kind: Secret
35 metadata:
36   name: {{ $name }}
37   namespace: {{ include "common.namespace" $global }}
38   labels:
39     app: {{ include "common.name" $global }}
40     chart: {{ $global.Chart.Name }}-{{ $global.Chart.Version | replace "+" "_" }}
41     release: {{ include "common.release" $global }}
42     heritage: {{ $global.Release.Service }}
43 {{- if .annotations }}
44   annotations: {{- include "common.tplValue" (dict "value" .annotations "context" $global) | nindent 4 }}
45 {{- end }}
46 type: Opaque
47 {{- end -}}
48
49 {{/*
50   For internal use only!
51
52   Pick a value based on "user input" and generation policy.
53
54   The template takes below arguments:
55     - .global: environment (.)
56     - .secretName: name of the secret where the value will be placed
57     - .secretEnv: map of values which configures this secret. This can contain below keys:
58         - value: Value of secret key provided by user (can be a template inside a string)
59         - policy: What to do if value is missing or empty. Possible options are:
60             - generate: Generate a new password deriving it from master password
61             - required: Fail the deployment if value has not been provided
62           Defaults to generate.
63         - name: Name of the key to which this value should be assigned
64 */}}
65 {{- define "common.secret._value" -}}
66   {{- $global := .global }}
67   {{- $name := .secretName }}
68   {{- $secretEnv := .secretEnv }}
69   {{- $value := tpl $secretEnv.value $global }}
70   {{- $policy := default "generate" $secretEnv.policy }}
71
72   {{- if $value }}
73     {{- $value | quote }}
74   {{- else if eq $policy "generate" }}
75     {{- include "common.createPassword" (dict "dot" $global "uid" $name) | quote }}
76   {{- else }}
77     {{- fail (printf "Value for %s secret %s key not provided" $name $secretEnv.name) }}
78   {{- end }}
79 {{- end -}}
80
81 {{/*
82   For internal use only!
83
84   Pick a value based on "user input" and generation policy.
85
86   The template takes below arguments:
87     - .global: environment (.)
88     - .secretName: name of the secret where the value will be placed
89     - .secretEnv: map of values which configures this secret. This can contain below keys:
90         - value: Value of secret key provided by user (can be a template inside a string)
91         - policy: What to do if value is missing or empty. Possible options are:
92             - generate: Generate a new password deriving it from master password
93             - required: Fail the deployment if value has not been provided
94           Defaults to generate.
95         - name: Name of the key to which this value should be assigned
96 */}}
97 {{- define "common.secret._valueFast" -}}
98   {{- $global := .global }}
99   {{- $name := .secretName }}
100   {{- $secretEnv := .secretEnv }}
101   {{- $value := $secretEnv.value }}
102   {{- $policy := default "generate" $secretEnv.policy }}
103
104   {{- if $value }}
105     {{- $value | quote }}
106   {{- else if eq $policy "generate" }}
107     {{- include "common.createPassword" (dict "dot" $global "uid" $name) | quote }}
108   {{- else }}
109     {{- fail (printf "Value for %s secret %s key not provided" $name $secretEnv.name) }}
110   {{- end }}
111 {{- end -}}
112
113
114 {{/*
115   Generate a secret name based on provided name or UID.
116   If UID is provided then the name is generated by appending this UID right after
117   the chart name. If name is provided, it overrides the name generation algorith
118   and is used right away. Both name and uid strings may contain a template to be
119   resolved.
120
121   The template takes below arguments:
122     - .global: environment (.)
123     - .uid: string that uniquely identifies this secret within a helm chart
124     - .name: string that can be used to override default name generation algorithm
125         and provide a custom name for the secret
126 */}}
127 {{- define "common.secret.genName" -}}
128   {{- $global := .global }}
129   {{- $uid := tpl (default "" .uid) $global }}
130   {{- $name := tpl (default "" .name) $global }}
131   {{- $fullname := ne (default "" .chartName) "" | ternary (include "common.fullnameExplicit" (dict "dot" $global "chartName" .chartName)) (include "common.fullname" $global) }}
132   {{- default (printf "%s-%s" $fullname $uid) $name }}
133 {{- end -}}
134
135 {{- define "common.secret.genNameFast" -}}
136   {{- $global := .global }}
137   {{- $uid := (default "" .uid) }}
138   {{- $name := (default "" .name) }}
139   {{- $fullname := ne (default "" .chartName) "" | ternary (include "common.fullnameExplicit" (dict "dot" $global "chartName" .chartName)) (include "common.fullname" $global) }}
140   {{- default (printf "%s-%s" $fullname $uid) $name }}
141 {{- end -}}
142
143 {{/*
144   Get the real secret name by UID or name, based on the configuration provided by user.
145   User may decide to not create a new secret but reuse existing one for this deployment
146   (aka externalSecret). In this case the real name of secret to be used is different
147   than the one declared in secret definition. This easily retrieve current secret real
148   name based on declared name or UID even if it has been overrided by the user using
149   externalSecret option. You should use this template always when you need to reference
150   a secret created using common.secret template by name.
151
152   The template takes below arguments:
153     - .global: environment (.)
154     - .uid: string that uniquely identifies this secret within a helm chart
155         (can be omitted if name has been provided)
156     - .name: name which was used to declare a secret
157         (can be omitted if uid has been provided)
158 */}}
159 {{- define "common.secret.getSecretName" -}}
160   {{- $global := .global }}
161   {{- $name := tpl (default "" .name) $global }}
162   {{- $uid := tpl (default "" .uid) $global }}
163   {{- $targetName := default (include "common.secret.genName" (dict "global" $global "uid" $uid "name" .name)) $name}}
164   {{- range $secret := $global.Values.secrets }}
165     {{- $currUID := tpl (default "" $secret.uid) $global }}
166     {{- $givenName := tpl (default "" $secret.name) $global }}
167     {{- $currName := default (include "common.secret.genName" (dict "global" $global "uid" $currUID "name" $secret.name)) $givenName }}
168     {{- if or (eq $uid $currUID) (eq $currName $targetName) }}
169       {{- $externalSecret := tpl (default "" $secret.externalSecret) $global }}
170       {{- default $currName $externalSecret }}
171     {{- end }}
172   {{- end }}
173 {{- end -}}
174
175 {{- define "common.secret.getSecretNameFast" -}}
176   {{- $global := .global }}
177   {{- include "common.secret.buildCache" $global }}
178   {{- $secretsCache := $global.Values._secretsCache }}
179   {{- $uid := tpl .uid $global }}
180   {{- $secret := index $secretsCache $uid }}
181   {{- $secret.realName }}
182 {{- end -}}
183
184 {{- define "common.secret.buildCache" -}}
185   {{- $global := . }}
186   {{- if not $global.Values._secretsCache }}
187     {{- $secretCache := dict }}
188     {{- range $secret := .Values.secrets }}
189       {{- $entry := dict }}
190       {{- $uid := tpl (default "" $secret.uid) $global }}
191       {{- $keys := keys $secret }}
192       {{- range $key := (without $keys "annotations" )}}
193         {{- $_ := set $entry $key (tpl (index $secret $key) $global) }}
194       {{- end }}
195       {{- if $secret.annotations }}
196         {{- $_ := set $entry "annotations" $secret.annotations }}
197       {{- end }}
198       {{- $realName := default (include "common.secret.genNameFast" (dict "global" $global "uid" $uid "name" $entry.name) ) $entry.externalSecret }}
199       {{- $_ := set $entry "realName" $realName }}
200       {{- $_ := set $secretCache $uid $entry }}
201     {{- end }}
202     {{- $_ := set $global.Values "_secretsCache" $secretCache }}
203   {{- end }}
204 {{- end -}}
205
206 {{/*
207   Convenience template which can be used to easily set the value of environment variable
208   to the value of a key in a secret.
209
210   It takes care of all name mangling, usage of external secrets etc.
211
212   The template takes below arguments:
213     - .global: environment (.)
214     - .uid: string that uniquely identifies this secret within a helm chart
215         (can be omitted if name has been provided)
216     - .name: name which was used to declare a secret
217         (can be omitted if uid has been provided)
218     - .key: Key within this secret which value should be assigned to this variable
219
220   Example usage:
221   env:
222     - name: SECRET_PASSWORD
223       {{- include "common.secret.envFromSecret" (dict "global" . "uid" "secret" "key" "password") | indent 8}}
224 */}}
225 {{- define "common.secret.envFromSecret" -}}
226   {{- $key := .key }}
227 valueFrom:
228   secretKeyRef:
229     name: {{ include "common.secret.getSecretName" . }}
230     key: {{ $key }}
231 {{- end -}}
232
233 {{- define "common.secret.envFromSecretFast" -}}
234   {{- $key := .key }}
235 valueFrom:
236   secretKeyRef:
237     name: {{ include "common.secret.getSecretNameFast" . }}
238     key: {{ $key }}
239 {{- end -}}
240
241 {{/*
242   Define secrets to be used by chart.
243   Every secret has a type which is one of:
244     - generic:
245         Generic secret template that allows to input some raw data (from files).
246         File Input can be passed as list of files (filePaths) or as a single string
247         (filePath)
248     - genericKV:
249         Type of secret which allows you to define a list of key value pairs.
250         The list is assiged to envs value. Every item may define below items:
251           - name:
252               Identifier of this value within secret
253           - value:
254               String that defines a value associated with given key.
255               This can be a simple string or a template.
256           - policy:
257               Defines what to do if value is not provided by the user.
258               Available options are:
259                 - generate:
260                     Generate a value by derriving it from master password
261                 - required:
262                     Fail the deployment
263     - password:
264         Type of secret that holds only the password.
265         Only two items can be defined for this type:
266           - password:
267               Equivalent of value field from genericKV
268           - policy:
269               The same meaning as for genericKV policy field
270     - basicAuth:
271         Type of secret that holds both username and password.
272         Below fields are available:
273           - login:
274               The value for login key.
275               This can be a simple string or a template.
276               Providing a value for login is always required.
277           - password:
278               The value for password key.
279               This can be a simple string or a template.
280           - passwordPolicy:
281               The same meaning as the policy field in genericKV.
282               Only the policy for password can be set.
283
284   Every secret can be identified using:
285     - uid:
286         A string to be appended to the chart fullname to generate a secret name.
287     - name:
288         Overrides default secret name generation and allows to set immutable
289         and globaly unique name
290     - annotations:
291         List of annotations to be used while defining a secret
292
293   To allow sharing a secret between the components and allow to pre-deploy secrets
294   before ONAP deployment it is possible to use already existing secret instead of
295   creating a new one. For this purpose externalSecret field can be used. If value of
296   this field is evaluated to true no new secret is created, only the name of the
297   secret is aliased to the external one.
298
299   Example usage:
300     secrets.yaml:
301       {{ include "common.secret" . }}
302
303     values.yaml:
304       mysqlLogin: "root"
305
306       mysqlExternalSecret: "some-other-secret-name"
307
308       secrets:
309         - uid: "mysql"
310           externalSecret: '{{ tpl .Values.passExternalSecret . }}'
311           type: basicAuth
312           login: '{{ .Values.mysqlLogin }}'
313           mysqlPassword: '{{ .Values.mysqlPassword }}'
314           passwordPolicy: generate
315
316     In the above example new secret is not going to be created.
317     Already existing one (some-other-secret-name) is going to be used.
318     To force creating a new one, just make sure that mysqlExternalSecret
319     is not set.
320
321 */}}
322 {{- define "common.secret" -}}
323   {{- $global := . }}
324   {{- range $secret := .Values.secrets }}
325     {{- $uid := tpl (default "" $secret.uid) $global }}
326     {{- $name := include "common.secret.genName" (dict "global" $global "uid" $uid "name" $secret.name) }}
327     {{- $annotations := default "" $secret.annotations }}
328     {{- $type := default "generic" $secret.type }}
329     {{- $externalSecret := tpl (default "" $secret.externalSecret) $global }}
330     {{- if not $externalSecret }}
331 ---
332       {{ include "common.secret._header" (dict "global" $global "name" $name "annotations" $annotations) }}
333
334       {{- if eq $type "generic" }}
335 data:
336         {{- range $curFilePath := $secret.filePaths }}
337           {{ tpl ($global.Files.Glob $curFilePath).AsSecrets $global | indent 2 }}
338         {{- end }}
339         {{- if $secret.filePath }}
340           {{ tpl ($global.Files.Glob $secret.filePath).AsSecrets $global | indent 2 }}
341         {{- end }}
342       {{- else if eq $type "genericKV" }}
343 stringData:
344         {{- if $secret.envs }}
345           {{- range $secretEnv := $secret.envs }}
346             {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }}
347     {{ $secretEnv.name }}: {{ include "common.secret._value" $valueDesc }}
348           {{- end }}
349         {{- end }}
350       {{- else if eq $type "password" }}
351         {{- $secretEnv := (dict "policy" (default "generate" $secret.policy) "name" "password" "value" $secret.password) }}
352         {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }}
353 stringData:
354   password: {{ include "common.secret._value" $valueDesc }}
355       {{- else if eq $type "basicAuth" }}
356 stringData:
357         {{- $secretEnv := (dict "policy" "required" "name" "login" "value" $secret.login) }}
358         {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }}
359   login: {{ include "common.secret._value" $valueDesc }}
360         {{- $secretEnv := (dict "policy" (default "generate" $secret.passwordPolicy) "name" "password" "value" $secret.password) }}
361         {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }}
362   password: {{ include "common.secret._value" $valueDesc }}
363       {{- end }}
364     {{- end }}
365   {{- end }}
366 {{- end -}}
367
368 {{/*
369   Define secrets to be used by chart.
370   Every secret has a type which is one of:
371     - generic:
372         Generic secret template that allows to input some raw data (from files).
373         File Input can be passed as list of files (filePaths) or as a single string
374         (filePath)
375     - genericKV:
376         Type of secret which allows you to define a list of key value pairs.
377         The list is assiged to envs value. Every item may define below items:
378           - name:
379               Identifier of this value within secret
380           - value:
381               String that defines a value associated with given key.
382               This can be a simple string or a template.
383           - policy:
384               Defines what to do if value is not provided by the user.
385               Available options are:
386                 - generate:
387                     Generate a value by derriving it from master password
388                 - required:
389                     Fail the deployment
390     - password:
391         Type of secret that holds only the password.
392         Only two items can be defined for this type:
393           - password:
394               Equivalent of value field from genericKV
395           - policy:
396               The same meaning as for genericKV policy field
397     - basicAuth:
398         Type of secret that holds both username and password.
399         Below fields are available:
400           - login:
401               The value for login key.
402               This can be a simple string or a template.
403               Providing a value for login is always required.
404           - password:
405               The value for password key.
406               This can be a simple string or a template.
407           - passwordPolicy:
408               The same meaning as the policy field in genericKV.
409               Only the policy for password can be set.
410
411   Every secret can be identified using:
412     - uid:
413         A string to be appended to the chart fullname to generate a secret name.
414     - name:
415         Overrides default secret name generation and allows to set immutable
416         and globaly unique name
417     - annotations:
418         List of annotations to be used while defining a secret
419
420   To allow sharing a secret between the components and allow to pre-deploy secrets
421   before ONAP deployment it is possible to use already existing secret instead of
422   creating a new one. For this purpose externalSecret field can be used. If value of
423   this field is evaluated to true no new secret is created, only the name of the
424   secret is aliased to the external one.
425
426   Example usage:
427     secrets.yaml:
428       {{ include "common.secretFast" . }}
429
430     values.yaml:
431       mysqlLogin: "root"
432
433       mysqlExternalSecret: "some-other-secret-name"
434
435       secrets:
436         - uid: "mysql"
437           externalSecret: '{{ tpl .Values.passExternalSecret . }}'
438           type: basicAuth
439           login: '{{ .Values.mysqlLogin }}'
440           mysqlPassword: '{{ .Values.mysqlPassword }}'
441           passwordPolicy: generate
442
443     In the above example new secret is not going to be created.
444     Already existing one (some-other-secret-name) is going to be used.
445     To force creating a new one, just make sure that mysqlExternalSecret
446     is not set.
447
448 */}}
449 {{- define "common.secretFast" -}}
450   {{- $global := . }}
451   {{- include "common.secret.buildCache" $global }}
452   {{- range $secret := .Values._secretsCache }}
453     {{- $uid := $secret.uid }}
454     {{- $externalSecret := $secret.externalSecret }}
455     {{- if not $externalSecret }}
456       {{- $name := $secret.realName }}
457       {{- $annotations := default "" $secret.annotations }}
458       {{- $type := default "generic" $secret.type }}
459 ---
460       {{ include "common.secret._header" (dict "global" $global "name" $name "annotations" $annotations) }}
461
462       {{- if eq $type "generic" }}
463 data:
464         {{- range $curFilePath := $secret.filePaths }}
465           {{ tpl ($global.Files.Glob $curFilePath).AsSecrets $global | indent 2 }}
466         {{- end }}
467         {{- if $secret.filePath }}
468           {{ tpl ($global.Files.Glob $secret.filePath).AsSecrets $global | indent 2 }}
469         {{- end }}
470       {{- else if eq $type "genericKV" }}
471 stringData:
472         {{- if $secret.envs }}
473           {{- range $secretEnv := $secret.envs }}
474             {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }}
475     {{ $secretEnv.name }}: {{ include "common.secret._valueFast" $valueDesc }}
476           {{- end }}
477         {{- end }}
478       {{- else if eq $type "password" }}
479         {{- $secretEnv := (dict "policy" (default "generate" $secret.policy) "name" "password" "value" $secret.password) }}
480         {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }}
481 stringData:
482   password: {{ include "common.secret._valueFast" $valueDesc }}
483       {{- else if eq $type "basicAuth" }}
484 stringData:
485         {{- $secretEnv := (dict "policy" "required" "name" "login" "value" $secret.login) }}
486         {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }}
487   login: {{ include "common.secret._valueFast" $valueDesc }}
488         {{- $secretEnv := (dict "policy" (default "generate" $secret.passwordPolicy) "name" "password" "value" $secret.password) }}
489         {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }}
490   password: {{ include "common.secret._valueFast" $valueDesc }}
491       {{- end }}
492     {{- end }}
493   {{- end }}
494 {{- end -}}