使用每运行身份保障CI/CD管道安全
如果一个主体可以做任何事情,那么一个错误就可以毁掉一切。
我读过太多事故报告,其中"自动化用户"最终成为了攻击者最好的朋友。一个令牌。所有门禁。代码、制品、生产环境。
我们构建CI/CD是为了快速交付。我们意外地让它成为了最快被攻破的路径。
就像对待人力资源一样,身份应该成为软件工厂的控制平面。这样对待它——否则就准备度过一个漫长的夜晚。
在这篇文章中,我将介绍如何在CI/CD管道中引入身份认证的方法和原因。我将展示如何利用CI/CD和下游资源提供的原语来实现这一点,以及如何通过使用工作负载身份和访问管理(Workload IAM)使其更简单和自动化。
CI/CD中"独特身份"的实际含义(以及为什么需要它)
安全的管道不携带密钥。它通过独特的、可加密验证的身份文档来证明自己的身份——组织、仓库、分支、工作流、运行——然后接收一个即时生成的、短期的凭证,在一个特定环境中完成一个特定工作。然后凭证过期。没有"永久"令牌。没有在保险库中蔓延的密钥。
这些机制并不奇特。你的CI平台(GitHub Actions、GitLab CI、Jenkins等)通常今天就可以提供这些声明,平台运行的环境也可以提供这些声明。你的云可以为一个狭窄的角色(开发/预发/生产)颁发临时凭证。将这些事物一致地连接起来,你可以免费获得三样东西:更小的爆炸半径、更好的取证能力和更少的凌晨轮班。
我们可以更进一步:工作负载IAM层(身份控制平面)使标准路径标准化和自动化。到处都有相同的声明模式。相同的TTL策略。相同的最小权限角色。一个审计跟踪明确地指出哪个管道运行在何时接触了哪个系统。这不是营销。这是操作上的理智。
标准指南支持这个方向:阅读NIST SSDF、NIST SP 800-204D、NSA/CISA CI/CD加固说明、SLSA。这些声音是一致的——最小权限、隔离、来源证明。如果你的管道共享一个"构建上帝"凭证,这些都不真实。
独特的、有时间限制的身份是你实现我们都认同的那些词语的方式。控制平面将它们转化为可重用的策略,而不是一次性的YAML和希望每个仓库维护者都能正确复制它。
这也是通往常见身份构建块——如OIDC、SPIFFE和工作负载IAM——如何协同工作的自然桥梁。我们还将看看每个构建块扮演什么角色,以及为什么你经常需要它们并存。
Pearson 2025:一个令牌,多个门禁
1月份,攻击者获得了一个GitLab个人访问令牌(PAT)。凭借这一条线索,他们拉取了私有仓库,并像时钟一样找到了嵌入式凭证以扩大访问权限。该公司几个月后披露了这起事件。不需要零日漏洞——只需要一个长期有效的、范围广泛的令牌,连接到软件工厂的中枢神经系统。
通过独特的、每运行身份和短TTL,第一个立足点将会有更少的门禁可以打开。通过身份控制平面,安全团队将拥有在危机中最重要的两个杠杆:组织范围的紧急停止开关和证据。谁在什么时候使用了什么。无需争论。
“但那会有很多身份……"(和其他可预见的反对意见)
我们已经建立了一个共享的CI主体。这就是风险。如果这个单一控制点被攻破,你的软件栈将像纸牌屋一样倒塌。转向每运行联邦,并从CI中删除静态密钥。原生工具已经存在;控制平面默认强制执行保护措施。你需要做一些工作来增强现有堆栈吗?是的,但远不及如果不这样做即将发生的违规行为所需的工作量。
但是每个管道一个身份会有太多身份。更小的单位,更小的爆炸半径。在IaC中按仓库×环境模板化角色。让控制平面处理颁发、TTL和撤销,这样成本和精力不会随着仓库数量而扩展。然后关键是如何大规模自动化管理。我们将讨论这个问题。
我们的运行器在本地,资源在云中(或混合)。通过一点规划,你的方法可以轻松桥接信任域。例如,你可以使用SPIFFE/SPIRE来证明主机并颁发短期工作负载身份;通过工作负载IAM将该信任代理到你的云账户中。统一的策略,无论你在哪里运行。
你脑海中的画面
想象一个管道将签名的声明交给身份控制平面,接收一个即时凭证,并在一个环境中承担一个微小角色来完成一个工作。同时,一个锁定的签名服务——在自己的身份下运行——产生来源证明。构建从不接触签名密钥。部署从不看到构建密钥。杀死一个身份,停止一个通道。
|
|
你的身份原语:SPIFFE、OIDC和工作负载IAM如何协同工作
我们一直在将身份视为通道。以下是这三个部分如何保持这些通道狭窄和安全——而不将你的架构变成鲁布·戈德堡机器。OIDC让你的CI运行进入云角色而无需存储密钥。SPIFFE/SPIRE给你自托管的运行器和内部服务一个加密证明的身份和mTLS。工作负载IAM是策略大脑,决定谁在什么条件下获得什么——并保留收据。
一张图,两条路径
A) SaaS CI → 云(简单)
|
|
B) 自托管运行器 → 内部 + 云(混合)
|
|
每个存在的原因(一口气说完)
OIDC是CI获得每运行云访问的干净、原生方式。没有存储的云密钥。没有共享的超级主体。
SPIFFE/SPIRE在你的资产内部提供进程级身份和mTLS——完美适用于自托管的构建器、签名器和制品移动器。
工作负载IAM将两者转化为策略:强制执行分支/批准/签名门控,限制TTL,缩小范围,代理交换,并给安全团队一个带有审计跟踪的紧急停止开关。你的工作负载IAM应该支持多种身份形式:OIDC、SPIFFE、云元数据、Kerberos、VM vCenter证明等。
何时使用什么
当SaaS CI需要云凭证时使用OIDC。当你在SaaS CI之外运行工作负载或希望默认使用mTLS时添加SPIFFE。将工作负载IAM放在两者之上,使规则可重用,证据自动生成。
这是上面心智模型和下面步骤之间的连接组织:图示显示了一个运行如何成为一个狭窄的、有时间限制的身份;下一节将其付诸实践。
实现它(而不毁掉你的一周)
- 从CI中清除静态密钥。在上下文或运行器环境中没有长期云密钥。默认阻止新的"永久"令牌。
- 使用OIDC将CI联邦到云。将信任绑定到仓库/分支/工作流声明;每运行颁发凭证。如果你只运行少量管道,直接联邦。如果你在大规模操作,通过实施工作负载IAM来简化。
- 为每个环境划分最小权限角色。开发 ≠ 预发 ≠ 生产。保持操作狭窄。像代码一样审查策略。
- 隔离签名和来源证明。独立的主体。短TTL。将证明存储在制品旁边。通过工作负载IAM管理签名器。
- 运行遏制演练。撤销一个管道身份并确认只有该通道停止。这应该需要几分钟,而不是几天。
“完成"的样子
通过隔离每个仓库到每个环境来开始向身份的迁移。这一单一举措改变了你的风险状况。对于核心资产,分离构建与部署,并按受保护资产(制品注册表、生产数据库)划分身份。将模式编码到策略中,这样新仓库在第一天就继承了这个态势。
CI中没有长期云密钥。PAT使用很少,范围严格限制,短期有效,并由工作负载IAM控制。如果你尚未使用工作负载IAM,至少通过SSO控制它。每个部署都映射到一个每运行主体。紧急撤销正好中断一个通道。当安全团队问"谁在哪里签署了这个?“时,你可以在几秒钟内回答。
独特的、短暂的身份将CI/CD从超级用户转变为狭窄、光线充足的走廊。工作负载IAM使安全路径成为默认,而不是例外。