GitHub Actions 安全加固实战:CI/CD 供应链攻击防护配置

适用场景

GitHub Actions 安全加固适用于以下场景:团队使用 GitHub Actions 构建、测试并部署生产代码;仓库包含数据库密码、云厂商密钥、API Token 等敏感凭据;CI 流程依赖第三方 action 或自定义脚本;使用自托管 runner 执行流水线。近几年供应链攻击频发,攻击者通过投毒流行 action、窃取 secrets、劫持 runner 等方式横向渗透,CI/CD 管道已成为攻破生产环境的捷径,本文给出可直接复制的加固配置。

前置条件

  • 一个 GitHub 仓库(公开或私有均可),具有 Admin 权限
  • 已启用 GitHub Actions(Settings → Actions → General)
  • 如需自托管 runner,准备一台独立的 Linux 虚拟机或容器

原理说明

GitHub Actions 供应链攻击的核心是利用信任链:工作流中引用的第三方 action、运行环境变量、secrets 注入机制和 runner 权限。常见攻击路径有四条:一是action 投毒,攻击者向流行 action 提交恶意代码或劫持失活账户(如 2021 年 CVE-2021-32688 的 tj-actions/changed-files);二是secrets 泄露,恶意脚本通过环境变量或日志输出窃取仓库 secrets;三是 pull_request_target 滥用,让不可信 PR 代码运行在拥有 secrets 的上下文中;四是自托管 runner 失陷,runner 上残留的 secrets 和缓存被攻击者读取。加固思路是:最小化权限、隔离敏感上下文、固定依赖版本、加密存储凭据。

操作步骤

1. 工作流权限最小化

在仓库 Settings → Actions → General → Workflow permissions 中,将默认权限改为 Read repository contents,禁止 Actions 创建或审批 PR;对每个工作流通过 permissions 字段显式声明所需权限:

name: build
on: [push]
permissions:
  contents: read        # 只读仓库内容
  packages: read        # 只读容器包
  issues: none          # 不需要 issues 权限
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build

2. Secrets 保护策略

将敏感信息存入 Settings → Secrets and variables → Actions,避免硬编码在仓库中。环境级 secrets 只注入到指定环境,防止开发分支访问生产凭据:

# 环境级 secrets 使用示例
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production    # 仅 production 环境有 DEPLOY_KEY
    steps:
      - name: Deploy
        env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
        run: ./deploy.sh

关键参数environment 将 secrets 作用域限定到指定环境,配合环境保护规则(必须审核才可部署)可大幅降低泄露面。

3. 第三方 action 固定版本与校验

引用第三方 action 时禁止使用 @main@master 等浮动分支,必须固定到完整 commit SHA,并开启 Dependabot 自动更新:

# 不安全的写法
- uses: actions/checkout@main

# 安全写法:固定 commit SHA
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11  # v4.1.1

同时限制仓库允许的 action 来源:Settings → Actions → General → Actions permissions 选择 Allow select actions,仅允许 GitHub 官方 action 和白名单仓库。

4. 防止 pull_request_target 滥用

pull_request_target 在默认分支上下文中运行,可访问 secrets。若必须使用,将不可信的 PR 代码放入单独步骤并用最小权限执行,且不要 checkout 并执行 PR 中的构建脚本:

# 危险用法:checkout PR 代码并运行
on: pull_request_target
jobs:
  comment:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      # 绝不在此处执行 PR 代码中的脚本!

# 安全用法:只在默认分支上下文运行固定逻辑
on: pull_request_target
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - name: Comment PR
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '审核通过'
            })

5. 自托管 runner 隔离

自托管 runner 与公司内网直接相连,是横向移动的跳板。为每个项目单独部署 runner,以专用低权限账号运行,禁止复用 root 账号;runner 所在主机不存放其他服务的凭据,并限制其网络出口(仅放行构建所需域名)。定期清理 runner 上的 _work 目录与缓存:

# 创建专用 runner 用户
sudo useradd -m -s /bin/bash runner-user

# 清理历史构建缓存
rm -rf /home/runner-user/actions-runner/_work/*
rm -rf /home/runner-user/actions-runner/_diag/*

# 限制网络出口(仅放行必要域名)
sudo iptables -A OUTPUT -d github.com -j ACCEPT
sudo iptables -A OUTPUT -d api.github.com -j ACCEPT
sudo iptables -A OUTPUT -j DROP

6. 审计与监控

开启仓库的 Audit log(Enterprise 版),定期检查 Secrets scanning 告警,将 Actions 运行日志接入日志平台。对 workflow 文件变更设置分支保护规则,要求 PR 审核后方可合并,防止攻击者直接修改 .github/workflows/ 注入恶意代码。

配置验证

# 1. 推送一个测试分支触发工作流,确认 permissions 生效
git push origin test

# 2. 在 Actions 页面检查每次运行的权限
# 打开运行详情 → Job summary,查看 "GITHUB_TOKEN Permissions" 仅含已声明项

# 3. 验证 secrets 不泄漏:在日志中 grep 关键字符串
# 若在 Actions 日志中搜索到 secrets 值,说明配置有误,立即撤销并轮换

常见问题

Q1:固定到 commit SHA 后,第三方 action 如何升级?

启用 Dependabot(Settings → Security → Dependabot alerts),它会自动为引用了旧 SHA 的 action 创建升级 PR。升级 PR 中应人工检查 action 的变更记录(尤其是 diff),确认无恶意改动后再合并,而不是盲目点击 “Update branch”。

Q2:secrets 是否安全?为什么说 secrets 放在 GitHub 不等于绝对安全?

secrets 加密存储在 GitHub 侧,但一旦工作流中被 ${{ secrets.XXX }} 引用,就会以明文注入到 runner 的进程环境变量,任何在该步骤内执行的恶意代码都能读取。因此除了存放位置,更要限制谁能在哪些上下文(环境、分支、PR)触发对 secrets 的访问,并对 secrets 设置有效期与轮换机制

Q3:公开仓库使用 GitHub Actions 有什么额外风险?

公开仓库任何 fork 的 PR 都可能触发工作流(若配置了 pull_request 事件),攻击者可在 PR 中提交恶意 workflow 改动或利用已存在工作流的漏洞。建议公开仓库关闭 pull_request 自动触发、启用 “Require approval for first-time contributors”,并严格控制第三方 action 白名单。

总结

GitHub Actions 安全加固的核心是信任最小化:权限按需声明、secrets 环境隔离、action 固定 SHA、runner 独立隔离、工作流变更走审核。这五步配置成本低、见效快,能有效阻断绝大多数针对 CI/CD 管道的供应链攻击。建议将上述检查项写入团队安全基线,每季度复核一次。