この記事は、Classi developers Advent Calendar 2021 2日目の記事です。
はじめに
正式アナウンスに先んじて Twitter で話題 になっていた、GitHub Actions で AssumeRole が使える 件が、2021年10月末頃に GitHub 社より正式にアナウンスされました。
GitHub Actions: Secure cloud deployments with OpenID Connect
(正確には、OpenID Connect による認証をサポートした、という内容です。)
Classi では、ソースコード管理に GitHub を使っていて、インフラ構成管理には Terraform を利用しています。
Terraform は、Backend に Amazon S3 を指定することで、Terraform によるインフラ構成管理をチームでできるようにしています。
今回、この正式アナウンスを機に、GitHub 側に AWS の認証情報(アクセスキー)を持たせることなく、GitHub Actions で S3 Backend な Terraform の plan を実行できるようにしたので、その内容を紹介します。
前提
想定読者
- AWS IAM User のアクセスキーを発行・管理せずに GitHub Actions から AWS リソースへアクセスしたい方
- Terraform を GitHub Actions で実行させたい方
この記事に書かれていること
- GitHub Actions で AssumeRole を利用するための AWS の設定手順
- GitHub Actions で terraform plan を実行する Actions のサンプル
この記事に書かれていないこと
- GitHub や GitHub Actions そのものの説明
- Terraform そのものの説明
- AWS や IAM そのものの説明
- OIDC(OpenID Connect) の説明
手順
基本的には GitHub 公式の手順 に従って設定を進めるだけですが、ところどころ説明が端折られているので、やったことを順に記載していきます。
AWS 側の設定手順
ID Provider の作成
- IAM ID プロバイダのコンソールに行き、「プロバイダを追加」をクリック
- プロバイダのタイプ:
OpenID Connect
を選択 - プロバイダの URL:
https://token.actions.githubusercontent.com
- URL 入力後、「サムプリントを取得」をクリックしてサムプリント取得
- 対象者(Audience):
sts.amazonaws.com
- 公式の Action aws-actions/configure-aws-credentials を使う場合は対象者に
sts.amazonaws.com
を指定 - 今回は公式 Action を使ったのでこの通り指定
- 公式の Action aws-actions/configure-aws-credentials を使う場合は対象者に
- タグは任意に設定
- 入力後はこんな感じ
IAM ポリシーの作成
GitHub 公式の手順 では IAM ポリシーの話は出てきませんが、Terraform が S3 にアクセスするのに権限設定が必要なため、以下の IAM ポリシーを作成します。(IAM ロールのインラインポリシーでも構いません)
- IAM ポリシーのコンソールに行き、「ポリシーを作成」をクリック
- JSON エディタに切り替えて↓の json を貼り付け
- タグ、ポリシー名、説明は任意に設定
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::{YOUR_BUCKET_NAME}"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObjectAcl",
"s3:PutObject",
"s3:GetObjectAcl",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::{YOUR_BUCKET_NAME}/*"
}
]
}
IAM ロールの作成
GitHub Actions から利用する IAM ロールを作成します。
- IAM ロールのコンソールに行き、「ロールを作成」をクリック
-
ウェブ ID
を選択 - アクセス権限
- ↑で作成したポリシーを選択
- タグ、ロール名、説明は任意に設定
信頼ポリシーの修正
GitHub 公式の手順 によると、信頼ポリシーにはデフォルトでは Condition に aud
しか入ってないので sub
も追加する必要があると書いてあります。
By default, the validation only includes the audience (aud) condition, so you must manually add a subject (sub) condition.
Edit the trust relationship to add the sub field to the validation conditions.
sub を指定することで、リポジトリやブランチ単位で制限をかけることができるようです。
今回、弊社ではリポジトリを絞りたかったため、Condition に以下を追加しました。
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:{YOUR_ORGANIZATION_NAME}/{YOUR_REPOSITORY_NAME}:*"
}
-
{YOUR_ORGANIZATION_NAME}
には、Organization 名を指定 -
{YOUR_REPOSITORY_NAME}
には、この IAM ロールを引き受けることを許可するリポジトリを指定
※ {YOUR_ORGANIZATION_NAME}
は Organization ではなく通常アカウントの指定でも使えると思うが未検証。
追加後の信頼ポリシー json 全体はこちらです。
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::{YOUR_AWS_ACCOUNT_ID}: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:{YOUR_ORGANIZATION_NAME}/{YOUR_REPOSITORY_NAME}:*"
}
}
}
]
}
信頼ポリシーを上記のように修正して IAM ロールの作成は完了。
GitHub Actions の用意
今回は、プルリクエストに terraform plan {TARGET_DIRECTORY}
というコメントをした場合に、{TARGET_DIRECTORY}
配下で terraform plan
を実行したかったため、それを実現する Action を用意しました。
実際に使っている yaml ファイルを一部加工したものがこちらです。
# プルリクのコメントに反応して plan を実行する action
name: 'terraform plan'
on:
issue_comment:
types: [created, edited]
jobs:
plan:
name: 'terraform plan'
# プルリクエスト上で "terraform plan " から始まるコメントをした場合にのみ実行
if: contains(github.event.comment.html_url, '/pull/') && startsWith(github.event.comment.body, 'terraform plan ')
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: get branch
id: get_branch
run: |
echo "::set-output name=branch::$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" ${{ github.event.issue.pull_request.url }} | jq -r '.head.ref')"
- uses: actions/checkout@v2
with:
ref: ${{ steps.get_branch.outputs.branch }}
- name: get working directory
id: work_dir
run: |
echo "::set-output name=dir::$(echo "${{ github.event.comment.body }}" | sed 's/terraform plan //g')"
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: {作成した IAM ロールの ARN}
role-session-name: {作成した IAM ロールの名前}
aws-region: {デフォルトリージョン}
- uses: hashicorp/setup-terraform@v1
with:
terraform_version: "1.0.0"
- name: terraform init
run: terraform init
working-directory: ${{ steps.work_dir.outputs.dir }}
- name: terraform plan
continue-on-error: true
id: plan
run: terraform plan -no-color -lock=false
working-directory: ${{ steps.work_dir.outputs.dir }}
- name: Comment the plan result to the pull request
uses: actions/github-script@v1
env:
STDOUT: "${{ steps.plan.outputs.stdout }}"
TARGET_DIR: "${{ steps.work_dir.outputs.dir }}"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: process.env.TARGET_DIR + " terraform plan\n\n<details>\n<summary>result</summary>\n\n```\n" + process.env.STDOUT + "\n```\n\n</details>"
})
ポイントは、以下の2点。
- permissions での
id-token: write
設定- GitHub 公式の手順 でも記載のある通り、この設定を追加する必要がある
- 公式の Action aws-actions/configure-aws-credentials は
v1
またはv1.6.0
またはmaster
(ブランチ) を指定- OIDC に対応したのは 2021年11月23日にリリース された
v1.6.0
からである - そのため、
v1.6.0
または、最新の v1.x.x を追いかけているv1
または、常に最新であるmaster
ブランチを指定する必要がある - 本稿執筆時点での GitHub 公式の手順 では
master
を指定しているが、これは、GitHub 社による正式アナウンス時点で aws-actions/configure-aws-credentials の最新版(OIDC対応版)が未リリースだったためと思われる
- OIDC に対応したのは 2021年11月23日にリリース された
もし、最後のステップの「Comment the plan result to the pull request」が Resource not accessible by integration
というエラーで失敗する場合は、Personal Access Token を利用してみてください。
こちらの記事が参考になります。
おわりに
今回は terraform plan を実行するための Action や IAM ポリシーの紹介でしたが、やりたいことに合わせてポリシーの中身の修正と Action の修正で、他の AWS リソースへのアクセスを実現することができます。
ご参考まで。