GitHub Actions 权限加固清单:GITHUB_TOKEN、Secrets、OIDC 和自托管 Runner 边界

Actions 的安全基线不是“仓库私有就行”,而是每次运行拿到最小权限、密钥不进日志、云端访问尽量用短时凭证。

Actions 的安全基线不是“仓库私有就行”,而是每次运行拿到最小权限、密钥不进日志、云端访问尽量用短时凭证。

  1. 01先读摘要,判断是否与你的场景相关。
  2. 02再看来源,保留继续查证的路径。
  3. 03最后看步骤、风险和可复用动作。

GitHub 官方安全参考反复强调同一句话:任何有仓库写权限的人都能读取仓库里的 Secrets,因此工作流里的凭证必须是最小权限。GITHUB_TOKEN 默认权限过高、Secrets 放在不相关环境、云端密钥长期存在,是 CI/CD 最常见的三类风险。下面这套清单按仓库、工作流、环境和 Runner 四层收紧。

适用场景

  • 仓库使用 GitHub Actions 做测试、构建、部署或自动化任务。
  • 工作流需要访问云平台、包仓库或其他外部服务。
  • 你想把 GITHUB_TOKEN 从全写权限降到只读。
  • 你正在从长期云密钥迁移到 OIDC 短时凭证。

不适用场景

  • 没有 GitHub Actions,也没有 CI/CD 工作流。
  • 团队完全使用 GitHub-hosted runner,并且不需要访问云资源。
  • 你希望一个 token 同时满足所有历史工作流,不做逐项排查。
  • 你把 Actions 安全当成仓库私有就能解决,不检查第三方 action。

准备材料

  • GitHub 仓库、组织或企业管理权限。
  • 当前 workflow 文件列表和使用的第三方 action。
  • 云平台或外部服务的账号权限,用于配置 OIDC 信任。
  • Secrets 清单,记录名称、使用环境、最后修改人和轮换周期。
  • 一个测试分支,用于灰度权限变更。

步骤一:把默认 GITHUB_TOKEN 权限设为只读

GitHub 官方建议把仓库或组织的默认 token 权限设为 read access only for repository contents,需要时再在单个 job 里增加。这样即使某个 action 被滥用,token 也无法直接写仓库。

  • 在仓库 Settings 的 Actions 页面找到 Workflow permissions。
  • 选择 Read repository contents and packages permissions。
  • 组织层面也设置默认只读,避免新仓库继承高权限。
  • 记录哪些工作流需要 write,再在 job 内显式开放。

步骤二:在每个 job 里显式声明 permissions

不要在 workflow 顶部一次性放开所有权限。官方文档建议在需要 token 的 job 中设置最小 permissions。下面是一个只读示例:

permissions:
  contents: read
  id-token: write

id-token: write 只在需要 OIDC 时出现。它允许请求 OIDC JWT,但不会自动给仓库写权限。发布 job 如果确实需要创建 release,再单独把 contents 设为 write,不要复制给测试 job。

步骤三:把 Secrets 放进对应 Environments

仓库级 Secrets 对所有 Actions 可见,环境级 Secrets 只对指定 environment 可见。官方文档说明环境中可以配置 required reviewers,让生产部署前有人工审批。把测试密钥和生产密钥分开,能显著减少误用。

  1. 在仓库 Settings 的 Environments 创建 production、staging、test。
  2. 把生产云密钥放入 production environment,而不是仓库 Secrets。
  3. 为 production 配置 required reviewers 和 deployment branch。
  4. 在 workflow 的 job 中声明 environment,并引用 secrets.ENV_NAME。
  5. 定期检查哪些 workflow 能访问生产环境。

步骤四:访问云资源时优先使用 OIDC

GitHub 官方说明 OIDC 允许工作流从云平台获取短时 token,不再把长期云凭证存成 GitHub Secrets。配置时必须在云角色上设置至少一个 subject 或 audience 条件,否则不受信任仓库也可能请求访问。

  • 为每个仓库或工作流创建独立云角色。
  • 在角色信任策略中限制 repo、environment 和 ref。
  • 不要使用宽泛的 “所有 GitHub Actions” 信任条件。
  • 用官方 login action 或 getIDToken 请求 token。
  • 上线后验证 token 过期时间和最小权限。

步骤五:给自托管 Runner 画清边界

GitHub 官方强烈建议公开仓库不要使用自托管 runner,因为任何能开 PR 的人可能获得 runner 环境,包括 Secrets 和 GITHUB_TOKEN。私有仓库也要限制到可信任用户,并使用隔离环境、只读根文件系统和受控网络。

  • 不在公开仓库配置自托管 runner。
  • runner 标签区分生产、测试和不同项目。
  • 环境密钥只暴露给对应 environment 和 runner group。
  • 定期清理陈旧 runner,检查最后心跳。
  • 需要执行任意代码的 runner 与主开发机隔离。

步骤六:审计第三方 action 和凭证轮换

第三方 action 可以通过 github.token 间接访问仓库,即使 workflow 没有显式传 token。官方建议固定 action 版本或使用 SHA,并对第三方 action 做代码审查。同时为仍存在的长期 Secrets 设置轮换日期,而不是无限保留。

  • 把 action 从 main 改为具体 tag 或 commit SHA。
  • 检查 action 是否读取 inputs、token 和环境变量。
  • 删除不再使用的 Secrets,避免旧 token 长期有效。
  • 每季度导出 Secrets 使用情况,标记 90 天未使用的项目。
  • 需要长期凭证时使用最小 scope 的 fine-grained token,不用经典 token。

可复制检查表

仓库:
默认 token 权限:
job 名:
permissions:
环境:
Secrets 名称:
OIDC 角色:
Runner 标签:
action 版本:
最近审计日期:
下次轮换:

实际例子:部署工作流从全写 token 改成分层权限

一个小型项目原先在 workflow 顶部写 permissions: write-all,并把 AWS 长期密钥放进仓库 Secrets。审计后改为:测试 job 只读 contents,生产部署 job 声明 environment production,使用 aws-actions/configure-aws-credentials 配合 OIDC,并设置 required reviewers。两周后,某个第三方 action 被替换时不再能访问生产密钥,部署日志也变得更干净。

验收清单

  • 仓库和组织默认 token 权限为只读。
  • 每个 job 都显式声明所需权限。
  • 生产 Secrets 只存在于对应 Environment。
  • 云访问使用 OIDC,且信任条件按仓库或环境限制。
  • 公开仓库没有自托管 runner。
  • 第三方 action 固定版本或 SHA。
  • Secrets 有负责人和轮换日期。

常见坑

  • 在 workflow 顶部写 permissions: write-all,测试 job 也有写权限。
  • 把生产密钥放仓库级 Secrets,任何 workflow 都能读。
  • OIDC 信任条件写成所有 repo,风险反而扩大。
  • 公开仓库使用自托管 runner,接受不可信代码执行。
  • 依赖 main 分支的 action,更新后没有审查。

排错路径

  • job 报 403:检查 GITHUB_TOKEN permissions 是否缺所需 scope。
  • OIDC token 无法获取:确认 job 有 id-token: write,并检查云角色信任条件。
  • Environment 密钥不可见:确认 job 声明了对应 environment。
  • required reviewers 不触发:检查 environment protection rule 和 deployment branch。
  • 自托管 runner 被滥用:立即移除公开仓库 runner,并轮换可能暴露的 Secrets。

后续维护建议

更新日期:2026-08-11。建议每季度检查一次 workflow permissions、Environment 列表、OIDC 角色和第三方 action。每次新增部署能力时,先在测试环境验证最小权限,再复制到生产。长期 Secrets 能迁移到 OIDC 就迁移,不能迁移时至少设置过期和轮换提醒。

公开来源

  1. GitHub Docs: GITHUB_TOKEN
  2. GitHub Docs: Secure use reference
  3. GitHub Docs: OpenID Connect

订阅更新

输入邮箱,订阅站点更新。

参与讨论

你的邮箱不会公开。 标有 * 的为必填项。