☰
Flux 提供自有 SSH 密钥完整指南:用你的 Git 部署密钥替代 Flux 自动生成的 identity
2026/10/15 15:03:35 网站建设 项目流程
  • 云原生
  • DevOps
  • 容器编排
  • 运维

【免费下载链接】flux

Successor: https://github.com/fluxcd/flux2

项目地址:https://gitcode.com/gh_mirrors/flu/flux
点击查看免费下载

Flux 通过从 Kubernetes Secret 中读取 SSH 私钥来连接 Git 仓库;当被配置的 Secret 中没有identity数据项时,它才会自动生成新的私钥。本篇指南基于 provide-own-ssh-key.md 展开,完整讲解如何把你自己生成的 Git 仓库部署密钥(Deploy Key)交给 Flux 使用:从创建 Secret、调整--k8s-secret-name参数,到 Helm 与原生 Manifest 两种部署方式的配置,并结合仓库源码剖析密钥环(KeyRing)的加载与再生成原理。读完后你将能自主掌控 Flux 的 Git 身份,而不是被动使用 Flux 自动生成的密钥。

Flux 的 SSH 密钥机制:先读 Secret,没有才自动生成

Flux(fluxd守护进程)启动后,会从 Kubernetes Secret 中获取连接 Git 仓库所需的 SSH 私钥。其核心规则如下:

  • 通过--k8s-secret-name指定要读取的 Secret 名称(默认flux-git-deploy);
  • 若该 Secret 中存在identity键值对(数据项),Flux 直接使用其中存放的私钥,不会重新生成;
  • 若 Secret 中没有identity数据项,Flux 会调用ssh-keygen生成一对新的密钥,并将私钥写回该 Secret。

这一逻辑在 sshkeyring.go 的NewSSHKeyRing中实现得十分直观:它检查挂载路径下是否存在私钥文件,文件不存在则执行Regenerate();文件存在但权限不是0400则先尝试chmod修正,随后通过ssh.ExtractPublicKey提取出对应的公钥。

由此得出一个关键结论:提供自己的 SSH 密钥,本质上就是按照 Flux 期望的格式创建一个 Secret,把私钥放到identity数据项里即可,Flux 会自动"接管"并一直使用它。

第一步:准备你的私钥

你既可以使用现有环境里已生成的 SSH 私钥,也可以临时生成一对新密钥。若选择现成密钥,直接跳到下一步;若想生成专用部署密钥,可参考 values.yaml 中给出的做法:

ssh-keygen -q -N "" -f ./identity

这会在当前目录生成无口令(-N "")的私钥文件identity和公钥文件identity.pub。注意两个细节:

  • Flux 期望私钥数据项名为identity,因此生成时请保持文件名一致,或用--from-file=identity=...显式指定;
  • 不要把私钥提交进 Git 仓库,创建完 Kubernetes Secret 后应立即删除本地的私钥文件(保留identity.pub用于配置部署密钥)。

第二步:创建 Kubernetes Secret(核心操作)

将私钥内容写入 Kubernetes Secret:

kubectl create secret generic flux-git-deploy --from-file=identity=/full/path/to/private_key

其中/full/path/to/private_key替换为你的私钥绝对路径。命令执行后,得到的 Secret 结构如下:

apiVersion: v1 data: identity: <base64 encoded RSA PRIVATE KEY> kind: Secret type: Opaque metadata: ...

等价地,也可以直接编写一个 YAML 文件提交,效果相同。仓库里的占位示例 flux-secret.yaml 展示了该 Secret 的基础骨架(name: flux-git-deploy、type: Opaque,data 部分由你填充)。

创建完成后,把对应的公钥identity.pub添加到 Git 平台(GitHub/GitLab/Gitea 等)的 Deploy Key 中,并授予写权限——原因见下文"权限要求"一节。

第三步(可选):使用非默认的 Secret 名称

Flux 默认读取名为flux-git-deploy的 Secret。如果你创建 Secret 时使用了其他名称,需要给fluxd进程显式指定,例如:

--k8s-secret-name=foo

这条参数的定义位于 main.go,完整相关参数如下表:

参数默认值说明
--k8s-secret-nameflux-git-deploy存放 SSH 私钥的 Kubernetes Secret 名称
--k8s-secret-volume-mount-path/etc/fluxd/sshSecret 在容器内的挂载路径
--k8s-secret-data-keyidentitySecret 内保存私钥的数据项键名
--ssh-keygen-dir空(回退到挂载路径)生成新密钥时使用的目录,建议为 tmpfs 卷

这些参数同时记录在 daemon.md 的fluxd参数参考表中。

通过 Helm Chart 部署时如何指定自有密钥

使用 Helm 安装 Flux 时,在values.yaml中设置git.secretName即可绕过默认 Secret:

git: secretName: "flux-ssh" secretDataKey: "" # 若私钥数据项名不是 identity,可在此覆盖
  • git.secretName:填入你自建 Secret 的名称。设置后,模板不再创建默认的<release>-git-deploySecret(见 secret.yaml),并把它挂载为git-key卷(见 deployment.yaml);
  • git.secretDataKey:如果--from-file指定的源文件名不是identity,Flux 默认仍会去读名为identity的数据项,此时需要设置此值对齐。模板中会据此生成--k8s-secret-data-key参数(见 deployment.yaml)。

对应地,模板会生成--k8s-secret-name={{ .Values.git.secretName | default ... }}参数,把 Helm 值与fluxd的启动参数串起来。

原生 Manifest / Kustomize 部署方式

使用 deploy/ 下的原生 Manifest 部署时,同样只需两处配合:

  1. 创建你自己的 Secret(参考上文的kubectl create secret generic命令);
  2. 在 flux-deployment.yaml 中把卷git-key的secretName改为你的 Secret 名称,或通过--k8s-secret-name参数指定。

部署清单中还有一个容易被忽略的关键点:私钥卷以defaultMode: 0400且只读(readOnly: true)方式挂载到/etc/fluxd/ssh,而密钥生成目录git-keygen使用emptyDir的内存介质挂载到/var/fluxd/keygen,并通过--ssh-keygen-dir=/var/fluxd/keygen传入。这正对应源码中"私钥文件权限必须是 0400,否则 ssh 拒绝使用"以及"生成密钥需写入 tmpfs"的设计(见下节)。

源码级原理:密钥环如何发现并接管你的密钥

理解 KeyRing 的加载分支,就能明白为什么"创建好 Secret 就万事大吉"。

启动加载。NewSSHKeyRing(sshkeyring.go)在初始化时执行:

  • 检查SecretVolumeMountPath+SecretDataKey拼接出的私钥文件是否存在;
  • 不存在:说明 Secret 里没有可用的identity,调用Regenerate()生成新密钥(此时"提供自有密钥"未生效,Flux 走的仍是自动生成路径);
  • 存在但权限 ≠ 0400:尝试chmod修正(只读挂载下可能失败,这就是为什么defaultMode: 0400要在卷层面就设好);
  • 存在且权限正确:直接用该文件,并通过ssh-keygen -y提取公钥(keygen.go),同时计算 md5 与 sha256 指纹。

privateKeyFileMode = os.FileMode(0400)这一硬性要求定义在 sshkeyring.go。

自动生成路径。当 Secret 中没有identity时,Regenerate()(sshkeyring.go)会:

  1. 调用ssh.KeyGen(keygen.go),在--ssh-keygen-dir指向的 tmpfs 目录里执行ssh-keygen -q -N "" -f ...生成密钥对——私钥不落盘到持久存储;
  2. 把新私钥与公钥分别 base64 编码,通过 Strategic Merge Patch 写回 Kubernetes Secret 的identity与identity.pub数据项;
  3. 用符号链接完成原子切换,使当前进程立即使用新密钥。

这也是"查看 Flux 日志能 grep 到identity.pub"的来源:main.go 在启动时会把公钥打印到日志,供你复制后配置到 Git 平台。

验证你的密钥已被使用

部署完成后,可以从三个角度确认 Flux 正在使用你提供的密钥:

  1. fluxctl 查看公钥:fluxctl identity(identity_cmd.go)会输出当前密钥的公钥。对比该值与你的identity.pub,一致即说明自有密钥已生效;若不一致,说明 Secret 未被正确创建或被忽略。fluxctl identity --regenerate可强制重新生成。
  2. 容器日志:kubectl logs deploy/flux | grep identity.pub | cut -d '"' -f2,输出即为当前公钥。
  3. HTTP 接口:Flux 暴露了GET /v6/identity.pub与POST /v6/identity.pub两个路由(transport.go),其中 GET 用于读取公钥、POST 用于触发再生成。该端点同时被用作存活/就绪探针(见 flux-deployment.yaml)。

权限要求:必须能创建并更新标签

⚠ 注意:提供给 Flux 的 SSH 密钥必须对仓库具有读/写(R/W)访问权限。更具体地说,密钥必须能够创建和更新 Git 标签(tag)。

原因是 Flux 默认通过向仓库打一个特殊的同步标签(如flux-sync)来记录同步进度。举 GitLab 的例子:这要求密钥拥有Maintainer权限——Developer权限虽然可以创建标签,但无法更新已存在的标签,会导致后续同步失败。

在其他平台(GitHub 等)配置 Deploy Key 时,请务必勾选写权限(Write access),并在首次添加公钥前确认标签的读写行为与你的 Git 托管平台一致。

常见问题与安全提醒

  • Flux 仍在自动生成密钥?检查 Secret 的data.identity是否确实存在且为完整私钥(-----BEGIN RSA PRIVATE KEY-----开头);检查--k8s-secret-name与 Secret 实际名称、命名空间是否一致。
  • 同步报权限错误?按上节确认密钥具备 R/W 与标签更新能力,并将公钥正确配置为 Deploy Key。
  • 私钥被拒绝使用?确认卷的defaultMode: 0400,因为 ssh 会拒绝权限过宽的私钥文件;只读挂载下 Flux 无法自行chmod。
  • 安全提醒:Flux 生成的私钥不加密(-N ""),因此特意要求写入 tmpfs;你自备密钥时同样应遵循最小暴露原则——私钥只存在于 Secret 中,本地文件在创建 Secret 后删除,公钥则单独维护。

最后提示:本文所述为 Flux(v1)的机制,该版本已于 2022 年 11 月停止维护,其演进项目为 Flux v2;若在新项目中使用,请优先参考 Flux v2 的迁移与配置方式。

  • 云原生
  • DevOps
  • 容器编排
  • 运维

【免费下载链接】flux

Successor: https://github.com/fluxcd/flux2

项目地址:https://gitcode.com/gh_mirrors/flu/flux
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询