用户登录

技术文章

外部链接将在新标签页打开。

Trusted Publishing 替代长期密钥:VS Code 扩展发布链路的信任边界怎么划

一句话回答

Microsoft 为 Visual Studio Marketplace 推出 Trusted Publishing,用 GitHub Actions 的 OIDC 或 Azure Pipelines 的 Entra 背书 WIF 身份替代长期 Azure DevOps PAT。信任边界因此从“仓库里的一枚长期密钥”移到“CI 平台签发的短时身份 + Marketplace 侧的策略或身份绑定”。文章拆解 GitHub 策略匹配字段、私有仓库 48 小时激活窗口、Azure 侧不走 Marketplace policy 的差异,以及先并行后撤除 PAT 的迁移顺序,并列出材料未覆盖、仍需自行

核心要点 TL;DR
  • Trusted Publishing 把发布凭证从 CI 密钥换成 CI 平台签发的短时身份,GitHub Action
  • GitHub Actions 的边界由 Marketplace 策略决定,策略精确匹配仓库所有者、仓库名、工作流文件名和
  • 私有仓库新建策略只有 48 小时临时激活窗口,首次成功换取令牌后永久激活。
  • 迁移应先让 OIDC 发布跑通再删除 PAT;现有 PAT 发布方式继续可用。

如果你现在用一条长期 Azure DevOps 个人访问令牌(PAT)在 CI 里发布 VS Code 或 Visual Studio 扩展,那么信任边界其实划在“谁能读到那个 secret”上。Microsoft 为 Visual Studio Marketplace 推出的 Trusted Publishing,把这个边界往上游挪了一层:CI 平台签发的短时身份取代了可存储的发布凭证,Marketplace 侧只验证“这个工作流或这个身份被允许发布”。Microsoft 的发布说明给出的关键事实是:没有需要存储或轮换的发布密钥,GitHub Actions 场景下临时凭证 15 分钟后过期。

下文围绕“信任边界怎么划”拆解这条链路:谁签发身份、谁做验证、策略粒度落在哪里、失败或过期时回退到什么状态。所有具体字段与行为均来自上述公告;材料未覆盖的部分会明确标为待核实。

先看旧模型:PAT 把信任集中在 secret 上#

按公告描述,传统的自动化发布要求把 PAT 存成 CI/CD secret。这条链路的信任边界有三个特征:凭证长期有效、任何能读到该 secret 的步骤都能使用它、轮换需要人工介入。它的风险不在于 PAT 一定会泄露,而在于一旦泄露,有效窗口由凭证本身决定,而不是由某次发布决定。

Trusted Publishing 改变的是这一层:CI/CD 系统向 Marketplace 出示联邦身份,Marketplace 验证 GitHub 的 Trusted Publishing 策略或 Azure Pipelines 的工作负载身份,发布工具凭已验证身份发布,全程没有 PAT 可取用。

信任链上的三个角色#

  • 签发方:GitHub Actions 的 OIDC,或 Azure Pipelines 中由 Microsoft Entra 背书的 Workload Identity Federation(WIF,工作负载身份联合)。它决定“这次运行为谁作证”。
  • 验证方:Visual Studio Marketplace。GitHub 场景下校验你预先创建的 Trusted Publishing 策略;Azure 场景下校验以 publisher contributor 身份出现的工作负载身份。
  • 使用方:发布工具本身。公告的表述是“用已验证身份发布,无需 PAT”,并强调走 OIDC 时整个过程自动完成。

值得注意的是两侧的验证机制并不对称:GitHub 依赖 Marketplace 侧的一条策略,Azure 依赖 Entra 侧的服务连接加 Marketplace 侧的贡献者角色。这种不对称直接决定了后面两节的配置差异。

GitHub Actions:策略就是边界的定义#

在 Marketplace 的 publisher 管理页打开 Trusted Publishing,展开 Create 后需要填写四个必填项和一个可选项,公告给出的语义如下:

字段填写内容边界含义
Policy name描述性名称,如 Release workflow仅用于识别,不影响授权
Repository owner精确的 GitHub 组织或用户登录名,如 contoso绑定所有者,不接受近似匹配
Repository不含所有者的仓库名,如 sample-extension绑定到具体仓库
Workflow.github/workflows 下的工作流文件名,如 publish.yml绑定到具体工作流文件
Environment(可选)工作流使用的 GitHub environment 精确名称,如 production需要环境审批时补上这一层

把它读成边界:这条策略授权的是“某个仓库里的某个工作流文件(以及可选的某个环境)”,而不是“这个仓库的所有自动化”。公告未说明策略是否支持通配符、是否区分分支或提交,也未说明同一仓库能否并存多条策略——这些都需要按官方文档核实,不能从字段列表反推。

私有仓库的 48 小时窗口是个容易踩的点

公告明确区分了仓库可见性:私有仓库新建的策略先处于临时激活状态,有效期 48 小时,首次成功完成令牌交换后永久激活;若窗口内没有被使用,策略过期,可以重新打开再获得 48 小时。策略的状态和最后使用时间都能在 Trusted Publishing 页面查看。对排期发布的项目来说,这意味着“建完策略、隔一周再接 CI”的顺序会失败,正确顺序是先建策略、尽快跑一次真实发布。

工作流侧只需要一个权限

迁移步骤中与工作流文件相关的改动只有一处:给发布 job 加上 id-token: write。以下片段为未执行的示例,仅示意权限位置,具体发布命令参数以 Visual Studio Code 文档中的安全自动发布指南为准。

# 未执行示例:仅展示 OIDC 所需权限声明
jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write   # 允许该 job 申请 OIDC 令牌
    steps:
      - uses: actions/checkout@v4
      # 发布步骤的具体参数请对照官方指南,本文不代为给出

这里有一个材料没展开、但工程上必须自己回答的问题:id-token: write 是 job 级权限,任何进入该 job 的步骤理论上都能申请令牌。公告没有讨论第三方 action 混入同一 job 的情况,因此这条边界需要你在工作流结构上自行收窄,而不是指望 Marketplace 策略替你区分步骤。

Azure Pipelines:边界在身份和角色,不在策略#

Azure 侧的路径完全不同,公告用加粗级别的措辞提醒:不要为 Azure Pipelines 在 Marketplace 的 Trusted Publishing 页面创建策略。正确做法分三步:

  1. 配置一个使用 Workload Identity Federation 的 Azure Pipelines 服务连接,后端可以是 Microsoft Entra 应用注册加服务主体,也可以是托管标识。
  2. 把该身份加入 Visual Studio Marketplace 的 publisher,并授予 Contributor 角色。
  3. 把发布步骤配置为使用这个 WIF 服务连接。

于是 Azure 侧的信任边界落在两处:Entra 侧“谁能使用这个服务连接”,以及 Marketplace 侧“这个身份在 publisher 里是什么角色”。公告只说明需要 Contributor 角色,未逐条列出该角色在 Marketplace 中的全部权限范围,这一点属于需要自行核实的部分,尤其当同一 publisher 下有多个扩展时。

迁移顺序:先并行,再撤除#

公告给出的 GitHub 迁移路径是渐进的,顺序本身就是风险控制:

  1. 为仓库和工作流创建 Trusted Publishing 策略。
  2. 给发布 job 加 id-token: write。
  3. 把发布命令改为走 OIDC。
  4. 运行工作流,确认 OIDC 发布成功。
  5. 成功之后再从工作流和仓库 secret 中移除 Marketplace PAT。

公告明确建议在第一次 Trusted Publishing 运行验证通过前保留 PAT,成功后再删除未使用的 secret,避免它被其他工作流步骤误用。Azure 侧同理:先配好 WIF 服务连接与 publisher 身份,更新发布步骤使用该连接,联邦发布成功后再移除 PAT。

这个顺序隐含一个判断:迁移期间两种凭证并存,此时实际信任边界是两者中较宽的那个。把窗口压到最短,比一次性切换更稳妥。

四类边界,一张对照表#

边界问题GitHub ActionsAzure Pipelines
身份由谁签发GitHub OIDCMicrosoft Entra 背书的 WIF 服务连接
Marketplace 侧配置需创建 Trusted Publishing 策略不创建策略,只把身份加为 Contributor
授权粒度仓库所有者 + 仓库 + 工作流文件(+ 可选 environment)服务连接身份 + publisher 角色
凭证有效期临时凭证 15 分钟过期公告未给出具体时长,待核实

这套模型没有替你解决的问题#

  • 工作流内部的可信度:策略保证“是这个工作流文件发起的”,不保证文件里的每一步都可信。依赖的第三方 action、脚本注入、被篡改的分支,仍要靠在仓库侧控制。
  • 分支与评审约束:公告未说明策略是否限定分支,也未说明环境审批如何与策略交互。若需要“只有合并到主分支且通过评审才能发布”,这部分要靠 GitHub 侧规则补足。
  • 失败路径与重试:公告未描述令牌交换失败时的错误语义、限流或重试建议,排障应按官方文档进行。
  • 审计:公告提到可在页面查看策略状态和最后使用时间,但未说明事件留存周期与导出方式。

归纳起来,Trusted Publishing 把“有没有一枚长期密钥泄露”这个高频问题,换成了“身份签发条件、策略匹配范围、角色权限、迁移窗口”四个可逐项检查的控制点。前两个由 Marketplace 策略和 CI 平台共同决定,第三个在 Azure 侧尤其要自己确认,第四个则是迁移期最容易放松的地方。

公告同时说明现有 PAT 发布方式继续可用,因此采用节奏可以自定;但一旦决定迁移,建议按公告顺序执行:先建策略、再改工作流、验证成功、最后删密钥。具体配置细节与排障,应以 Visual Studio Code 和 Visual Studio 文档中的对应指南为准。

常见问题(FAQ)

启用 Trusted Publishing 后,原来的 PAT 会立刻失效吗?
不会。Microsoft 说明基于 PAT 的发布方式继续可用,可以按自己的节奏迁移。PAT 只在你确认 OIDC 发布成功、并从工作流和仓库 secret 中主动删除之后才不再参与发布。
Azure Pipelines 也需要在 Marketplace 的 Trusted Publishing 页面建策略吗?
不需要,而且官方明确要求不要为 Azure Pipelines 建这个策略。Azure 侧走的是 Microsoft Entra 背书的 Workload Identity Federation 服务连接,把该身份加为 publisher 的 Contributor。
私有仓库创建的 GitHub 策略为什么过一段时间就不能用了?
私有仓库的新策略先处于 48 小时临时激活状态,首次成功完成令牌交换才永久激活;窗口内未使用则过期,可以重新打开再获得 48 小时。

参考来源

  1. Publish Visual Studio Marketplace extensions securely with Trusted Publishing

以上为本文写作时的参考资料,引用观点以原文为准。

作者:沐小悠

本文约 11 分钟读完 · 关键词:Trusted Publishing、VS Code 扩展发布、OIDC、短期凭证、PAT 迁移

更多文章 GET 示例接口

「」标签下的其他文章