Trusted Publishing 的信任链怎么搭:策略匹配、短期凭据与迁移顺序
Trusted Publishing 把发布权限从“持有的密钥”改为“可验证的工作流身份”:CI 平台签发联邦身份,Visual Studio Marketplace 按策略或工作负载身份校验,再发放短期凭据完成发布。GitHub Actions 的信任锚是 Marketplace 上的策略,Azure Pipelines 的信任锚是 Microsoft Entra 支持的服务连接及其发布者 Contributor 角色,两者不能混用。私有仓库的新策略有 48 小时激活窗口,GitHub Actions 的临时凭据 15 分钟过期;迁移时应先并行验证 OIDC 发布成功,再删除 PAT。
- 信任链的关键不是“有没有密钥”,而是 Marketplace 能否把一次发布请求对应到某个具体仓库、工作流或工作负载身份
- GitHub Actions 在 Marketplace 侧建策略;Azure Pipelines 不建策略,改为把 W
- 私有仓库策略创建后 48 小时内未完成首次令牌交换会过期;首次成功交换后永久激活。
Trusted Publishing 要解决的问题可以概括成一句话:让发布流水线在不保存长期凭据的前提下,仍然能向 Visual Studio Marketplace 证明“我是那个被授权的发布流程”。微软在 2026 年 10 月 28 日的公告中把它描述为用联邦身份验证发布工作流,取代把 Azure DevOps 个人访问令牌(PAT,Personal Access Token)存成 CI/CD 密钥的做法(Microsoft for Developers 公告)。
所以“信任链怎么搭”其实是在回答三个问题:谁签发身份、谁校验身份、校验通过后拿到什么。下面按这三跳拆开,再分别说明 GitHub Actions 与 Azure Pipelines 两条路径的差异与迁移顺序。
第一跳:CI 平台签发联邦身份#
信任链的起点在 CI 平台,而不在 Marketplace。GitHub Actions 走 OIDC,工作流在运行时获得一个由平台签发的身份令牌;Azure Pipelines 走工作负载身份联合(WIF,Workload Identity Federation),由一条 Microsoft Entra 支持的服务连接代表流水线身份。两者共同点是:凭据由平台在运行时产生,仓库里没有可被复制走的长期发布密钥。
这也是 Trusted Publishing 与“把 PAT 放进 Secrets”最本质的区别。PAT 是持有即有权,泄露即可用;联邦身份是“运行时才有、且可被平台侧策略约束”,攻击面从“密钥保管”转移到“谁能修改工作流与策略”。
第二跳:Marketplace 侧的信任锚#
两条路径在这第二跳上分道扬镳,这是实践中最容易配错的地方。
| 对比项 | GitHub Actions | Azure Pipelines |
|---|---|---|
| 信任锚 | Marketplace 发布者下的 Trusted Publishing 策略 | Microsoft Entra 支持的工作负载身份服务连接 |
| Marketplace 侧动作 | 创建策略,限定仓库与工作流 | 把该身份加为发布者并授予 Contributor 角色 |
| 是否需要 Marketplace 策略 | 需要 | 不需要,原文明确提示不要为其创建策略 |
| CI 侧动作 | 工作流使用 GitHub OIDC 发布 | 配置 WIF 服务连接并在发布步骤中引用 |
| 凭据有效期 | 临时凭据 15 分钟过期 | 本次材料未给出,待核实 |
Azure Pipelines 的模型更接近传统 RBAC:信任的对象是“某个身份”,也就是 Entra 应用注册加服务主体,或托管标识;把这个身份加进发布者并给 Contributor 角色,流水线就能发布 VS Code 与 Visual Studio 扩展,同样不需要保存 Marketplace PAT。GitHub Actions 的模型则是“某个具体的仓库 + 工作流(+ 可选环境)”,粒度更细,也更依赖策略字段填得准。
第三跳:短期凭据与策略匹配#
GitHub 策略字段就是匹配规则
策略不是备注,而是逐字段比对的匹配条件。创建入口在 Marketplace 的发布者页面下:选中拥有扩展的发布者,进入 Trusted Publishing,展开 Create 后填写。原文给出的字段含义如下:
- Policy name:描述性名称,例如
Release workflow。 - Repository owner:拥有仓库的 GitHub 组织或用户登录名,必须是精确值,例如
contoso。 - Repository:不含 owner 的仓库名,例如
sample-extension。 - Workflow:
.github/workflows下的工作流文件名,例如publish.yml。 - Environment(可选):若工作流使用了 GitHub 环境,填写其精确名称,例如
production。
这五个字段合起来构成信任边界。填得宽,任何能改该工作流的人都能发布;填得窄,重命名工作流文件或调整环境名就会让发布失败。工程上更稳妥的做法是把策略名与工作流文件名对应起来,让匹配失败时的排查有迹可循。
私有仓库的 48 小时激活窗口
策略激活与仓库可见性有关。对私有仓库,新建策略先处于临时激活状态,窗口为 48 小时;第一次成功的令牌交换会让策略永久激活。如果这段时间内没有使用,策略会过期,可以重新打开以获得另一个 48 小时窗口。策略的状态与最近使用时间都可以在 Trusted Publishing 页面查看。
这条规则对工程安排有直接影响:创建策略和第一次跑通流水线应当排在同一次操作里。若先建策略、隔几天再调 CI,很可能第一次真正的发布就撞上过期,表现为“明明配好了却不被信任”,而根因只是窗口失效。
迁移顺序:先并行,后删除#
原文明确说明,现有基于 PAT 的发布方式继续可用,因此迁移不必是一次性切换。对已经用 vsce 发布的 GitHub Actions 工作流,建议按下列顺序推进:
- 为仓库与工作流创建 Trusted Publishing 策略。
- 在发布 job 上添加
id-token: write权限。 - 把发布命令改为使用 OIDC 的方式。
- 运行工作流,确认 OIDC 发布成功。
- 确认成功后再从工作流与仓库 Secrets 中移除 Marketplace PAT。
第四条是关键。原文的建议是保留 PAT,直到第一次 Trusted Publishing 运行验证通过,之后再删除未使用的密钥,避免它被其他步骤误用。Azure Pipelines 同理:先配好 WIF 服务连接与发布者身份,把发布步骤切到该连接,联邦发布成功后再移除 PAT。
下面这个片段只写出材料明确提到的部分。这是未执行的示例,具体发布命令的参数本次材料未给出,需按官方文档核实后再用:
# 未执行示例:仅体现材料中提到的 id-token: write 权限
permissions:
id-token: write # 允许工作流请求 OIDC 令牌
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- run: echo "发布命令需按 VS Code 文档改为 OIDC 方式(参数待核实)"
边界与容易误判的地方#
- “去掉长期密钥”不等于“去掉所有凭据管理”:信任链把风险从密钥保管转移到策略与工作流配置,能改工作流的人实际上就握有发布能力。
- 两条路径的信任锚不可互换:GitHub Actions 依赖 Marketplace 策略,Azure Pipelines 依赖 Entra 工作负载身份与 Contributor 角色;给 Azure 建策略不会生效。
- 15 分钟只针对 GitHub Actions:原文表述是 Marketplace 为 GitHub Actions 发放 15 分钟过期的临时凭据,Azure Pipelines 侧的凭据时效本次材料未说明。
- 策略字段是精确匹配:仓库所有者、仓库名、工作流文件名、环境名任一不符都不会被信任,重命名文件属于破坏性变更。
- 企业版、审计日志、失败重试的具体行为:本次材料未涉及,属于待核实范围,不宜凭经验推断。
把这三跳连起来看,Trusted Publishing 的落地难点不在“打开开关”,而在把信任边界写准:GitHub 侧用策略把发布权限钉在具体仓库与工作流上,Azure 侧用工作负载身份把权限钉在具体服务连接上,然后让第一次发布在激活窗口内成功完成。做到这几点,长期密钥才真正可以退场。
常见问题(FAQ)
已有 PAT 发布流程必须立刻改吗?
Azure Pipelines 也需要在 Marketplace 的 Trusted Publishing 页面建策略吗?
参考来源
以上为本文写作时的参考资料,引用观点以原文为准。