ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Argo CD Source Verification Policies:基于 Git/GPG 的源码完整性验证体系深度解析

Argo CD Source Verification Policies:基于 Git/GPG 的源码完整性验证体系深度解析 Argo CD Source Verification Policies基于 Git/GPG 的源码完整性验证体系深度解析【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cdSource Verification PoliciesSVP源码验证策略是 Argo CD 对传统 GnuPG 提交签名验证机制的演进式设计它把签名验证从项目级的一刀切约束细化为按源码仓库、按验证严格度的多策略体系并为未来接入 Helm provenance、sigstore 等更多验证方法预留了扩展空间。本文以 docs/proposals/source-verification-policies.md 提案为核心骨架结合 pkg/apis/application/v1alpha1/source_integrity.go、util/sourceintegrity/source_integrity.go 等仓库实现与官方用户指南系统讲解策略结构、none/head/strict三种验证模式、策略匹配顺序、密钥管理、seal 提交以及升级迁移的完整方法论。一、背景与动机为什么需要源码验证策略作为部署工具Argo CD 处于实施供应链安全要求的关键位置。对来源与制品的密码学验证对组织越来越重要且在部分行业受到严格监管。Argo CD 很早就通过 GnuPG 提供对 Git 提交的 OpenPGP 签名验证能力但该特性存在明显局限只验证 HEADArgo CD 仅验证Application解析后的targetRevision所指向的HEAD提交签名这不足以满足许多组织对整条历史都被签名的要求。All-or-Nothing 模式验证对任意给定AppProject是全有或全无的无法对不同仓库施加不同的信任等级。不同仓库可能有不同的贡献者集合、不同的签名/贡献规范。无法细分多源应用多源应用出现后为项目所有仓库/应用统一配置可信签名者的方式缺乏灵活性。SVP 正是针对这些问题而生它引入了新的验证模式、允许同一 Application 中的多个源码使用不同严格度的策略并为此后实现更多非 GPG、非 Git 专属的验证方法奠定基础。目标Goals提升 Git 提交验证的置信度基于源码仓库管理签名者信任比基于应用项目更细粒度具备足够的灵活性以支持未来的其他验证提供方如 Helm provenance、sigstore 签名的 Git 等让用户易于迁移到更安全的验证策略与现有 GnuPG 提交验证机制完全向后兼容。非目标Non-Goals不实现 GnuPG 之外的 Git 提交验证方法——这可能留待以后而 SVP 的设计本身已允许这些方法较容易地集成进来。二、核心概念Source Verification Policy 的配置结构SVP 配置在AppProject的.spec.sourceIntegrity字段下示意结构如下取自 docs/proposals/source-verification-policies.mdapiVersion: argoproj.io/v1alpha1 kind: AppProject spec: sourceIntegrity: # 超出当前范围此处仅演示声明结构允许未来扩展到不同来源类型 # helm: {} git: policies: - repos: - url: https://github.com/foo/* gpg: mode: none|head|strict keys: - 0xDEAD - 0xBEEF在仓库中这一结构被实现在 pkg/apis/application/v1alpha1/source_integrity.goSourceIntegrity顶层结构当前只包含git字段在出现替代方案之前是必填字段SourceIntegrityGit持有policies策略列表SourceIntegrityGitPolicy一条策略由repos仓库匹配条件与gpg验证方法当前唯一受支持方法同样为必填构成SourceIntegrityGitPolicyRepo单一 URL 匹配模式SourceIntegrityGitPolicyGPG验证模式与可信密钥列表。type SourceIntegrityGitPolicyGPG struct { Mode SourceIntegrityGitPolicyGPGMode json:mode protobuf:bytes,1,namemode // List of key IDs to trust. The keys need to be in the repository server keyring. Keys []string json:keys protobuf:bytes,3,namekeys }策略的 repos 匹配规则repos是与待验证源码 URL 进行匹配的 glob 风格模式列表。当模式匹配到某个源时该源会被验证否则跳过对该源的验证。用户指南 docs/user-guide/source-integrity-git-gpg.md 进一步明确了实际实现中的匹配语义repos可以同时包含正向 glob 与以!开头的负向 glob排除模式当 URL 匹配任一正向 glob 且不被任何负向 glob 匹配时该策略生效spec: sourceIntegrity: git: policies: - repos: - url: https://github.com/my-group/* - url: !https://github.com/my-group/ignored.git gpg: mode: none|head|strict keys: - D56C4FCA57A46444对应源码在 util/sourceintegrity/source_integrity.go 的findMatchingGitPolicies与repoMatches函数中正向模式命中返回 1include!前缀的负向模式命中返回 -1排除并中断否则返回 0。GPG 验证策略目前 GPG 是唯一受支持的验证方法它使用 GnuPG 验证 Git 提交上的 PGP 签名本质上是带配置密钥环调用git verify-commit/git verify-tag并确保签名使用的密钥 ID 位于策略声明的可信密钥 ID 列表内见 docs/user-guide/source-integrity-git-gpg.md 及 util/sourceintegrity/source_integrity.go 的verify函数。关于keys的要点keys列出用于签名提交的可信密钥 ID 集合若提交由列表中未出现的 ID 签名验证将失败若未配置任何可信密钥则信任argocd-gpg-keys-cmConfigMap 中的所有签名者除了将密钥 ID 列入白名单密钥本身还必须通过既有机制导入 Argo CD导入仓库服务器密钥环从源码实现看还支持签名子密钥自动解析回主密钥当 git 使用子密钥签名而策略中列出的是主密钥时gpgProblemMessage会通过lookupPrimaryKeyID将 16 位短密钥 ID 解析为主密钥再判断是否允许util/sourceintegrity/source_integrity.go。mode定义 GPG 验证的严格程度其类型常量在 pkg/apis/application/v1alpha1/source_integrity.go 中定义mode含义源码注释要点none不执行任何 GPG 验证对排障场景有用head验证目标修订所指向的 HEAD 提交对注解标签验证标签签名strict验证目标修订的全部祖先提交直至 git init 或 seal 提交若指向注解标签同时验证标签签名与提交历史三、验证模式详解以一个简单的修订历史为例见 docs/proposals/source-verification-policies.mdHEAD 1.0 2.0 | | A---B---C---D---E---F - - - 其中A到F是构成仓库历史的提交1.0与2.0是分别指向对应提交的注解标签。HEAD指向F即2.0。/-表示提交或标签是否由可信密钥签名——提交D、E、F已签名两个标签也已签名。模式none此模式下Application 可以同步上述任意修订无论源上是否存在有效签名。不执行验证。需要注意none模式不仅接受未签名提交也接受某种意义上有缺陷的签名过期、不可验证等的提交见 docs/user-guide/source-integrity-git-gpg.md。模式head若targetRevision指向提交A、B或C将不被信任未签名指向D、E或F则被信任指定HEAD命名分支的尖端、1.0或2.0会成功验证HEAD因指向的修订已签名1.0/2.0因是签名标签。实际语义上若修订是注解标签则验证标签本身签名标签必须通过git tag -s签名否则若目标是分支名、引用名如HEAD或提交 SHAArgo CD 验证提交的 GnuPG 签名。这一点在 util/git/client.go 的LsSignatures中体现当修订是注解标签且deep为 false 时仅返回标签签名。模式strict严格模式不会信任该 git 历史的任何一点因为历史包含未签名的提交A、B和C。它验证目标修订及其全部祖先确保历史上不存在任何未签名变更若修订为注解标签标签签名与提交历史含其指向的提交一并验证。四、策略顺序的意义与多源应用策略是非累积的每个源码仓库只应用一条策略因此定义的顺序非常重要。多源应用的各源码仓库可分别基于不同的 SVP 进行验证Argo CD 选择第一条匹配仓库源 URL 的策略并忽略其后任何策略策略自上而下求值因此更具体的策略必须放在更宽泛的策略之前。示例来自 docs/proposals/source-verification-policies.md希望验证来自github.com的所有仓库的提交都带有 GitHub web 签名密钥的有效签名但对某个特定仓库施加不同的策略——使用strict模式并额外允许另一个签名者。正确写法是具体策略在前、宽泛策略在后apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: gpg namespace: argocd spec: sourceIntegrity: git: policies: - repos: - url: https://github.com/example/super-secure gpg: mode: strict keys: - 4AEE18F83AFDEB23 - D56C4FCA57A46444 - repos: - url: https://github.com/* gpg: mode: head keys: - 4AEE18F83AFDEB23若顺序颠倒https://github.com/example/super-secure的专用策略永远不会被匹配因为该 URL 已被https://github.com/*模式匹配宽泛策略会被应用。从源码看这种多策略匹配即视为配置错误的行为有防御性设计lookupGit中若发现同一仓库匹配多条策略会返回一个必然失败的检查结果以确保配置错误不会静默关闭验证util/sourceintegrity/source_integrity.go。这与提案中自上而下取第一条的规则互为补充——正常情况下应只匹配一条多匹配属于需要告警的异常。提案还指出Argo CD CLI 与 UI 需要提供视觉指示标出未执行 GPG 验证的项目仓库为管理员提供仓库匹配求值的反馈。五、源码级纵深从策略声明到签名验证的调用链SVP 的实际执行横跨多个模块理解调用链有助于排障与二次开发策略求值入口util/sourceintegrity/source_integrity.go 的VerifyGit依据 git client 的RepoURL()查找到期匹配的策略找不到时返回空跳过验证HasCriteria则判断任一源是否声明了相关标准排除 OCI 与 Helm 源。GPG 验证开关IsGPGEnabled()读取环境变量ARGOCD_GPG_ENABLED当其值为false/no不区分大小写时返回 falseutil/sourceintegrity/source_integrity.go。策略中 GPG 验证方法可通过该环境变量整体停用。底层 git 操作verify调用gitClient.LsSignatures(ctx, verifiedRevision, deep)util/git/client.go该函数先解析语义化版本标签约束如v1.0.x到具体标签通过VerifyCommitSignature获得兼容 legacy 行为的描述字符串用于signatureKeys兼容路径若目标是注解标签读取标签签名非 deep 模式就此返回通过git rev-list列出提交签名信息CSV 形式构造RevisionSignatureInfo列表。问题描述与结果describeProblems汇总最多 10 条最近的问题签名/未签名提交避免刷屏 UI 与日志同密钥相关问题会被折叠SourceIntegrityCheckResult通过PassedChecks()/AsError()/IsValid()供上层判断同步是否放行pkg/apis/application/v1alpha1/source_integrity.go。多源场景下用InjectSourceName为各源的问题消息加上源名前缀以便区分。strict 模式下的 seal 提交LsSignatures在 deep 模式下会先搜索带Argocd-gpg-seal:trailer 的签名提交作为封条仅验证从目标修订回溯至最近 seal 提交之间的历史util/git/client.go。相关行为有单元测试覆盖见 util/git/gpg_verification_test.goTest_LsSignatures_Sealed_linear、Test_LsSignatures_UnsignedSealedCommitDoesNotStopHistorySearch。CLI 管理入口cmd/argocd/commands/project_source_integrity.go 提供argocd proj source-integrity git policies子命令树list/add/update/delete支持以--repo-url、--gpg-mode、--gpg-key等标志声明式管理策略add/update时还会调用warnOnProblems检查策略是否含空仓库模式、密钥是否已存在于 repo-server 密钥环不在则告警见同文件warnOnProblems函数。六、GnuPG 密钥环管理验证的前提是可信密钥已进入 Argo CD 的 GnuPG 密钥环。Argo CD 采用极简信任模型密钥一旦导入即被信任不支持更复杂的信任模型也不需要对导入的公钥进行再签名见 docs/user-guide/source-integrity-git-gpg.md。RBAC 规则管理 GnuPG 密钥对应的资源记法是gpgkeysp, role:myrole, gpgkeys, get, *, allow # 列出 p, role:myrole, gpgkeys, create, *, allow # 添加 p, role:myrole, gpgkeys, delete, *, allow # 删除CLI 管理argocd gpg list # 列出所有已配置密钥 argocd gpg get key-id # 查看某密钥信息 argocd gpg add --from path-to-key # 导入公钥二进制或 ASCII armor 格式 argocd gpg rm key-id # 移除密钥Web UI 与声明式配置Web UI 的Settings → GnuPG keys模块支持列出、导入与移除UI 导入目前要求 ASCII armor 格式。声明式配置下密钥存放在argocd-gpg-keys-cmConfigMap 中条目名为公钥 ID、值为 ASCII armor 密钥数据例如 GitHub web-flow 签名密钥节选4AEE18F83AFDEB23: | -----BEGIN PGP PUBLIC KEY BLOCK----- ... -----END PGP PUBLIC KEY BLOCK-----密钥环位置与同步密钥环由argocd-repo-serverPod 维护从argocd-gpg-keys-cmConfigMap 同步该 ConfigMap 以卷挂载方式提供给 repo-server Pod。可通过kubectl exec进入 repo-server Pod 检查$ kubectl exec -it argocd-repo-server-7d6bdfdf6d-hzqkg bash argocdargocd-repo-server-7d6bdfdf6d-hzqkg:~$ GNUPGHOME/app/config/gpg/keys gpg --list-keys注意Pod 内密钥环是瞬态的每次重启都会从配置重建不应手工增删 Pod 内密钥私有密钥也是临时的仅用于构建运行中的信任数据库。若密钥环长期与配置不同步可重启 repo-server Pod。七、升级 / 降级迁移策略升级向后兼容升级是无缝的。当 Argo CD 检测到旧的 Git 提交验证配置即AppProject的.spec.signatureKeys已填充时新实现会表现得与当前实现一致。内部会创建一个与此前示例类似的单一验证策略从.spec.signatureKeys取密钥。该兼容逻辑实现在AppProject.EffectiveSourceIntegrity()pkg/apis/application/v1alpha1/types.golegacy 密钥被转换为repos: [{url: *}]gpg: {mode: head, keys: legacyKeys}的单一策略若项目同时声明了sourceIntegrity与signatureKeys会记录错误并忽略后者若只有非 git 的sourceIntegrity则做深拷贝合并。signatureKeys字段本身已标记 Deprecated将在下一个大版本移除pkg/apis/application/v1alpha1/types.go。要迁移到新的源码验证策略用户需要先移除.spec.signatureKeys然后在.spec.sourceIntegrity.git.policies中定义期望的策略。要在项目中复刻 legacy Argo CD 验证行为使用以下配置docs/proposals/source-verification-policies.mdapiVersion: argoproj.io/v1alpha1 kind: AppProject spec: sourceIntegrity: git: policies: - repos: # 针对项目中的任意仓库 - url: * gpg: mode: head # 仅验证 targetRevision 的 HEAD keys: - ... # 来自 .spec.signatureKeys 的密钥降级降级时用户必须将.spec.signatureKeys重新配置到所有曾移除它的 AppProject并同时删除.spec.sourceIntegrity.git.policies。除非降级动机是 Argo CD 实现中的 bug否则将模式移到head或none取决于降级目标版本通常已足够。用户指南补充提醒legacy 功能缺乏新特性——对项目所有仓库而言它只是全 head 模式。与 legacy 配置的共存约束GnuPG 验证自 v1.7 起以signatureKeys形式作为项目级约束引入自 Argo CD 3.5 起成为源码完整性验证方法之一但采用不同的声明格式。配置在signatureKeys中的密钥将继续受支持但不能与sourceIntegrity同时使用见 docs/user-guide/source-integrity-git-gpg.md 的兼容性说明。八、安全考量实施本提案将显著增强对 Git 仓库被攻破时的恢复力典型威胁场景包括未授权贡献者获得提交权限签名密钥被泄露。当攻击者同时攻破开发者凭据与签名密钥时对手只能在其密钥被加入的那些仓库中迫使 Argo CD 信任其提交而无法扩展到其他仓库——这就是按仓库划分签名者集合成为密钥泄露事件中又一道防线的意义。需要注意的是源码完整性验证具有全局影响一旦启用将无法再从本地源同步即argocd app sync --local不可用见 docs/user-guide/source-integrity.md 的警告。另外git generator 填充且project字段模板化的 ApplicationSet 不支持签名验证。九、strict 模式与 Git 历史封条Seal Commit理想状态是仓库从 init 起所有提交都经密码学签名但现实往往并非如此。历史中出现未签名或签名但不可信提交的常见原因包括用户忘记签名提交 / 使用了非预期密钥配置错误的工具创建的未签名提交如 mergesquash、自动化或 IDE 创建密钥曾获批但因泄露、过期、密码学淘汰而轮换前贡献者不再受信任离职等希望接受不可信方的 Pull Request 并在未经可信 GPG 密钥重签的情况下合并仓库策略过去并未要求 GPG 签名。处理这类提交若要求验证全部历史往往需要 git 历史重写rebase、force-push这在技术与组织层面都存在诸多问题force-push 常被作为安全措施明令禁止要求用户为提升安全而放松安全是一种两难选择。部分问题可通过要求 push 时携带 GPG 签名来预防但并非全部且相比限制只能由固定 GPG 密钥集 push在 git 托管平台禁用 force-push 更容易配置。因此本提案将 git 历史重写视为不受欢迎、甚至技术上被禁止的操作并引入**Git 历史封条seal commit**机制Seal Commit 的定义与用法Seal commit 是一个 GPG 签名的提交充当批准印章证明其全部祖先提交要么由可信密钥签名要么经提交作者审阅并信任。Argo CD 验证 GnuPG 签名时只回溯到各祖先分支上最近的 seal 提交为止。实际操作中提交者先审阅自上一个 seal 以来所有未签名或不可信密钥签名的提交然后创建一个可能为空的提交并在消息中包含自定义 trailer。这类提交可表达组织层面的语义从今往后本仓库所有提交都将 GPG 签名之前未签名的无须验证。我合并了来自不可信外部贡献者的变更并对它们表示认可。我正在移除 Bob 的 GPG 密钥。他之前的所有提交仍受信任但之后的新提交不再受信任。我正在用新密钥替换旧密钥此提交之前由旧密钥签名的提交可信任此后信任我的新密钥。创建 seal 提交的命令git commit --signoff --gpg-sign --trailerArgocd-gpg-seal: justification随后推送到 Argo CD 拉取的分支。其优势是同一套流程可以应对上述所有历史中存在未签名/不可信提交的情形消除了因重写历史而出现 rebase 错误、进而危及安全或正确性的空间。还可以引入工具来帮助识别所有历史 seal 提交及之后产生的不可信提交使管理员清楚自己在封签什么。三种模式下的验证范围对比## head mode T - verified | \ | o | | o | | | | o | / o | o ## strict mode T - verified | \ | o - verified | | o | - verified | | | o - verified | / o - verified | o - verified ## strict mode - with seal commits T - verified | \ | S - verified (seal) | | S | - verified (seal) | | | o | / o | o图示取自 docs/proposals/source-verification-policies.md。Git 历史封条可作为strict模式的一部分、最终通过标志启用也可作为独立的更宽松模式启用。两种方式都不需要 force-push。仓库实现中LsSignatures在 deep 模式下通过git rev-list --grepArgocd-gpg-seal:搜索签名 seal 提交并构造--boundary ... --not seal...过滤参数来界定验证范围util/git/client.go。与原始 progressive 模式的比较Seal-signing 的灵感来自一种原始模式从targetRevision验证到上一次 Argo CD Application 成功同步的提交。两者都只向后验证历史到某个被视为天然可信的点。但仓库与 Application甚至 Argo CD 实例之间的非平凡 N:M 映射在原提案中引发了许多边界情况而 seal-signing 把从何处起不再验证的标记放进仓库本身确保所有 Argo CD 实例及其应用对可信边界有一致看法与 Application 从 Argo CD 移除、Argo CD 迁移等事件无关。两种方案本质上都是通过限制待验证提交数来优化性能对封条方案即使没有未签名变更提交者也需要手动添加 seal 提交以加速验证。此外实现层面可对每个仓库与策略最近一次 strict 验证通过的提交做缓存以尽力优化验证速度。十、权衡与备选方案权衡Drawbacks配置源码验证策略给 Argo CD 实现与用户配置都增加了复杂度配置或实现不当本身可能成为安全事故源。备选如何对待本地 manifest当前实现会在 GPG 开启且项目声明签名密钥时拒绝本地 manifest未来可基于源码完整性标准的适用性Git/OCI/Helm 与仓库做选择性处理。备选验证策略配置在哪里验证策略可以放在AppProject的sourceRepos中例如spec: sourceRepos: # ...但这将是破坏性变更因为当前sourceRepos的条目类型只是string必须变为复杂类型。提案建议可在下一个大版本中考虑把sourceIntegrity移入这些位置之一。十一、结语与延伸阅读Source Verification Policies 将 Argo CD 的源码验证从项目级、单点、仅 HEAD提升为仓库级、多策略、可分级的体系同时通过EffectiveSourceIntegrity无缝兼容 legacysignatureKeys。无论你是想为关键仓库启用全历史签名校验还是想对多源应用中不同仓库施加差异化信任都可以按本文的方法在AppProject上完成配置。相关资源可在当前仓库中继续深入提案原文docs/proposals/source-verification-policies.md用户指南总览docs/user-guide/source-integrity.mdGit GPG 验证指南密钥管理、模式、迁移、排障docs/user-guide/source-integrity-git-gpg.mdAPI 类型与模式常量定义pkg/apis/application/v1alpha1/source_integrity.goLegacy 兼容转换逻辑pkg/apis/application/v1alpha1/types.go策略匹配与验证核心实现util/sourceintegrity/source_integrity.goGit 签名枚举与 seal 提交实现util/git/client.go相关单元测试util/git/gpg_verification_test.go、pkg/apis/application/v1alpha1/source_integrity_test.goCLI 管理命令cmd/argocd/commands/project_source_integrity.goE2E 测试test/e2e/app_management_source_integrity_test.go【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表