🐧

GitHub ActionsでOpenID Connect(OIDC)認証を使ってTerraformをデプロイする(AWS)

2024/08/14に公開

はじめに

GitHub Actionsを使ったAWSへのTerraformデプロイ方法について、OpenID Connect(OIDC)を使用したセキュアな認証方法を使用する方法で設定してみます。
この方法を使うことで、AWSのアクセスキーを直接GitHub Secretsに保存する必要がなくなり、よりセキュアなCI/CDパイプラインを構築することができます。

OIDCとは

OpenID Connect(OIDC)は、OAuth 2.0プロトコルの上に構築された認証レイヤーです。OIDCを使用することで、アプリケーション(この場合はGitHub Actions)は別のサービス(AWS)に対して安全に認証を行うことができます。

GitHub ActionsのOIDC認証フロー

GitHub ActionsでAWS IAMロールのOIDC認証フローは通常の下記のようになります。

以下に各ステップの詳細を説明します:

  1. GitHub Actionsワークフローが開始されると、GitHub OIDCプロバイダーにOIDCトークン(JWT) をリクエストします。
  2. GitHub OIDCプロバイダーは、ワークフローに対して一意のトークンを発行します。このトークンには、リポジトリ名、ブランチ名、ジョブ名などの情報が含まれます。
  3. GitHub Actionsは、このトークンを使用してAWS Security Token Service (STS) の AssumeRoleWithWebIdentity APIを呼び出します。
  4. AWS STSは、受け取ったトークンを使用してAWS IAMロールに対する認証を試みます。IAMロールには、GitHub OIDCプロバイダーを信頼するように設定されたトラストポリシーが定義されている必要があります。
  5. AWS IAMは、トークンの内容とトラストポリシーを照合し、ロールの引き受けを承認します。
  6. 承認が成功すると、AWS STSはGitHub Actionsに対して一時的なAWS認証情報を提供します。
  7. GitHub Actionsは、これらの一時的な認証情報を使用してAWSのサービス(S3、EC2、RDSなど)にアクセスし、必要なタスクを実行します。
  8. AWSサービスは、リクエストに応じてレスポンスを返します。

なぜOIDCを使用するのか

セキュリティの向上:長期的なAWSアクセスキーをGitHubに保存する必要がありません。
管理の簡素化:アクセスキーのローテーションが不要になります。
細かなアクセス制御:特定のリポジトリやブランチからのみAWSリソースにアクセスできるように制限できます。

設定手順

前提条件

  1. デプロイするためのAWSアカウントがあること
  2. Terraform実行する環境が準備できていること
    環境構築手順は下記記事を参照ください
    Terraformを使うための環境構築手順をまとめてみた(AWS編)~Windows
  3. GitHubアカウントがあること

1.GitHubでOrganizationを設定する

  1. GitHubのコンソールで「Organizations」→「New Organization」を選択します

    GitHubプランの選択画面が出ます。今回はFreeプランで問題ないので、一番左のFreeプランの「Create a free organization」を選択します。

  2. Organization Name、Contact emailを入力します。今回は個人用なので「My personal account」を選択します



  3. 作成したOrganizationにユーザーを追加する画面になります
    作成したユーザーはすでに追加されていますので、そのまま「Complete setup」を選択します。

    Confirm accessで、再度GitHubのアクセスキーなどを入力して、Organization作成完了です。
    作成したOrganization名は、のちほど使用します。

  4. GitHub Actionsを使用するリポジトリを作成します
    Organizationで、「Repositories」→「New repository」を選択します。


  5. 下記のような設定でリポジトリを作成します
    Repository name:適当に名前をつけます
    Private:今回はプライベートとします
    Add .gitignore:今回はTerraformのHCLを管理するつもりなのでTerraformを選択
    DescriptionとREADMEはお好みで、Choose a licenseは必要に応じて

    「Create repository」を選択してリポジトリを作成します。

2.AWSでOIDCプロバイダーを設定する

GitHubの公式手順はこちら


OIDCプロバイダーやIAMロールもTerraformで作成したほうが管理しやすいと思いますが、今回はマネージメントコンソールで作成していきます。

  1. AWSマネージメントコンソールでIAMに移動し、「IDプロバイダー」→「プロバイダーを追加」を選択します


  2. 「プロバイダーの設定」で下記のように設定します
    タイプ:OpenID Connect
    プロバイダーURL:https://token.actions.githubusercontent.com
    対象者(Audience):sts.amazonaws.com



    タグはお好みで入力して「プロバイダーを追加」を押すと、プロバイダーが追加されました。


3.IAMロールを作成する

  1. IAM コンソールで「ロール」→「ロールの作成」を選択します


  2. 「信頼されたエンティティを選択 」で下記のように設定して「次へ」を選択します
    信頼されたエンティティタイプ:ウェブアイデンティティ
    アイデンティティプロバイダー:2で作成したGitHub ActionsのOIDCプロバイダー(https://token.actions.githubusercontent.com
    Audience:2で設定したAudience(sts.amazonaws.com
    GitHub組織:1で設定したGitHub Organization名
    GitHubリポジトリ-オプション:許可するGitHubリポジトリとして1で作成したリポジトリ名
    GitHub ブランチ-オプション:許可するGitHubブランチ(今回はスキップ)

  3. 必要なAWSの権限を付与して「次へ」を選択します
    GitHub Actionsをじっこうするにあたり必要な権限を持つポリシーを選択します。
    今回はAdministratorAccessを選択しますが、本来は必要最低限なポリシーを付与することが望ましいです。


  4. ロール名を入力して「ロールを作成」を選択します


4.GitHub ActionsのSecretを作成する

GitHub Actionsのワークフロー内で使用するシークレットを登録します。
https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions
今回は3で作成したロールのARNをシークレットとして登録しておきます。
GitHubコンソールで1で作成したリポジトリを選択し、「Setting」タブから左メニュー内「Secrets and variables」のactionsを選択します。

「New repository secret」を押します。

シークレット名はASSUME_ROLE_ARNとし、Secretは3で作成したロールのARN(arn:aws:iam::123456789012:role/kiku_github_terraform)を設定します。

「Add secret」でシークレットを登録します。


5.GitHub Actionsワークフローを作成する

GitHub Actionsでワークフローを作成していきます。

  1. まず1で作成したリポジトリをローカルPCにCloneします
    普通にcloneしようとすると下記のようなSign inウィンドウが出ると思うので、WebブラウザやTokenを使用してSign inします。


  2. ローカルPCにCloneしたリポジトリのフォルダを開きます
    おそらくなかには.gitignoreやREADMEなどがあると思います(リポジトリ作成時の設定によっては何もない場合があります)。
    .githubというフォルダを作成してフォルダを開き、なかにworkflowsというフォルダを作成します。
    私の場合は下記のようなフォルダ構成となります。



    workflowsフォルダ内にGitHub Actionsの動作を定義するYAMLファイルを下記のように作成します。

name: Terraform Deploy
env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

on:
  push:
    branches:
      - main
    paths:
      - "terraform/**"

jobs:
  deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{secrets.ASSUME_ROLE_ARN}}
          aws-region: ap-northeast-1

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.9.1

      - name: Terraform Init
        run: terraform -chdir=./terraform init

      - name: Terraform Plan
        run: terraform -chdir=./terraform plan

      - name: Terraform Apply
        run: terraform -chdir=./terraform apply -auto-approve

env: GitHub Actionsワークフロージョブの認証用トークン${{ secrets.GITHUB_TOKEN }}を設定します。
こちらはあらかじめ用意されているシークレットなので自分でシークレットを登録する必要はありません。
https://docs.github.com/ja/actions/security-for-github-actions/security-guides/automatic-token-authentication


on:ワークフローのトリガを設定します。
今回はmainブランチのterraform下にpushされた場合の自動トリガと手動トリガの両方を設定しておきます。


runs-on: ジョブを実行するランナーの設定をします。
セルフホステッドランナーを使用する場合もここで設定します。
https://docs.github.com/ja/actions/writing-workflows/choosing-where-your-workflow-runs/choosing-the-runner-for-a-job


timeout-minutes: ジョブのタイムアウト設定です。
設定しない場合はタイムアウトはデフォルト360分となりますので、適切な値を設定しておいたほうがいいと思います。
https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes


permissions: ジョブの権限設定です。
https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/assigning-permissions-to-jobs


steps: ここで実際の動作を記載していきます。
usesは、あらかじめ用意されたアクションを設定します。
actions/checkout@v4actions/はGitHub公式のアクションです。
hashicorp/などはサードパーティのアクションとなります。
checkout@v4checkoutがアクション名となり、@v4がバージョンになります。
withで変数を設定します。
runは、任意のコマンドを実行します。


role-to-assumeのところには[4](#4.GitHub ActionsのSecretを作成する)で作成したロールのシークレット(ASSUME_ROLE_ARN)を設定しています。


GitHub Actions実行結果をSlackなどに通知するジョブを記載しておくと、GitHubコンソールで結果を確認しなくてもよいので楽です(今回は省略します)。


GitHub Actionsワークフローの記載方法の詳細は下記
https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions

  1. 作成したYAMLをPushしておきます
git add .
git commit -m "Add GitHub workflow"
git push origin main

6.GitHub Actionsワークフロー実行

  1. リポジトリ直下にterraformフォルダを作成します
  2. terraformフォルダ直下でtfファイルを作成します
    下記を参考に簡単なtfファイルを作成します。
    Terraformを使うための環境構築手順をまとめてみた(AWS編)~Windows
    下記のような感じで一旦VPCとサブネットをデプロイしてきます。
resource "aws_vpc" "main" {
  cidr_block       = "10.1.0.0/16"
  instance_tenancy = "default"

  tags = {
    Name = "test-vpc"
  }
}

resource "aws_subnet" "main" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.1.0.0/24"

  tags = {
    Name = "private"
  }
}
  1. tfファイルをPushします。
git add main.tf provider.tf
git commit -m "Add terraform tf file"
git push origin main

これによりワークフローがトリガされて、TerraformでVPCとサブネットが作成されます。

  1. GitHubコンソールで対象リポジトリのActionsタブを開くと、workflowが並んでいます。
    実行中のワークフローは黄色マークがついており、失敗(エラー)が赤、成功は緑となっています。
    (ちなみに最初のワークフローは私のミスによりエラーになりました...)

    ワークフローをクリックすると、詳細情報を確認できます。
    下記だとワークフローが30秒で完了していますが、初めて実行したワークフローの場合はもっと時間がかかると思います。

    ワークフロー内の各stepの実行内容も確認することができます。

  2. AWSマネージメントコンソールで確認すると、ちゃんとリソースが作成されています。

まとめ

GitHub ActionsをOIDC認証で使えるように設定し、実際にGitHub ActionsのワークフローでTerraformを実行してAWS環境にデプロイしてみました。

Discussion