From ba73e834856db7875a44a6a301ed1224769e78ff Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Sat, 14 Dec 2019 00:22:19 +0100 Subject: Improve common secret template Improve common secret template by adding: - ability to generate secrets if they are not provided - ability to fail the deployment if marked secret is not provided - support for using already existing secret instead of creating a new one Issue-ID: OOM-2053 Change-Id: Ic101f384f7c767702f646eb0e879ec80bf9a6334 Signed-off-by: Krzysztof Opasiak --- kubernetes/common/common/templates/_secret.yaml | 263 ++++++++++++++++++++++-- 1 file changed, 248 insertions(+), 15 deletions(-) diff --git a/kubernetes/common/common/templates/_secret.yaml b/kubernetes/common/common/templates/_secret.yaml index 945530877e..523d7880f0 100644 --- a/kubernetes/common/common/templates/_secret.yaml +++ b/kubernetes/common/common/templates/_secret.yaml @@ -13,14 +13,26 @@ # See the License for the specific language governing permissions and # limitations under the License. */}} -{{- define "common.secret" -}} -{{- $global := . }} -{{- range $secret := .Values.secrets }} ---- + +{{/* + For internal use only! + + Generates a secret header with given name and desired labels. + + The template takes two arguments: + - .global: environment (.) + - .name: name of the secret + + Example call: + {{ include "common.secret._header" (dict "global" . "name" "myFancyName") }} +*/}} +{{- define "common.secret._header" -}} +{{- $global := .global }} +{{- $name := .name }} apiVersion: v1 kind: Secret metadata: - name: {{ tpl $secret.name $global }} + name: {{ $name }} namespace: {{ include "common.namespace" $global }} labels: app: {{ include "common.name" $global }} @@ -28,16 +40,237 @@ metadata: release: {{ $global.Release.Name }} heritage: {{ $global.Release.Service }} type: Opaque +{{- end -}} + +{{/* + For internal use only! + + Pick a value based on "user input" and generation policy. + + The template takes below arguments: + - .global: environment (.) + - .secretName: name of the secret where the value will be placed + - .secretEnv: map of values which configures this secret. This can contain below keys: + - value: Value of secret key provided by user (can be a template inside a string) + - policy: What to do if value is missing or empty. Possible options are: + - generate: Generate a new password deriving it from master password + - required: Fail the deployment if value has not been provided + Defaults to generate. + - name: Name of the key to which this value should be assigned +*/}} +{{- define "common.secret._value" -}} + {{- $global := .global }} + {{- $name := .secretName }} + {{- $secretEnv := .secretEnv }} + {{- $value := tpl $secretEnv.value $global }} + {{- $policy := default "generate" $secretEnv.policy }} + + {{- if $value }} + {{- $value | quote }} + {{- else if eq $policy "generate" }} + {{- include "common.createPassword" (dict "dot" $global "uid" $name) | quote }} + {{- else }} + {{- fail (printf "Value for %s secret %s key not provided" $name $secretEnv.name) }} + {{- end }} +{{- end -}} + + +{{/* + For internal use only! + + Generate a secret name based on provided name or UID. + If UID is provided then the name is generated by appending this UID right after + the chart name. If name is provided, it overrides the name generation algorith + and is used right away. Both name and uid strings may contain a template to be + resolved. + + The template takes below arguments: + - .global: environment (.) + - .uid: string that uniquely identifies this secret within a helm chart + - .name: string that can be used to override default name generation algorithm + and provide a custom name for the secret +*/}} +{{- define "common.secret._genName" -}} + {{- $global := .global }} + {{- $uid := tpl (default "" .uid) $global }} + {{- $name := tpl (default "" .name) $global }} + {{- default (printf "%s-%s" (include "common.fullname" $global) $uid) $name }} +{{- end -}} + +{{/* + Get the real secret name by UID or name, based on the configuration provided by user. + User may decide to not create a new secret but reuse existing one for this deployment + (aka externalSecret). In this case the real name of secret to be used is different + than the one declared in secret definition. This easily retrieve current secret real + name based on declared name or UID even if it has been overrided by the user using + externalSecret option. You should use this template always when you need to reference + a secret created using common.secret template by name. + + The template takes below arguments: + - .global: environment (.) + - .uid: string that uniquely identifies this secret within a helm chart + (can be omitted if name has been provided) + - .name: name which was used to declare a secret + (can be omitted if uid has been provided) +*/}} +{{- define "common.secret.getSecretName" -}} + {{- $global := .global }} + {{- $targetName := include "common.secret._genName" (dict "global" $global "uid" .uid "name" .name) }} + {{- range $secret := $global.Values.secrets }} + {{- $currName := include "common.secret._genName" (dict "global" $global "uid" $secret.uid "name" $secret.name) }} + {{- if eq $currName $targetName }} + {{- $externalSecret := tpl (default "" $secret.externalSecret) $global }} + {{- default $currName $externalSecret }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* + Convenience template which can be used to easily set the value of environment variable + to the value of a key in a secret. + + It takes care of all name mangling, usage of external secrets etc. + + The template takes below arguments: + - .global: environment (.) + - .uid: string that uniquely identifies this secret within a helm chart + (can be omitted if name has been provided) + - .name: name which was used to declare a secret + (can be omitted if uid has been provided) + - .key: Key within this secret which value should be assigned to this variable + + Example usage: + env: + - name: SECRET_PASSWORD + {{- include "common.secret.envFromSecret" (dict "global" . "uid" "secret" "key" "password") | indent 8}} +*/}} +{{- define "common.secret.envFromSecret" -}} + {{- $key := .key }} +valueFrom: + secretKeyRef: + name: {{ include "common.secret.getSecretName" . }} + key: {{ $key }} +{{- end -}} + +{{/* + Define secrets to be used by chart. + Every secret has a type which is one of: + - generic: + Generic secret template that allows to input some raw data (from files). + File Input can be passed as list of files (filePaths) or as a single string + (filePath) + - genericKV: + Type of secret which allows you to define a list of key value pairs. + The list is assiged to envs value. Every item may define below items: + - name: + Identifier of this value within secret + - value: + String that defines a value associated with given key. + This can be a simple string or a template. + - policy: + Defines what to do if value is not provided by the user. + Available options are: + - generate: + Generate a value by derriving it from master password + - required: + Fail the deployment + - password: + Type of secret that holds only the password. + Only two items can be defined for this type: + - password: + Equivalent of value field from genericKV + - policy: + The same meaning as for genericKV policy field + - basicAuth: + Type of secret that holds both username and password. + Below fields are available: + - login: + The value for login key. + This can be a simple string or a template. + Providing a value for login is always required. + - password: + The value for password key. + This can be a simple string or a template. + - passwordPolicy: + The same meaning as the policy field in genericKV. + Only the policy for password can be set. + + Every secret can be identified using: + - uid: + A string to be appended to the chart fullname to generate a secret name. + - name: + Overrides default secret name generation and allows to set immutable + and globaly unique name + + To allow sharing a secret between the components and allow to pre-deploy secrets + before ONAP deployment it is possible to use already existing secret instead of + creating a new one. For this purpose externalSecret field can be used. If value of + this field is evaluated to true no new secret is created, only the name of the + secret is aliased to the external one. + + Example usage: + secrets.yaml: + {{ include "common.secret" . }} + + values.yaml: + mysqlLogin: "root" + + mysqlExternalSecret: "some-other-secret-name" + + secrets: + - uid: "mysql" + externalSecret: '{{ tpl .Values.passExternalSecret . }}' + type: basicAuth + login: '{{ .Values.mysqlLogin }}' + mysqlPassword: '{{ .Values.mysqlPassword }}' + passwordPolicy: generate + + In the above example new secret is not going to be created. + Already existing one (some-other-secret-name) is going to be used. + To force creating a new one, just make sure that mysqlExternalSecret + is not set. + +*/}} +{{- define "common.secret" -}} + {{- $global := . }} + {{- range $secret := .Values.secrets }} + {{- $name := include "common.secret._genName" (dict "global" $global "uid" $secret.uid "name" $secret.name) }} + {{- $type := default "generic" $secret.type }} + {{- $externalSecret := tpl (default "" $secret.externalSecret) $global }} + {{- if not $externalSecret }} +--- + {{ include "common.secret._header" (dict "global" $global "name" $name) }} + + {{- if eq $type "generic" }} data: -{{- range $curFilePath := $secret.filePaths }} -{{ tpl ($global.Files.Glob $curFilePath).AsSecrets $global | indent 2 }} -{{- end }} -{{- if $secret.filePath }} -{{ tpl ($global.Files.Glob $secret.filePath).AsSecrets $global | indent 2 }} -{{- else if $secret.envs }} - {{- range $secretEnv := $secret.envs }} - {{ $secretEnv.name }}: {{ tpl $secretEnv.value $global }} + {{- range $curFilePath := $secret.filePaths }} + {{ tpl ($global.Files.Glob $curFilePath).AsSecrets $global | indent 2 }} + {{- end }} + {{- if $secret.filePath }} + {{ tpl ($global.Files.Glob $secret.filePath).AsSecrets $global | indent 2 }} + {{- end }} + {{- else if eq $type "genericKV" }} +stringData: + {{- if $secret.envs }} + {{- range $secretEnv := $secret.envs }} + {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }} + {{ $secretEnv.name }}: {{ include "common.secret._value" $valueDesc }} + {{- end }} + {{- end }} + {{- else if eq $type "password" }} + {{- $secretEnv := (dict "policy" (default "generate" $secret.policy) "name" "password" "value" $secret.password) }} + {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }} +stringData: + password: {{ include "common.secret._value" $valueDesc }} + {{- else if eq $type "basicAuth" }} +stringData: + {{- $secretEnv := (dict "policy" "required" "name" "login" "value" $secret.login) }} + {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }} + login: {{ include "common.secret._value" $valueDesc }} + {{- $secretEnv := (dict "policy" (default "generate" $secret.passwordPolicy) "name" "password" "value" $secret.password) }} + {{- $valueDesc := (dict "global" $global "secretName" $name "secretEnv" $secretEnv) }} + password: {{ include "common.secret._value" $valueDesc }} + {{- end }} + {{- end }} {{- end }} -{{- end }} -{{- end }} {{- end -}} -- cgit 1.2.3-korg