协会地址:上海市长宁区古北路620号图书馆楼309-313室
门垫下的钥匙更少:为什么可信发布(trusted publishing)对 Open VSX 至关重要
来源: 博客文章
作者: Mikaël Barbero
发布时间: 2026/10/9 16:30:00
原文链接: https://blogs.eclipse.org/post/mika%C3%ABl-barbero/fewer-keys-under-doormat-why-trusted-publishing-matters-open-vsx
每一个软件注册中心最终都会明白同一个道理:发布流水线中最有价值的东西不是代码,而是那个让人得以发布代码的凭据。
在 Open VSX Registry 的大部分历史中,从 CI 向 Open VSX Registry 发布扩展都意味着创建一个个人访问令牌(personal access token),并将其作为密钥存储在流水线中。这个令牌就像是一把压在门口地垫下的钥匙。它随时可用、随处可用、谁捡到都能用,而且会一直有效,直到有人意识到它本不该还有效。

这一切都不是个别发布者的失败。依赖成千上万的维护者每次都把密钥卫生做到位的安全模式,根本无法规模化。一个想要值得信赖的注册表,必须让安全的路径成为最省事的路径。
从共享密钥到声明式关系
可信发布(Trusted Publishing)用一段声明式关系取代了共享密钥:此仓库中的这个工作流,可以发布这个扩展。 注册本身完全不包含任何密钥,它只是记录了发布者所信任的是哪条流水线。
在发布时,CI 系统会为该任务提供一份短时效、带加密签名的自身身份声明。注册表会将该声明与注册信息进行核验,若两者匹配,就签发一份有效期约五分钟、且只能发布某一个扩展的凭证。任何地方都不会存储长期有效的东西,因此没有什么会泄露到公开仓库,没有什么会被信息窃取程序(infostealer)从笔记本电脑中窃走,也没有什么需要轮换。
回到我们之前提到的三个维度,爆炸半径(blast radius)在每一个轴上都缩小了:从数月变为数分钟,从整个命名空间变为单个扩展,从令牌曾被粘贴过的所有地方变为单个已注册的工作流。恢复策略也随之改变。攻击者一旦失去对被入侵流水线的访问权,也就失去了发布能力,而无需任何人轮换任何东西。
云基础设施多年前就走出了这一步——静态访问密钥让位于工作负载身份联合(workload identity federation)和“无常驻权限”(no standing privileges)原则。包注册表如今正在迎头赶上,Open VSX 正是这一转变的一部分。
Open VSX 实现中的若干设计取舍,反映了其他注册表付出惨痛代价才学到的教训。注册表在创建注册时,会把仓库名和所有者名解析为不可变的数字标识符,因此一个被删除后又由他人以同名重建的仓库,自然就不再匹配。当注册的创建者不再是该命名空间的所有者时,该注册会被自动移除,因此访问权不会在授权者离开后悄然存续。错误响应被刻意设计成统一格式,因此令牌交换无法被用来探测哪些扩展配置了可信发布者。项目文档涵盖了这些及其他细节。
最重要的是,该实现遵循 OpenSSF 的指南《面向所有包仓库的可信发布者》,而非另起炉灶自创设计。这是一个战略性的选择。可信发布最早由 PyPI 与 Trail of Bits 于 2023 年开创,此后已被 npm、RubyGems、NuGet、crates.io 和 pub.dev 采纳。当时 Trail of Bits 就预测,它会像双因素认证一样,成为打包安全的基石。遵循这一共通模型,意味着许多同时也要向 npm 发布内容的 Open VSX 发布者,面对的是一项他们已经理解的机制,其保障已在多个生态系统中经过审视。当注册表趋同于经过充分评审的模式、而不是各创各的时,供应链安全提升得更快。
可信发布做不到什么
精确说明一项安全控制的边界,是负责任地部署它的一部分。可信发布有两个值得明确指出的局限。
它是身份认证,而非背书。 正如其最初设计者之一 William Woodruff 在《你不该信任可信发布》中所论述的,名字里的“信任”指的是 CI 工作流与注册表之间的机器对机器信任。它丝毫不能说明某个扩展是否安全、是否写得好、是否出于善意。任何人都可以注册一个工作流,包括那些以自己名义发布恶意软件的人。
Open VSX 扩展页面“Published by”旁边的那个小标记,应当据此来理解。它是一条来源记录(provenance record):该版本是通过发布者已注册的工作流发布的,而不是通过个人令牌。这很有用,主要作为一种一致性信号。在今年的一起 npm 事件中,被入侵的关键迹象就是一次以个人令牌发布的恶意版本,而该项目平时是通过其 CI 身份发布的。出于同样的原因,我们自己的 2025 年审计也把发布行为的突然变化视为被入侵的指标。但这个标记不是安全评级,我们也不打算把它当作评级。无论采用何种身份认证方式,每一次上传仍要经过发布前检查。
它移动了信任边界(trust boundary);但并没有消除它。 任何能够修改或触发已注册工作流(workflow)的人都可以发布。2026 年已经表明,攻击者正在相应地调整策略。5 月,TanStack 被入侵事件 将危险的 pull_request_target 触发器、GitHub Actions 缓存投毒,以及从 runner 内存中提取 OIDC token(令牌)串联起来,并利用它们通过项目自己的发布流水线发布恶意 npm 包,而且带有有效的来源证明。根据一项分析,该项目的信任配置覆盖的是整个仓库,而不是特定的受保护分支和工作流。
教训并不是可信发布(trusted publishing)失败了。它把攻击者的成本从“找到一个 token”抬高到了“攻陷一条流水线(pipeline)”,而流水线如今正是防御必须集中之处。在 Open VSX 上,注册会绑定到特定的工作流文件,但和大多数实现一样,并不会绑定到分支:任何运行该工作流的 ref(引用)都会被视为可信。这就是为什么我们强烈建议固定一个带有必需审查者和分支限制的部署环境(deployment environment),这样合并的 pull request 或一个误提交的 commit 就无法自行发布版本。将 action 固定到 commit SHA、保持默认 token 权限为只读,以及避免使用会以特权运行不受信任代码的触发器,如今承担着过去由存储 token 承担的分量。Eclipse 基金会安全团队关于强化 GitHub Actions的指南是一个不错的起点。
深思熟虑策略中的一层
可信发布回答的是一个具体问题:谁被允许发布? 它位于一个分层模型之中,其中每项控制都覆盖扩展生命周期中的不同阶段。
- 谁可以发布: 经过验证的命名空间、已签署的发布者协议,以及如今与已声明流水线绑定的短期、范围狭窄的凭据。
- 发布的是什么: 针对冒充、嵌入的密钥和已知恶意模式的发布前检查,可疑上传会被扣留审查,而不是直接发布。
- 之后可以更改什么: 不可变版本,因此已发布的版本永远不会被悄悄替换。
- 谁可以观察: Registry Changes Feed,一份仅追加的发布、停用和移除记录,独立监控者和镜像可以跟进。
- 我们如何响应: 快速撤销 token、协调披露,以及在出现问题时发布透明的公告。
共同的主线是从对报告作出反应,转向消除机会。与其变得非常擅长在被攻击者得手时察觉,我们更愿意直接拿走攻击者想要的东西。
发布安全也是一个选择与控制的问题。今天,Open VSX 上的可信发布支持 GitHub Actions。接下来将支持 GitLab,其设计使任何 GitLab 实例(包括自托管实例)都可以被配置为身份提供者(identity provider)。对于一个厂商中立的 registry 而言,发布信任的根源不绑定于单一平台,并且组织可以将其锚定在自己控制的基础设施中,这一点很重要。
切换到可信发布
如果你从 CI 发布到 Open VSX,请迁移。在实践中,这意味着四件事。
- 按照 Tamas 的指南,将你的工作流注册为可信发布者,并将发布 job 切换到可信发布。新扩展的第一个版本仍然需要 token;此后的每一次发布都不需要。
- 从 CI secrets 中删除存储的 token 并撤销它。留在流水线中的 token 仍会继续工作并优先生效,这意味着你实际上并没有完成切换。
- 固定一个带有必需审查者的部署环境,这样发布就需要经过有意识的人工决策。
- 将工作流文件视为安全关键代码:保护它、审查对它的更改,并强化其中运行的内容。
保护关键基础设施需要社区
这项工作之所以能够实现,离不开 Alpha-Omega。自 2022 年以来,它一直支持 Eclipse 基金会的安全项目,并资助了 Open VSX Registry 的强化,从发布前检查到基础设施,再到如今的可信发布。正是这种支持,使一个非营利基金会能够超越对事件的被动响应,转而系统性地消除使这些事件成为可能的条件。谢谢。
还要感谢 Tamas Cservenak、Thomas Neidhart 以及设计并发布此功能的 Open VSX 贡献者们,也要感谢我们所依托的那些奠基工作:开创可信发布的 PyPI 和 Trail of Bits 团队,以及 OpenSSF 软件仓库安全工作组的指导,为每个注册表提供了通用的蓝图。
Open VSX 存在的意义,在于让开发者工具生态系统不必依赖于单一厂商的应用市场。而只有当这个注册表配得上托付给它的信任时,这种独立性才有价值。 我们帮助退役的每一个长期有效的令牌,都是门垫下少放的一把钥匙。







