GitHub Actions OIDC 云认证:无需密钥的安全 AWS/Azure/GCP 集成

深入讲解 GitHub Actions 的 OpenID Connect (OIDC) 认证机制,涵盖 AWS IAM Role、Azure Managed Identity、GCP Workload Identity 的配置实战,以及供应链安全加固与无密钥架构的完整落地路径,帮助团队彻底消除 CI/CD 中的长期云凭证泄露风险。

2023 年,某知名开源项目的 npm 发布 token 因泄露被恶意利用,攻击者在供应链中植入了后门代码。这类事件的根源几乎总是同一个:CI/CD 系统中存储的长期云凭证。GitHub Actions 在 2021 年底推出的 OIDC(OpenID Connect)认证机制,彻底改变了这一局面——通过短期、自动轮换的 token 替代静态密钥,实现了「零长期凭证」的云资源访问架构。本文将系统讲解 OIDC 的原理、三大云平台的配置实战,以及落地过程中的安全加固策略。


一、为什么传统密钥认证不再安全

1.1 长期凭证的根本风险

# ❌ 传统方式:将 AWS 密钥硬编码在仓库 secrets 中
env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
风险点说明发生频率
密钥泄露被意外提交到代码、日志或第三方服务高频
权限过大为了方便,密钥通常授予过度权限极高
轮换困难手动轮换密钥容易遗漏某些系统中频
审计盲区无法追踪「谁在何时使用密钥做了什么」极高
供应链传递fork 的 PR 可能意外读取 secrets中频

1.2 OIDC 如何解决这些问题

OIDC 的核心思想是:GitHub Actions 临时生成一个 JWT token,云平台验证其签名后授予短期权限

传统模式:
开发者 ──生成──► 长期 AWS 密钥 ──存储──► GitHub Secrets ──注入──► Workflow
                                                                  │
                                                             泄露 = 永久风险

OIDC 模式:
GitHub ──签发──► 短期 JWT (15分钟) ──交换──► 云平台临时 token ──访问──► 资源
               │
               └── 自动过期,无需存储,每次 job 独立

优势对比

维度传统密钥OIDC
有效期永久(直到手动删除)最短 5 分钟,最长 1 小时
存储位置GitHub Secrets / 配置文件无需存储,运行时生成
权限粒度粗粒度(关联到 IAM User)细粒度(关联到 IAM Role + 条件判断)
审计追踪模糊(只知道密钥 ID)精确(知道仓库、workflow、job、commit)
泄露影响永久、全局限定在 token 有效期内

二、OIDC 认证机制详解

2.1 JWT Token 的结构

GitHub Actions 在每个 job 开始时,向 GitHub OIDC Provider 请求一个 JWT:

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "12345678"
}
.
{
  "sub": "repo:my-org/my-repo:ref:refs/heads/main",
  "aud": "https://github.com/my-org",
  "repository": "my-org/my-repo",
  "repository_owner": "my-org",
  "workflow": "deploy",
  "run_id": "1234567890",
  "run_attempt": "1",
  "actor": "username",
  "head_ref": "",
  "base_ref": "",
  "event_name": "push",
  "ref": "refs/heads/main",
  "ref_type": "branch",
  "job_workflow_ref": "my-org/my-repo/.github/workflows/deploy.yml@refs/heads/main",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1699999999,
  "exp": 1700000599,
  "iat": 1699999999
}

关键字段

字段含义信任条件示例
sub主体标识只信任特定仓库的分支
repository来源仓库限制为白名单仓库
workflow触发 workflow 名称只允许 deploy.yml
refGit ref(分支/tag)只允许 refs/heads/main
iss签发者必须是 GitHub 官方
aud受众限制为特定组织

2.2 认证流程

Workflow Job 启动
      │
      ▼
GitHub OIDC Provider ──签发──► JWT Token
      │                         │
      │                         │ 携带 JWT 调用云 STS API
      │                         ▼
      │                    AWS/Azure/GCP
      │                    └── 验证 JWT 签名(通过 GitHub 公钥)
      │                    └── 检查 trust policy(sub/aud/ref 匹配)
      │                    └── 颁发临时凭证(15-60 分钟)
      │                         │
      │                         ▼
      │                    Workflow 使用临时凭证访问云资源
      │
      ▼
Job 结束 ──token 自动失效──► 无残留凭证

三、AWS 配置实战

3.1 创建 OIDC Identity Provider

# 在 AWS IAM 控制台或使用 CLI 创建
aws iam create-open-id-connect-provider \
  --url https://token.actions.githubusercontent.com \
  --thumbprint-list 6938fd4e98bab03faadb97b34396831e3780aea1 \
  --client-id-list sts.amazonaws.com

3.2 创建信任 GitHub 的 IAM Role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012: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:*"
        }
      }
    }
  ]
}

条件说明

条件作用严格程度
StringLike + repo:my-org/my-repo:*信任该仓库的所有分支和 tag中等
StringEquals + ref:refs/heads/main只允许 main 分支
StringEquals + workflow:deploy.yml只允许特定 workflow 文件极高

3.3 GitHub Actions Workflow

name: Deploy to AWS
on:
  push:
    branches: [main]

permissions:
  id-token: write   # 必需:请求 OIDC JWT token
  contents: read    # 必需:检出代码

jobs:
  deploy:
    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::123456789012:role/GitHubActionsDeployRole
          aws-region: us-east-1

      - name: Deploy to S3
        run: |
          aws s3 sync ./dist s3://my-bucket/

关键permissions: id-token: write 是获取 JWT 的前提。如果省略,workflow 会失败。

3.4 IAM Role 的最小权限策略

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

原则:OIDC Role 的权限应比传统 IAM User 更严格——因为你能精确控制「哪个仓库的哪个 workflow 的哪个分支」才能获取凭证。


四、Azure 配置实战

4.1 创建 App Registration 和 Federated Credential

# 1. 创建 App Registration
az ad app create --display-name "GitHubActionsOIDC"

# 2. 创建 Service Principal
az ad sp create --id <app-id>

# 3. 添加 Federated Credential(信任 GitHub)
az ad app federated-credential create \
  --id <app-id> \
  --parameters '{
    "name": "github-main-branch",
    "issuer": "https://token.actions.githubusercontent.com",
    "subject": "repo:my-org/my-repo:ref:refs/heads/main",
    "audiences": ["api://AzureADTokenExchange"]
  }'

4.2 GitHub Actions Workflow

name: Deploy to Azure
permissions:
  id-token: write
  contents: read

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

      - 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 }}

      - name: Deploy to App Service
        run: az webapp deploy --resource-group my-rg --name my-app --src-path ./dist

Azure 的 OIDC 实现需要显式指定 client-idtenant-idsubscription-id,但这些不再是敏感密钥,而是公开标识符——真正的认证由 OIDC 流程完成。


五、GCP 配置实战

5.1 配置 Workload Identity Federation

# 1. 创建 Workload Identity Pool
gcloud iam workload-identity-pools create "github-pool" \
  --location="global" \
  --display-name="GitHub Actions Pool"

# 2. 创建 OIDC Provider
gcloud iam workload-identity-pools providers create-oidc "github-provider" \
  --location="global" \
  --workload-identity-pool="github-pool" \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --allowed-audiences="https://github.com/my-org" \
  --attribute-mapping="google.subject=assertion.sub"

# 3. 绑定 Service Account
gcloud iam service-accounts add-iam-policy-binding \
  deployer@my-project.iam.gserviceaccount.com \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/projects/my-project/locations/global/workloadIdentityPools/github-pool/subject/repo:my-org/my-repo:ref:refs/heads/main"

5.2 GitHub Actions Workflow

name: Deploy to GCP
permissions:
  id-token: write
  contents: read

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

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

      - name: Deploy to Cloud Run
        uses: google-github-actions/deploy-cloudrun@v2
        with:
          service: my-service
          source: ./

六、跨云平台统一策略

6.1 多云部署的权限设计

当项目同时部署到 AWS、Azure、GCP 时,推荐为每个云平台创建独立的 IAM Role,而非使用一个超级凭证:

jobs:
  deploy-aws:
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with: { role-to-assume: arn:aws:iam::...:role/GitHubActionsAWSRole }

  deploy-azure:
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: azure/login@v2
        with: { client-id: ..., tenant-id: ..., subscription-id: ... }

  deploy-gcp:
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: google-github-actions/auth@v2
        with: { workload_identity_provider: ..., service_account: ... }

6.2 环境隔离策略

jobs:
  deploy-staging:
    environment: staging
    permissions:
      id-token: write
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::STAGING-ACCOUNT:role/DeployRole

  deploy-production:
    environment: production  # 触发审批
    permissions:
      id-token: write
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::PROD-ACCOUNT:role/DeployRole

七、安全加固与审计

7.1 Trust Policy 的精细化配置

最宽松的配置(不推荐)

"Condition": {
  "StringLike": {
    "token.actions.githubusercontent.com:sub": "repo:my-org/*:*"
  }
}

最严格的配置(推荐)

"Condition": {
  "StringEquals": {
    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
    "token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main",
    "token.actions.githubusercontent.com:workflow": "deploy"
  }
}

7.2 CloudTrail / Activity Log 审计

AWS CloudTrail 会记录每次 AssumeRoleWithWebIdentity 调用:

{
  "eventName": "AssumeRoleWithWebIdentity",
  "requestParameters": {
    "roleArn": "arn:aws:iam::...:role/GitHubActionsDeployRole",
    "roleSessionName": "GitHubActions"
  },
  "responseElements": {
    "subject": "repo:my-org/my-repo:ref:refs/heads/main",
    "issuer": "https://token.actions.githubusercontent.com"
  }
}

这意味着你可以精确审计:哪个仓库的哪次 workflow 在哪个时间获取了云凭证


八、常见问题解答(FAQ)

Q1: OIDC token 在 workflow 中如何手动获取?

curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
  "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.amazonaws.com"

通常不需要手动获取,aws-actions/configure-aws-credentials 等官方 action 会自动处理。

Q2: 私有仓库是否支持 OIDC?

完全支持。OIDC 与仓库公开性无关,只与 workflow 的 permissions: id-token: write 有关。

Q3: 自托管 Runner 是否支持 OIDC?

支持,但需要确保 Runner 能访问 https://token.actions.githubusercontent.com。在完全离线的内网 Runner 上,OIDC 不可用。

Q4: 迁移现有密钥到 OIDC 的步骤?

  1. 创建 OIDC Identity Provider 和 IAM Role
  2. 在 workflow 中添加 permissions: id-token: write
  3. 替换 secrets.AWS_ACCESS_KEY_IDrole-to-assume
  4. 在测试环境验证权限边界
  5. 删除旧的 IAM User 和 secrets

总结

OIDC 不是「另一个认证选项」,而是 CI/CD 云资源访问的安全范式转变。从「长期密钥永不失效」到「短期 token 每次生成、每次过期」,从「模糊审计」到「精确的仓库-workflow-分支-提交级追踪」,OIDC 为现代软件供应链安全提供了基础设施级的保障。

实施检查清单

  • 所有 GitHub → 云的访问已迁移到 OIDC
  • IAM Role 的 trust policy 包含细粒度条件(仓库、分支、workflow)
  • IAM Role 的权限策略遵循最小权限原则
  • 生产部署启用了 Environment 审批保护
  • CloudTrail / Activity Log 已启用并定期检查
  • 旧的 IAM User 和静态密钥已清理删除

完成以上检查后,你的 CI/CD 基础设施将达到当前业界最高安全水位。


延伸阅读

继续阅读

探索更多技术文章

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

全部文章 返回首页

「github-actions」更多文章

  1. GitHub Actions 通知与 ChatOps:Slack/钉钉/飞书集成与评论触发工作流
  2. GitHub Actions 自托管 Runner:架构设计、安全隔离与大规模部署
  3. GitHub Actions 缓存优化完全指南:从 actions/cache 到分层依赖管理