GitHub Actions 安全与 Secret 管理:权限控制、OIDC 认证、审计与最佳实践

GitHub Actions 安全深度指南:最小权限原则、Secrets 管理策略、OIDC 免密云认证(AWS/Azure/GCP)、Artifact 安全、权限审计、依赖供应链安全(Dependabot/CodeQL)、Self-hosted Runner 隔离,以及常见安全漏洞与防护。

CI/CD 管道是供应链攻击的主要目标。源码、构建环境、密钥一旦泄露,攻击者可以直接植入恶意代码、窃取数据或劫持部署。本文从权限配置到认证机制,构建 GitHub Actions 的完整安全防线。


一、最小权限原则(Principle of Least Privilege)

1.1 默认关闭权限,按需分配

# ❌ 危险:默认赋予所有权限
# (不设置 permissions 时,默认读写所有内容)

# ✅ 推荐:显式声明最小权限
permissions:
  contents: read           # 只读代码
  pull-requests: write     # 仅 PR 操作
  id-token: write          # OIDC Token(云认证)

jobs:
  deploy:
    permissions:
      contents: read
      packages: write      # 推送容器镜像
      id-token: write

权限级别:

级别作用域说明
read只读safest,默认首选
write读写需要修改资源时使用
none无权限显式禁用

1.2 组织级权限策略

# 在组织级别限制默认权限
# GitHub Organization → Settings → Actions → General
# Default workflow permissions: Read repository contents and packages permissions

二、Secrets 管理策略

2.1 Secret vs Variable:明确区分

类型存储方式日志显示适用
Secrets加密存储❌ 隐藏(显示为 ***)API Key、Token、密码
Variables明文存储✅ 可见环境名、Region、版本号

2.2 Secret 注入正确方式

# ✅ 正确:env 注入,避免命令行回显
jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      API_KEY: ${{ secrets.API_KEY }}
    steps:
      - run: |
          curl -H "Authorization: Bearer $API_KEY" https://api.example.com

# ❌ 危险:直接在命令行使用(部分 CI 系统会回显)
# - run: curl -H "Authorization: Bearer ${{ secrets.API_KEY }}" ...

2.3 Secret 轮转策略

Secret 类型轮转周期方式
云平台 Access Key90 天IAM 控制台重新生成
npm Token180 天npm 网站重新生成
Docker Hub Token90 天Account Settings → Security
SSH 密钥180 天ssh-keygen 重新生成

三、OIDC 免密云认证

3.1 为什么用 OIDC?

传统方式将云服务密钥(AWS Access Key)存为 Secrets,存在泄露风险。OIDC(OpenID Connect)让 GitHub Actions 通过 JWT Token 临时换取云服务的访问凭证,无需长期密钥。

3.2 AWS OIDC 配置

permissions:
  id-token: write
  contents: read

jobs:
  deploy-aws:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
          aws-region: us-east-1
          role-duration-seconds: 1200  # 临时凭证有效期

      - run: aws s3 sync ./dist s3://my-bucket

AWS IAM 信任策略:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com" },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" },
      "StringLike": { "token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:*" }
    }
  }]
}

3.3 Azure OIDC

- name: Azure Login
  uses: azure/login@v2
  with:
    client-id: ${{ secrets.AZURE_CLIENT_ID }}
    tenant-id: ${{ secrets.AZURE_TENANT_ID }}
    subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

3.4 GCP OIDC

- name: GCP Auth
  uses: google-github-actions/auth@v2
  with:
    workload_identity_provider: 'projects/123/locations/global/workloadIdentityPools/github-pool/providers/github-provider'
    service_account: 'github-actions@my-project.iam.gserviceaccount.com'

四、依赖与供应链安全

4.1 Dependabot 自动化依赖更新

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    reviewers:
      - "octocat"

4.2 CodeQL 安全扫描

name: CodeQL
on:
  push: { branches: [main] }
  pull_request: { branches: [main] }
  schedule: [ cron: '0 9 * * 1' ]

jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: javascript, typescript
      - uses: github/codeql-action/analyze@v3

4.3 npm audit 在 CI 中

- run: npm audit --audit-level=moderate
- run: npm audit fix --dry-run  # 查看建议修复

4.4 SLSA 来源证明

- uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
  with:
    base64-subjects: "${{ hashFiles('dist/**') }}"

4.5 Sigstore 签名与验证

对构建产物进行密码学签名,防止中间人替换:

- name: Sign artifact with Sigstore
  uses: sigstore/cosign-installer@v3
- run: |
    cosign sign-blob --yes dist/app.tar.gz \
      --output-signature dist/app.tar.gz.sig \
      --output-certificate dist/app.tar.gz.crt

客户端验证:

cosign verify-blob --signature app.tar.gz.sig \
  --certificate app.tar.gz.crt \
  --certificate-identity-regexp="^https://github.com/my-org/my-repo/.github/workflows/.*" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  app.tar.gz

五、Self-hosted Runner 安全

5.1 Runner 隔离策略

隔离级别方法效果
用户隔离每个 runner 独立用户防止跨项目访问
容器隔离Docker-in-Docker每个 job 独立容器
VM 隔离每次启动新 VM最强隔离,启动较慢
临时 Runner用完即销毁最高安全

5.2 Runner 标签策略

jobs:
  deploy-production:
    runs-on: [self-hosted, production]  # 标签限制

六、常见安全漏洞与防护

漏洞原因防护
秘密泄露硬编码 API Key使用 Secrets + OIDC
恶意 Action使用未审核第三方 Action固定 commit SHA,pin 版本
脚本注入${{ github.head_ref }} 在命令行中使用env 注入,避免字符串拼接
权限提升workflow 具有过高权限permissions: contents: read
Artifact 泄露敏感文件包含在 Artifact 中.gitignore + artifact 路径限制

七、监控与异常检测

7.1 工作流运行审计日志

name: Audit Log Monitor
on:
  workflow_run:
    workflows: ["*"]
    types: [completed]

jobs:
  audit:
    runs-on: ubuntu-latest
    permissions:
      actions: read
    steps:
      - uses: actions/github-script@v7
        with:
          script: |
            const run = context.payload.workflow_run;
            if (run.conclusion === "failure" && run.run_attempt > 3) {
              // 多次重试失败,可能存在攻击或配置篡改
              console.log("::warning:: 工作流多次失败后完成,请审查");
            }
            // 记录运行时长异常(正常 5min,突然 30min)
            const duration = (new Date(run.updated_at) - new Date(run.run_started_at)) / 60000;
            if (duration > 30) {
              console.log(`::warning:: 工作流运行异常耗时 ${duration.toFixed(1)} 分钟`);
            }

7.2 Secrets 访问告警

通过 GitHub Enterprise Cloud 的 Audit Log API,监控 Secrets 被意外访问的事件:

curl -H "Authorization: token $TOKEN" \
  "https://api.github.com/orgs/my-org/audit-log?phrase=action:secret_scanning&per_page=100"

7.3 环境保护规则(Environment Protection Rules)

对生产环境部署添加人工审批或分支限制:

jobs:
  deploy-production:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://app.mycompany.com
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh production

在 GitHub UI 中配置:

  • Settings → Environments → production → Deployment branches: main 分支限定
  • Required reviewers: 至少 1 名管理员审批
  • Wait timer: 300 秒冷却期(防止快速误操作)

八、安全审计检查清单

  • 组织级别设置默认只读权限
  • 所有工作流显式声明 permissions
  • Secrets 使用 env: 注入而非命令行
  • 使用 OIDC 替代长期云密钥
  • 第三方 Action 固定到 commit SHA
  • Dependabot 启用自动更新
  • CodeQL 启用安全扫描
  • npm audit 在 CI 中阻塞高危漏洞
  • Self-hosted Runner 启用标签隔离
  • 定期轮转 Secrets(90 天)
  • 启用 Sigstore 签名验证构建产物
  • 配置异常运行时长与重试次数告警

相关阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「saas」更多文章

  1. 短链接对 SEO 的影响与优化最佳实践
  2. UTM 参数 + 短链接:追踪每一条营销链路
  3. 私域流量运营中的短链接策略:从引流到转化