GitHub Actions から OIDC 認証で各クラウドを Terraform デプロイする – AWS 編

GitHub

GitHub Actions で Terraform を実行し、AWS にリソースをデプロイします。OIDC を利用することで、GitHub 内に AWS アカウントのシークレットなどを保存しなくて良いため、セキュリティが向上します。

公式ではこちらの手順が参考になります。

Configuring OpenID Connect in Amazon Web Services – GitHub Docs

スポンサーリンク

AWS でプロバイダーとロールを設定

まずは AWS 側で認証用の ID プロバイダーとロールの設定を行います。AWS コンソールからでもできるのですが、設定用のテンプレートが公開されているのでそちらを利用しました。

aws-actions/configure-aws-credentials: Configure AWS credential environment variables for use in other GitHub Actions.

こちらのテンプレートを利用すると、自動で ID プロバイダーとロールが作成されます。ロールに付与する権限は、ManagedPolicyArns の部分で必要に応じて調整します。今回は VPC、S3、EC2 の権限を持つ例として記載しています。

Parameters:
  GitHubOrg:
    Type: String
  RepositoryName:
    Type: String
  OIDCProviderArn:
    Description: Arn for the GitHub OIDC Provider.
    Default: ""
    Type: String
Conditions:
  CreateOIDCProvider: !Equals
    - !Ref OIDCProviderArn
    - ""
Resources:
  Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Action: sts:AssumeRoleWithWebIdentity
            Principal:
              Federated: !If
                - CreateOIDCProvider
                - !Ref GithubOidc
                - !Ref OIDCProviderArn
            Condition:
              StringLike:
                token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonVPCFullAccess
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/AmazonEC2FullAccess
  GithubOidc:
    Type: AWS::IAM::OIDCProvider
    Condition: CreateOIDCProvider
    Properties:
      Url: https://token.actions.githubusercontent.com
      ClientIdList:
        - sts.amazonaws.com
      ThumbprintList:
        - 6938fd4d98bab03faadb97b34396831e3780aea1
Outputs:
  Role:
    Value: !GetAtt Role.Arn

こちらのテンプレートを実行します。なお、パラメーターには次のように値を指定します。

  • GitHubOrg: アクセス元 GitHub リポジトリーの組織名やアカウント名
  • RepositoryName: アクセス元 GitHub リポジトリーのリポジトリー名
  • OIDCProviderArn: 空欄のままで OK (既存のプロバイダーを利用する場合に ARN を指定)

作成されたロールの ARN は次の手順で使うので確認して控えておきます。

ロールの中で Condition を指定する部分で、リクエスト元のリポジトリーを制限しています。この制限がないと、どこからのアクセスでも権限を取得されるため、絶対に指定しておくようにします。

GitHub Actions ワークフロー

AWS に OIDC 認証するための手順を GitHub Actions ワークフローに組み込みます。

シークレットの作成

まず、先ほど確認したロールの ARN を GitHub Actions シークレットとして登録しておきます。例として AWS_ROLE_TO_ASSUME という名前で登録しておきます。

権限設定の追記

ワークフローから OIDC トークンのリクエストを行えるように権限の設定を追加します。次のような内容をワークフローに追記します。

permissions:
  id-token: write

AWS アクセス トークンのリクエスト

AWS にアクセス トークンをリクエストするステップを追加します。role-to-assume で、認証時に使うロールの ARN を指定します。aws-region は利用するリージョンを指定します。

role-session-name は必須ではないですが、ログなどに記録されるセッション名を指定できます。

    steps:
      - name: configure aws credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: arn:aws:iam::1234567890:role/example-role
          role-session-name: samplerolesession
          aws-region: ${{ env.AWS_REGION }}

ワークフロー ファイルの例

上述の内容を踏まえ、次のような内容になります。

name: 'Terraform'
on:
  push:
    branches:
    - main
  pull_request:
jobs:
  terraform:
    name: 'Terraform'
    runs-on: ubuntu-latest
    environment: production
# 権限設定の追記
    permissions:
      id-token: write
    defaults:
      run:
        shell: bash
    steps:
    - name: Checkout
      uses: actions/checkout@v3
    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1
      with:
        cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
# AWS での認証を行うステップ
    - name: Authenticate to AWS
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
        aws-region: ap-northeast-1
    - name: Terraform Init
      run: terraform init
    - name: Terraform Format
      run: terraform fmt -check
    - name: Terraform Plan
      run: terraform plan
    - name: Terraform Apply
      if: github.ref == 'refs/heads/main' && github.event_name == 'push'
      run: terraform apply -auto-approve

Terraform プロバイダーの指定

あとは Terraform ファイルを用意して AWS リソースを作成します。作成するリソースに応じてロールに必要な権限は調整してください。プロバイダーの指定は次のようになります。

provider "aws" {
    region = var.aws_region
}

コメント

タイトルとURLをコピーしました