Helm-secrets插件通过GPG/Age等后端加密敏感配置,支持在Helmfile中用fetchSecretValue或expandSecretRefs安全解密并注入,确保密文可提交Git、解密可控且与部署流程自然集成。

不能直接把敏感值写进 values.yaml 提交到 Git —— 即使 Base64 编码也不行,那只是编码,不是加密。 Helm-secrets 插件真正起作用的地方,是让加密后的密文可安全提交、解密过程可控且与 Helmfile 流程自然集成。
helm-secrets 插件安装与 GPG 密钥准备
插件本身不自带密钥,必须提前配置好加解密后端。GPG 是最常用也最稳妥的选择,尤其适合已有团队 GPG 基础设施的场景。
- 确保
gpg已安装并有可用的私钥(gpg --list-secret-keys可验证) - 运行
helm plugin install https://github.com/jkroepke/helm-secrets安装插件 - 插件默认使用
gpg --decrypt,无需额外配置;若用 Age,则需单独安装age并设置HELM_SECRETS_BACKEND=age - 注意:CI/CD 环境中必须导入对应私钥(如 GitHub Actions 需用
gpg --import+ secrets 注入),否则helmfile sync会卡在解密环节
加密 values 文件并纳入 Helmfile 流程
敏感值不放在明文 values.yaml 中,而是单独存为 secrets.yaml.age 或 secrets.yaml.gpg,由 helm-secrets 自动识别并解密。
- 加密命令示例:
helm secrets enc secrets.yaml→ 生成secrets.yaml.age - Helmfile 中引用时仍写
values: [secrets.yaml],插件会自动匹配后缀并调用解密命令 - 不要手动修改加密后文件内容,哪怕只改一个空格,
helm secrets dec也会失败 - Git 提交的是
secrets.yaml.age,不是原始secrets.yaml;后者应加入.gitignore
在 Helmfile 中安全注入密钥值
模板里不能直接写 {{ .Values.db.password }} —— 这会导致未解密的密文被渲染进 Chart,或触发运行时错误。必须用插件提供的函数做显式解密或透传。
- 单字段解密:
password: {{ .Values.db.password | fetchSecretValue | quote }} - 整块结构展开:
{{ .Values.db | expandSecretRefs | toYaml | nindent 2 }} -
fetchSecretValue会在 Helm 渲染前调用helm secrets dec解密该字段;expandSecretRefs则对整个 map 递归处理 - 如果某字段没被加密(比如
replicaCount),fetchSecretValue会原样返回,不会报错 - 注意:这两个函数只在
helmfile template或sync时生效,helm template原生命令不识别它们
CI/CD 中解密失败的常见原因
本地能跑通,流水线却卡住,90% 是环境差异导致的解密链断裂。
- GPG 私钥未导入,或权限不对(
~/.gnupg目录需0700,私钥文件需0600) - CI 使用的用户和 GPG keyring 所属用户不一致(如 runner 以
gitlab-runner用户运行,但 key 导入在root下) - Age 密钥未正确设置
AGE_KEY_FILE环境变量,或密钥格式不匹配(如用了 SSH 私钥但未转成 Age 格式) - helm-secrets 插件版本与 Helm 版本不兼容(例如 Helm v3.14+ 需要 helm-secrets v4.0+)
最易被忽略的一点:helm-secrets 的解密发生在 Helmfile 渲染阶段,而不是 Kubernetes API 层;它不接触集群,纯粹是本地 YAML 处理。这意味着所有加密逻辑必须在部署机上闭环完成,无法靠集群内控制器补救。











