技術(tech)

GitHub Actions – AWSのシークレットキー不要! OIDCで安全にIAM Roleを使う構成をTerraformで構築

はじめに

GitHub ActionsでAWSのリソースにアクセスするとき、シークレットキー(AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)をGitHub のシークレットに登録するのが一番簡単で、ついついやってしまいがちです。

しかし、これはキー漏洩のリスクがあるため、推奨されなくなっています。

そこで登場するのが OIDC(OpenID Connect) を用いた認証方式です。
これにより、シークレットキーなしで安全に AWS の IAM Role を引き受ける ことができます。

本記事では、GitHub Actions で OIDC を使って AWS の IAM Role を設定する方法を解説します。

OIDCとは?

  • OIDC は、OAuth 2.0 をベースにした認証プロトコル
  • これを利用すると、GitHub が「私は GitHub の公式リポジトリです」と AWS に証明できる
  • AWS は GitHub の証明を信頼し、指定したIAM Roleの一時的な認証情報を受け取る

なぜ OIDC を使うのか?

  • シークレットキー不要 → キー漏洩のリスクをなくせる
  • ジョブ実行中のみの一時的な認証情報を発行 → 固定のキーではなく、その都度認証トークンを発行するので安全

設定

シークレットキーを直接利用するパターン

イメージ図は以下の通りです。

  1. ユーザがIAMから直接、自分が必要とするIAM Roleのシークレットキーを発行する
  2. 入手したシークレットキーをGitHubActions側のSecretに保存して、利用する
  3. 実際にジョブを実行する中で、Secretの情報をジョブ側にInjectする

というのが、簡単な流れです。
この1, 2のステップの際に、ユーザが自らシークレットキーを発行して、設定しなければらないです。
このシークレットキーはExpireしないように、長い有効期限を設定する必要もあります。

これはセキュリティ上避けたいよね。という話もあり、必要な時だけ必要な権限を渡したい。という発想になります。

OIDCを利用するパターン

全体的な流れ

OIDCを利用する際には、少しだけ設定が増えます。

  1. IAM OIDC ID Providerを準備し、GitHubActionsが信頼出来るという情報を登録します
    (管理者しか触れないようなAWSアカウント側に、第三者のProviderは情報が登録されているということは、そのProviderは流石に安全だよね。なぜなら、乗っ取りでもされない限りはそのような情報を意図的に登録することはないから。という論法です。)
  2. GitHubActions側では、GitHub OIDC ProvderはJWT(JSON Web Token)を発行できるようにCI側に設定します
  3. あとはUserがジョブを実行するだけです。認証が完了した後に、要求したIAM Role可能なアクセストークンを受け取り(認可され)ます

この辺の話は以下のドキュメントも参考になります。

設定例(Terrraform)

0. 渡したい権限を持ったIAM Roleの準備

locals {
  # 環境に応じてプロバイダーのARNを構築
  github_oidc_arn = "arn:aws:iam::your-account-id:oidc-provider/token.actions.githubusercontent.com"
  github_oidc_url = "token.actions.githubusercontent.com"
}

# ECSタスク実行ロールの定義
resource "aws_iam_role" "ecs_task_role" {
  name = "EcsTaskRole-${var.env}"

  assume_role_policy = jsonencode({
    Version = "2008-10-17"
    Statement = [
      {
        Sid    = "GitHubOIDC"
        Effect = "Allow"
        Principal = {
          Federated = local.github_oidc_arn
        }
        Action = "sts:AssumeRoleWithWebIdentity"
        Condition = {
          StringEquals = {
            "${local.github_oidc_url}:aud" : "sts.amazonaws.com"
          }
          StringLike = {
            "${local.github_oidc_url}:sub" : "repo:your-repository-name/*:*"
          }
        }
      }
    ]
  })
}
  • IAM Policy Documentを定義して、定義を外出ししたほうが綺麗かもしれないです
  • このロールが使用可能なリポジトリの名前を指定して、対象を絞っているのがポイントです。セキュリティ上、関係の無いリポジトリがこのRoleを使えるようにするわけにはいきません

あとは、他にも必要な権限があれば、ポリシーを必要最低限アタッチします。

例えば、ECRを操作したい場合は、このような感じ

resource "aws_iam_policy" "ecr_push_policy" {
  name        = "ECRPushPolicy-${var.env}"
  description = "Allow pushing to ECR repositories"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = "ecr:GetAuthorizationToken"
        Resource = "*"
      },
      {
        Effect = "Allow"
        Action = [
          "ecr:BatchCheckLayerAvailability",
          "ecr:CompleteLayerUpload",
          "ecr:InitiateLayerUpload",
          "ecr:PutImage",
          "ecr:UploadLayerPart"
        ]
        Resource = [
          aws_ecr_repository.api.arn,
        ]
      }
    ]
  })
}

# ECRプッシュポリシーをECSタスク実行ロールにアタッチ
resource "aws_iam_role_policy_attachment" "ecr_push_policy_attachment" {
  role       = aws_iam_role.ecs_task_role.name
  policy_arn = aws_iam_policy.ecr_push_policy.arn
}
1. IAM OIDC ID Providerの準備
data "tls_certificate" "github_actions" {
  url = "https://token.actions.githubusercontent.com/.well-known/openid-configuration"
}

resource "aws_iam_openid_connect_provider" "github" {
  url = "https://token.actions.githubusercontent.com"

  client_id_list = ["sts.amazonaws.com"]

  thumbprint_list = [data.tls_certificate.github_actions.certificates[0].sha1_fingerprint]

  tags = {
    Name        = "github-actions"
    Environment = var.env
  }
}
2. GitHubActions側の設定
name: Deploy

on:
  push:
    branches:
      - develop
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  build_and_push:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::(your account id):role/EcsTaskRole-stg
        aws-region: ap-northeast-1
        role-session-name: GitHubActions

    - name: Login to Amazon ECR
      uses: aws-actions/amazon-ecr-login@v1

ポイントは以下です。

以下の設定を加えることで、GitHubActionsがJWTを自動的に生成することができるようになります。

permissions:
  id-token: write
  contents: read

ここでは事前に定義したRoleのARNを指定します。
これにより、認証完了後にこのロールをアクセストークンを入手できます。

    - uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::(your account id):role/EcsTaskRole-stg
        aws-region: ap-northeast-1
        role-session-name: GitHubActions
3. ジョブの実行

あとは実際に動作確認です。

まとめ

本記事では、GitHub Actions で AWS のリソースにアクセスする際に、OIDC(OpenID Connect)を利用して IAM Role を安全に引き受ける方法を解説しました。

従来の シークレットキー(AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)を直接 GitHub のシークレットに登録する方法 は、キー漏洩のリスクがあるため、OIDC を活用することでより安全な運用 が可能になります。

OIDC を使うメリット

  • シークレットキー不要 → 漏洩リスクを排除
  • ジョブ実行中のみ有効な一時的な認証情報を発行 → 最小権限の原則に適合
  • IAM Role のスコープをリポジトリ単位で制限 → 不要なアクセスを防止

OIDC の設定手順

  1. IAM OIDC ID プロバイダーを作成(AWS 側で GitHub の OIDC を信頼)
  2. IAM Role を作成し、OIDC で AssumeRole を許可(リポジトリを制限)
  3. GitHub Actions のワークフローに OIDC の設定を追加(id-token の権限を付与)
  4. AWS リソースへ安全にアクセス(ジョブ実行時に認証情報を取得)

ここまで見ていただき、ありがとうございました。