🐷

巷で話題の GitHub Actions で AWS の IAM ロールを利用する方法を簡素なコードにしてみた with Terraform

2021/10/12に公開1

この記事は何?

巷で話題の GitHub Actions で AWS の IAM ロールを利用する方法を簡素なコードにしてみました。
AWS 側の構築は Terraform で実装しています。

ぶっちゃけ以下解説している内容はアチコチのコードを寄せ集めなので調べたらわかりますが、 Terraform 且つ短縮したコードがパッと出てこなかったので使える状態でまとめました。

時間がない人はこちらだけ見てください

https://github.com/shogomuranushi/github-actions-aws-oidc-sample

GitHub Actions と AWS IAM ロールの件を3行で

github actions aws oidc とか検索すると色々出てくるので細かいことは割愛して、3行で説明します。

  • 今までは AWS 外の CI サービスで AWS API を叩く時に IAM ユーザの永続的なクレデンシャルを発行する必要があり、そのクレデンシャルが漏れたり(GitHubで公開とか、退職時とか)外部で利用されるリスクがあった
  • GitHub Actions で AWS の OIDC プロバイダー経由で IAM ロールが利用できることになり、永続的なクレデンシャルの発行が不要になり、一時的なクレデンシャルの利用が可能になった
  • 世界が一つ安全になった

検索してよく出てくる GitHub Actions の冗長的なコード

以下のように curl を叩いて云々。これを毎回書くのか。と思うと良いけども少し冗長だよね。

    steps:
      - run: sleep 5 # there's still a race condition for now

      - name: Configure AWS
        run: |
          export AWS_ROLE_ARN=arn:aws:iam::xxxxxxxxxxxx:role/ExampleGithubRole
          export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/awscreds
          export AWS_DEFAULT_REGION=us-east-1

          echo AWS_WEB_IDENTITY_TOKEN_FILE=$AWS_WEB_IDENTITY_TOKEN_FILE >> $GITHUB_ENV
          echo AWS_ROLE_ARN=$AWS_ROLE_ARN >> $GITHUB_ENV
          echo AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION >> $GITHUB_ENV

          curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sigstore" | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE

      - run: aws sts get-caller-identity

aws-actions/configure-aws-credentials を利用する

aws-actions/configure-aws-credentials を利用すれば以下のように3行程度書くだけになる。
ちなみに大きな注意点として、ブランチは master を指定している。最新バージョンは v1 だが、v1 は 2020年2月 より更新されていない。

OIDCに対応したのは 2021年9月28日の このコミット なので、このコミットハッシュを指定するか、masterを指定すれば利用可能になる。
master を指定すると bugfix の恩恵を受けられるが、 bug が含まれることもあるので、コミットハッシュか master 指定かはお好みで。

これで冗長的なコードが減るけど、 master タグは安定しないかもだし、そもそも GitHub 側も AWS 側も公式手順等が出ているわけではないので、何とも言い難い実装だけど、まぁ簡素化されたということで。

name: Example
on:
  push:
    branches:
      - "master"

env:
  # Please change here
  aws_account_id: ''

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - run: sleep 5

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@master
        with:
          aws-region: ap-northeast-1
          role-to-assume: arn:aws:iam::${{ env.aws_account_id }}:role/GitHubActions
          role-session-name: GitHubActions

      - run: aws sts get-caller-identity

Terraform のコード

とりあえずローカルで実行できる状態にしておきました。
全容はこちらのコードを参照してください。

https://github.com/shogomuranushi/github-actions-aws-oidc-sample/blob/master/main.tf

こちらは必要に応じて tfstate の保存先やバージョンを指定してください。
とりあえずローカルで動かすだけなら以下で十分です。

リージョンは ap-northeast-1 になっていますが、今回作成するリソースは全てグローバルサービスなのでどこを指定しても変わりません。

terraform {
  required_version = ">= 0.15"
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}

provider "aws" {
  # Please change here
  region = "ap-northeast-1"
}

github_oidc_domain は変更しなくて良いですが、reponame は自身の値に必ず書き換えてください。
IAM ポリシーの condition でリポジトリの制限を加えます。組織名のみにすることでどのリポジトリからも実行可能にすることもできますが、権限の兼ね合いで、リポジトリまで制限することが推奨されます。また、ブランチやタグを制限することもできます。

locals {
  # Please change here
  github_oidc_domain = "token.actions.githubusercontent.com"
  # Please change here
  reponame = "shogomuranushi/github-actions-aws-oidc-sample"
}

一旦、ReadOnlyAccessを付与してますが、こちらは好きに編集してください。 sts のようにカスタムポリシーも書くこともできます。

resource "aws_iam_role_policy_attachment" "github_actions1" {
  role       = aws_iam_role.github_actoins.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

resource "aws_iam_role_policy" "sts" {
  name   = "stspolicy"
  role   = aws_iam_role.github_actoins.name
  policy = data.aws_iam_policy_document.sts.json
}

data "aws_iam_policy_document" "sts" {
  statement {
    actions   = ["sts:GetCallerIdentity"]
    resources = ["*"]
  }
}

ここに紹介している部分以外のコードは、基本的には GitHub Actions と AWS OIDC と繋ぐ部分なのであまり触らない方が無難です。
繋いでいる部分のコードの解説は他ブログを参照ください。

Discussion

sumitosumito

非常に参考になりました。ありがとうございました!