【问题标题】:How not to overwrite randomly generated secrets in Helm templates如何不覆盖 Helm 模板中随机生成的秘密
【发布时间】:2019-10-03 19:41:13
【问题描述】:

我想在 Helm 模板中生成密码,使用 randAlphaNum 函数很容易做到这一点。但是,当版本升级时,密码将被更改。有没有办法检查之前是否生成了密码,然后使用现有值?像这样的:

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 }}

【问题讨论】:

  • 从外部生成和传递秘密

标签: kubernetes passwords kubernetes-helm


【解决方案1】:

这仍然是 Helm 最大的问题之一。据我了解,目前还没有好的解决方案(请参阅https://github.com/helm/charts/issues/5167)。

一个肮脏的解决方法是create secret as pre-install hook。这种方法的明显缺点是在 helm delete 时不会删除 secret。

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 }}

【讨论】:

  • 我对预安装挂钩有疑问。如果您将新图表添加到需求中,这需要新的秘密怎么办?那么您正在使用 helm upgrade ,而不是 helm install ...它看起来根本没有合理的方法可以将生成的密码与 helm 一起使用(这让我想知道,为什么他们在第一行添加了生成随机密码的功能)。
  • Helm 也支持升级前挂钩。
  • 是的,这个魅力已经用了好几年了
【解决方案2】:

如果秘密已经存在,您可以使用lookup function 并跳过生成:

{{- if not (lookup "v1" "secret" .Release.Namespace "db-details") -}}
<create secret here>
{{- end -}}

【讨论】:

  • 我喜欢这个主意。有理由使用lookup 而不是Release.IsUpgrade 吗?
  • 嗯...好吧——假设升级实际上添加了秘密?你可以解决这个问题,但也许这更简单。
  • 其实这个方法并没有达到预期的效果。正如@jan-dubois 在下面的回答中正确指出的那样,如果秘密已经存在,则会在升级时删除。
【解决方案3】:

这里有点晚了,大多数人可能只是在文档中发现它:

helm 使用注释 "helm.sh/resource-policy": keep 为您完成此操作

见:

https://helm.sh/docs/howto/charts_tips_and_tricks/#tell-helm-not-to-uninstall-a-resource

【讨论】:

    【解决方案4】:

    您可以基于shaunc 的想法使用lookup 函数来修复原始海报的代码,如下所示:

    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 }}
    

    仅在 Secret 尚不存在时创建它是行不通的,因为 Helm 将删除升级期间不再定义的对象。

    使用注解来保留对象的缺点是当你用helm delete ...删除释放时它不会被删除。

    【讨论】:

    • 虽然我确实喜欢这种方法,但它似乎不适用于 helm linthelm templatehelm --dry-run,因为它不(也不应该)联系 Kubernetes API服务器来获取现有的秘密。 docs 声明“在这种情况下,lookup 函数将返回一个空列表(即 dict)”。这会导致“nil 指针评估接口”(在没有 index 的情况下调用时)或在使用 index 调用时出现“错误调用索引:无类型 nil 的索引”。想法?
    • @riha 我猜在helm lint.Release 中的所有字段都没有设置,所以简单的解决方法是将if .Release.IsInstall 替换为if not .Release.IsUpdate(好吧,避免否定和交换两个分支,但你明白我的意思)。此更改也应该有助于helm template
    • 对不起,不能再编辑评论了;应该是if not .Release.IsUpgrade
    • 我带着一个作业和一个条件去了。 {{- $data := (lookup ...).data -}},然后是 {{- if $data }}。另一方面:ConfigMaps 似乎是另一回事。当在 Helm 升级运行中完全省略键,但存在于集群上现有的 ConfigMap 对象中时,它们保持不变。
    【解决方案5】:

    我重写了 kubernetes 复制器并添加了一些注解来处理此类问题:https://github.com/olli-ai/k8s-replicator#use-random-password-generated-by-an-helm-chart

    现在可以使用 helm 生成一个随机密码,并且只将其复制一次到另一个 secret,因此以后不会被 helm 更改。

    apiVersion: v1
    kind: Secret
    type: Opaque
    metadata:
      name: admin-password-source
      annotations:
        k8s-replicator/replicate-to: "admin-password"
        k8s-replicator/replicate-once: "true"
    stringData:
      password: {{ randAlphaNum 64 | quote }}
    

    希望对大家有所帮助。

    【讨论】:

      【解决方案6】:

      Jan Duboisshaunc 的答案给我带来了很多麻烦。所以我构建了一个组合解决方案。

      简回答的缺点:与--dry-run 一起使用时会导致错误。
      shaunc 回答的缺点:它不会起作用,因为资源将在helm upgrade 上被删除。

      这是我的代码:

      # 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 }}
      

      【讨论】:

        【解决方案7】:

        基于shaunc 使用lookup 函数的想法,我创建了以下模板:

        {{/*
        Returns a secret if it already in Kubernetes, otherwise it creates
        it randomly.
        */}}
        {{- define "getOrGeneratePass" }}
        {{- $len := (default 16 .Length) | int -}}
        {{- $obj := (lookup "v1" .Kind .Namespace .Name).data -}}
        {{- if $obj }}
        {{- index $obj .Key -}}
        {{- else if (eq (lower .Kind) "secret") -}}
        {{- randAlphaNum $len | b64enc -}}
        {{- else -}}
        {{- randAlphaNum $len -}}
        {{- end -}}
        {{- end }}
        

        然后您可以简单地配置秘密,例如:

        ---
        apiVersion: v1
        kind: Secret
        metadata:
          name: my-secret
        type: Opaque
        data:
          PASSWORD: "{{ include "getOrGeneratePass" (dict "Namespace" .Release.Namespace "Kind" "Secret" "Name" "my-secret" "Key" "PASSWORD") }}"
        

        【讨论】:

          【解决方案8】:

          实际的工具都在这里。我的解决方法只是建议工具的另一种组合

          {{- if not (lookup "v1" "Secret" .Release.Namespace "mysecret") }}
          apiVersion: v1
          kind: Secret
          metadata:
            name: mysecret
            annotations:
              "helm.sh/resource-policy": "keep"
          type: Opaque
          stringData:
            password: {{ randAlphaNum 24 }}
          {{- end }}
          

          所以如果没有这样的秘密,它就会被创造出来。如果秘密存在,它将从图表中删除,但不会从集群中删除,"helm.sh/resource-policy": "keep" 将阻止它。

          你可能会问(就像上面有人已经做过的那样)为什么是lookup,而不是.Release.IsUpdate。想象一下这种情况:您的秘密是数据库的密码。您将数据保存在持久卷中,其声明也由"helm.sh/resource-policy": "keep" 注释,因此即使您卸载并重新安装图表,数据也会保留。如果您以.Release.IsUpdate 为条件这样做,那么您的密码将被重新创建,旧密码将丢失,您将失去对数据的访问权限。如果你查询秘密存在,它不会发生。

          【讨论】:

            【解决方案9】:

            您可以利用 _helpers.tpl 中的定义

            _helpers.tpl

            {{/*
            Create the secret name
            */}}
            {{- define "mssql-server.secretName" -}}
            {{- include "mssql-server.name" . }}-mssql-secret
            {{- end }}
            
            {{/*
            Get sa password value
            */}}
            {{- define "mssql-server.sapassword" -}}
            {{- if .Release.IsInstall -}}
            {{ .Values.sa_password | default (randAlphaNum 20) | b64enc | quote }}
            {{- else -}}
            {{ index (lookup "v1" "Secret" .Release.Namespace (include "mssql-server.secretName" .)).data "sa_password" }}
            {{- end }}
            {{- end }}
            

            secret.yaml

            apiVersion: v1
            kind: Secret
            metadata:
              name: {{ include "mssql-server.secretName" . }}
              labels:
                {{- include "mssql-server.labels" . | nindent 4 }}
            type: Opaque
            data:
              sa_password: {{ include "mssql-server.sapassword" . }}
            

            【讨论】:

              猜你喜欢
              • 2021-12-02
              • 1970-01-01
              • 2019-10-03
              • 1970-01-01
              • 2021-02-04
              • 2018-11-01
              • 1970-01-01
              • 2016-08-13
              • 1970-01-01
              相关资源
              最近更新 更多