登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  业界新闻

GitHub Actions 安全指南为何持续收紧工作流权限

来源:17golang原创

时间:2026-10-08 21:45:55 150浏览 收藏

GitHub Actions 的安全指南持续收紧,不是因为某一个 YAML 语法突然变得危险,而是工作流已经从“自动跑测试”升级为同时掌握源码、缓存、制品、发布权限和外部云身份的供应链入口。2026 年 GitHub 连续把限制扩展到 Action 白名单、不可信触发器的缓存写入、触发者与事件规则,以及 pull_request_target 的默认保护,说明平台正在把最小权限从令牌配置推进到完整执行链。

GitHub 官方地址:https://github.com/

Actions 安全参考:https://docs.github.com/en/actions/reference/security/secure-use

这轮变化可以归纳为四点
  • 谁能触发、什么事件能触发,开始由仓库外部的策略统一约束。
  • 不可信触发器不再默认拥有同等缓存写入能力,缓存也被视为供应链资产。
  • GITHUB_TOKEN 继续强调 job 级最小权限,而不是给整条流水线一组宽权限。
  • 第三方 Action、长期云密钥、自托管 Runner 和工作流文件变更都进入同一套威胁模型。

2026 年的几个变化串起来看更清楚

我第一次认真清理 Actions 权限时,只盯着 permissions。但把 GitHub 2026 年的官方更新放在一起看,会发现平台关心的已经不只是令牌读写范围。

官方变化它控制的对象反映出的安全判断
2 月:Action 白名单扩展到所有计划类型允许使用的 Action 和可复用工作流依赖来源应由策略限定,不能完全交给每份 YAML
6 月:不可信触发器对默认分支缓存只读Actions 缓存写入缓存可以跨信任边界传播被污染内容
9 月:工作流执行保护正式可用触发者、触发事件和具体工作流文件高风险工作流应在运行前被组织级策略拦截
持续更新:令牌权限细分GITHUB_TOKEN 的资源范围每个 job 只拿完成任务所需的能力

这条路线的共同点是:安全控制逐渐从工作流文件内部移到更难被同一提交修改的位置。攻击者即使能改 YAML,也不应自动获得触发权、缓存写入权和部署凭据。

权限收紧的起点已经不只是 GITHUB_TOKEN

官方安全文档明确提醒,pull_request_target 和 workflow_run 在处理不可信拉取请求代码时可能进入特权上下文;它们可能接触主分支共享缓存、仓库写权限或引用的 Secrets。第三方 Action 也能通过 github.token 间接访问 GITHUB_TOKEN,即使 YAML 没有显式把 Token 作为参数传入。

GitHub Actions 不可信入口、共享执行面和高价值资产之间的静态风险关系
图1:GitHub Actions 攻击面关系说明图,不是产品截图或运行证据。

2026 年 6 月的只读缓存变化很能说明问题:以前某些外部人员可触发的事件可以向默认分支作用域写缓存,后续受信任的 push 或 schedule 工作流再恢复这些缓存,就可能形成缓存投毒链。现在满足“不可信触发”和“共享默认分支作用域”两个条件时,缓存令牌只读;恢复仍可进行,但保存会被拒绝并记录警告。

这也是为什么“没有把 Secret 打印出来”远远不够。攻击面还包括缓存、工作目录、制品、Docker Socket、自托管 Runner 上的持久状态,以及一个 job 留给另一个 job 的文件。

先把令牌权限拆到 job,而不是停在 workflow

最容易落地的改造,是在工作流顶层设置只读基线,再让少数 job 单独申请额外权限。GitHub 官方建议默认让 GITHUB_TOKEN 只读仓库内容;未列出的权限会按规则落到 none,因此要把实际需要写入的资源写清楚。

name: build-and-deploy
on:
  push:
    branches: [main]

# 整条工作流默认只允许读取仓库内容。
permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      # 示例使用官方 Action;第三方 Action 在生产中应固定完整提交 SHA。
      - uses: actions/checkout@v4
      - run: npm test # 示例:测试任务不需要仓库写权限。

  deploy:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write # 只允许申请 OIDC 令牌,不等于获得云资源写权限。
    steps:
      - run: ./scripts/deploy.sh # 云端权限仍由 OIDC 信任策略决定。

上例用版本标签保持可读性,但生产环境若使用第三方 Action,官方更推荐固定到完整提交 SHA,因为标签可以被移动。可以再配合 Dependabot 更新 Action 引用,把“不可变引用”和“持续更新”同时保留。

id-token: write 经常被误解。它只允许工作流向 GitHub 的 OIDC 提供方请求令牌,不会直接授予云资源写权限;真正能访问哪些云资源,仍由云平台信任条件、受众、仓库、分支、环境等声明约束。相比长期保存云密钥,短期 OIDC 身份能显著缩短泄露后的可利用时间。

不可信触发器要和特权部署彻底分开

我更倾向于把来自 Fork 的验证工作流看成“读取并测试不可信代码”,把发布工作流看成“操作受信任资产”,两者不共享写权限和长期凭据。尤其要避免在 pull_request_target 中检出并执行来自 Fork 的代码。

GitHub 在 2026 年 9 月宣布工作流执行保护正式可用,管理员可以按 actor、event 和工作流文件路径设置规则。高风险的 deploy.yml 可以只允许指定团队触发,而普通 CI 继续服务贡献者;evaluate mode 还能先观察哪些运行会被拦截,再决定是否强制执行。同期官方也开始为 pull_request_target 滚动提供默认保护。

如果暂时没有组织级执行保护,至少先做三件事:

  • 外部拉取请求只运行无 Secret、只读 Token 的构建与测试。
  • 部署只接受受保护分支、人工批准或明确受信任的事件。
  • 缓存保存放在受信任的 push 工作流中,不让不可信上下文更新共享缓存。

现有流水线可以按六层顺序收紧

GitHub Actions 从触发者与事件到审计告警的六层安全架构
图2:工作流权限分层加固说明图,不是 GitHub 设置页截图。
  1. 触发者与事件:盘点 pull_request_target、workflow_run、workflow_dispatch 等入口,明确谁可以触发。
  2. 工作流文件范围:对发布、签名、制品上传等高权限文件单独设策略,并用 CODEOWNERS 要求指定人员审查。
  3. job 级权限:顶层只读,只有创建 Issue、发布包或申请 OIDC 的 job 才增加对应权限。
  4. 依赖来源:限制允许的 Action 和可复用工作流;第三方依赖固定到完整提交 SHA,并持续更新。
  5. 外部身份:用 OIDC 换取短期且范围受限的访问令牌,删除不再需要的长期云密钥。
  6. 审计回路:用 CodeQL 检查易受攻击的工作流模式,查看组织审计日志中的 Secret、策略和权限变更。

这六层没有要求一次完成。对多数团队,最划算的顺序是先降 GITHUB_TOKEN,再隔离不可信触发器,然后清理第三方 Action 与长期密钥,最后把规则提升到组织级。

失败处理也应该成为安全控制的一部分

工作流加固后,最常见的反馈不是“更安全”的提示,而是某个步骤突然收到 403、缓存无法保存或部署身份交换失败。不要第一时间把权限改回 write-all,而应把失败当成权限需求的观测信号。

失败现象优先检查不要立即做什么
API 返回 403失败 job 实际访问的资源和对应权限名不要给整个 workflow 写权限
缓存只恢复不保存触发事件是否属于不可信上下文不要让外部触发器写默认分支共享缓存
OIDC 无法换取云令牌云端信任条件、受众、分支和环境声明不要退回永久云密钥作为长期方案
Action 被策略拒绝来源是否在白名单、引用是否固定 SHA不要放开所有第三方 Action

通知也要分层:普通测试失败发给提交者;权限策略命中、工作流文件变更、Secret 变更和发布身份异常应进入安全或平台团队能看到的渠道。GitHub 的组织审计日志可以记录相关 Actions 与 Secret 事件,适合做周期复盘。

我的判断:这是从“配置建议”走向“平台强制”

早期的 GitHub Actions 安全更多依赖维护者记住最佳实践:手写 permissions、避免危险触发器、审核第三方 Action。2026 年的变化则明显把这些经验变成平台层规则:不可信缓存默认只读、触发执行可以被策略拦截、高风险事件获得默认保护、Action 白名单覆盖更多计划。

对小型私有仓库,这种收紧会增加一点配置成本;对开源项目、包发布仓库和多团队组织,它换来的却是更明确的信任边界。真正值得优先处理的,不是 YAML 是否看起来简洁,而是一个外部贡献者能否借由触发器、缓存或第三方依赖一路触达仓库写权限和部署凭据。

常见问题

所有工作流都要设置 permissions 吗?

建议显式设置。即使新仓库默认更保守,旧仓库、组织继承设置和不同 job 的需求仍可能不同;显式权限更容易审查和迁移。

pull_request_target 完全不能用吗?

不是,但它只应在确实需要基础仓库特权上下文时使用,而且不能检出并执行不可信拉取请求代码。能够用普通 pull_request 或隔离后的 workflow_run 完成时,优先选择风险更低的结构。

固定完整 SHA 会不会让升级很麻烦?

会增加维护动作,但可以交给 Dependabot 提交更新请求,由维护者审查来源与变更。标签更方便,却不具备同等级别的不可变性。

自托管 Runner 为什么风险更高?

GitHub 托管 Runner 通常是临时且隔离的虚拟机,自托管 Runner 可能保留文件、凭据和网络访问能力。官方文档提醒,公共仓库通常不应让不可信工作流使用自托管 Runner;即使采用一次性注册,也要确保底层环境真正干净。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>