CI/CDサービスとしてGitHub Actionsが有名です。
最近はOIDC認証が利用できると聞いたので試してみたい!
どうせならTerraformも実行させてみたい!
この記事では、GitHub ActionsをOIDCでAWS認証を行い、Terraformを実行する方法を紹介します。
- Terraformは使えるけど、GitHub Actionsなんも分からん…
- でもGitHub ActionsでTerraformを実行するようにしたい!
- OIDCでGitHub ActionsからAWSの認証をしたい!
- GitHub ActionsでTerraformを実行する
- AWSの認証をOIDCで行う
前提条件
本記事で使用するリポジトリ
この記事で使用例として登場するリポジトリは筆者の以下のリポジトリです。
github.com/akashikaikyouohasi/GitHubActionsTestByOIDC
ワークフローの実行タイミング
今回はmainブランチへのプルリクエストがマージされた際に実行するようにしています。
実行環境
以下の記事で作成したCloud9のTerraformの実行環境を使用しています。
GitHub Actionsとは
簡単に解説すると、GitHubでCI/CDを自動化できる機能です。
公式のトップページの紹介文は以下の通り。
GitHub Actionsを使用すると、ワールドクラスのCI / CDですべてのソフトウェアワークフローを簡単に自動化できます。 GitHubから直接コードをビルド、テスト、デプロイでき、コードレビュー、ブランチ管理、問題のトリアージを希望どおりに機能させます。
https://github.co.jp/features/actions
CIは継続的インテグレーション、CDは継続的デリバリーのことです。
ソフトウェアの変更を検知し、デプロイして自動でテストしてデプロイすることができます。
今回の記事ではTerraformを自動で実行できるようにします。
例えば、プルリクでレビュー用の環境を作ってデプロイし、レビューが完了してマージしたら削除みたいなことができます。
CI/CDサービスとして有名なのものにCircleCIがありますが、GitHubにリポジトリを持っている場合はGitHub Actionsの方が簡単に早く始められると思います!
手動でしなくてもいいことは積極的に機械に任せるべきなので、どんどん利用していきたいですね!
ワークフロー
GitHub Actionsを実行するためのワークフローを準備します。
ワークフロー内でAWSに接続する必要があるため、まずはAWSの認証ができるように準備します。
その後、Terraformの実行方法を準備します。
以前のやり方であれば、AWSのIAMユーザーのアクセスキーIDとシークレットアクセスキーを利用して認証していました。
この方法だとアクセスキーIDとシークレットアクセスキーが漏れた場合のセキュリティリスクが大きいです。
そのため、今回はGitHub Actionsで利用可能になったOIDC(OpenID Connect)を利用します。
OIDCを利用するとIDとキーをGitHub側で持つ必要がなくなります。
特に、AWS側で指定したGitHubのリポジトリだけを許可する設定を行うため、認証情報が漏れてもリスクが最小化されます!
(トークンのやり取りになるので、前任者にユーザー・パスワードを覚えられて外部から意図せず実行されることはないですね)
基本的にはGitHub Docsを参考に実施していきます
OIDC認証準備
IDプロバイダ作成
まずは、AWSでIDプロバイダを作成します。
- AWSのサービス一覧からIAMを選択
- アクセス管理の一覧からIDプロバイダを選択して、プロバイダを追加を選択
- プロバイダのタイプでOpenID Connectを選択して、残りは以下のように設定
- その後、サムプリントを取得を選択して、問題なければプロバイダを追加を選択
項目 | 設定内容 |
---|---|
プロバイダの URL | https://token.actions.githubusercontent.com |
対象者 | sts.amazonaws.com |
- GitHubのプロバイダが作成できればOK!
IAMロールの作成
続いて、作成したIDプロバイダから利用できるIAMロールを作成します。
- アクセスからロールを選択して、ロールを作成を選択
- 信頼されたエンティティの種類を選択にてウェブIDを選択
- IDプロバイダーは先ほど作成したGitHubのtoken.actions.githubusercontent.com:audを選択、Audienceはsta.amazonaws.comを選択
- 次のステップ:アクセス権限を選択
- ポリシーのフィルタにAdministratorAccessと入力してAdministratorAccessポリシーを検索します
- AdministratorAccessを選択して、次のステップ:タグを選択
- タグはなしで、そのまま次のステップ:確認を選択。
- 最後にロール名を付けます
今回はGitHubActionsTestByOIDCとしますが、お好きな名前でも構いません - ロール名を設定したらロールの作成
- ロール一覧画面に戻るので、検索バーにGitHubActionsTestByOIDCと入力してロールが作成できていることを確認します。
IAMロールの信頼関係調整
作成したままではGitHub Actionsの認証で使用できません。
そのため、信頼関係を更新します。
- 先ほど作成したIAMロールを選択します
- 信頼関係タブに移動して、信頼関係の編集を選択します
- 以下のようにポリシードキュメントを編集します
- 11行目のCondition内をStringLikeにして、12行目をtoken.actions.githubusercontent.com:subに変更
- 値はrepo:{GitHubのユーザー名}/{リポジトリ名}:*にします
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::{アカウントID}:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:akashikaikyouohasi/GitHubActionsTestByOIDC:*"
}
}
}
]
}
- 編集したら、信頼ポリシーの更新を選択
- 問題なく更新出来たら、以下のように値が更新されています
これでAWS側の準備は完了です!
リポジトリの初期化
今回は、空のリポジトリの状態から開始するため初期化を行います。
なお、実行環境は以前にCloud9で作成したTerrafromが実行可能な環境を使用します。
リポジトリの初期化
- 実行環境にログインします
- ローカルのリポジトリを作成して初期化と1stコミットを作成します
$ mkdir GitHubActionsTestByOIDC
$ cd GitHubActionsTestByOIDC/
$ git init
$ echo "# GitHubActionsTestByOIDC" >> README.md
$ git add README.md
$ git commit -m "first commit"
$ git branch -M main
$ git remote add origin git@github.com:akashikaikyouohasi/GitHubActionsTestByOIDC.git
- 今のままではGitHubにアクセスできません
- まずは、実行環境内でSSHキーを生成します
$ ssh-keygen
(質問事項は全てEnterでも構いません)
$ ls ~/.ssh/id_rsa.pub
/home/ec2-user/.ssh/id_rsa.pub
- GitHubのリポジトリのSettingsタブに移動します
- SecurityからDeploy keysを選択し、キー登録画面に行きます
- Titleは適当につけて、Keyには先ほど作成したキー(id_rsa.pub)の内容を貼り付けて、Allow write accessには忘れずチェックをつけること
- Add keyを選択
- 作成されればOKです!
- ローカルの内容をGitHubのリモートリポジトリにプッシュします
$ git push -u origin main
- リポジトリの画面で、READMEの内容が表示されればOKです!
ワークフロー作成
ここからはGitHub Actionsのワークフローを作成していきます。
- GitHub Actionsでは.github/workflows/配下のディレクトリから設定を読み込むため、ディレクトリを作成
- 空の設定ファイルterraform.ymlを作成します
$ mkdir -p .github/workflows/
$ cd .github/workflows/
$ touch terraform.yml
$ ls terraform.yml
terraform.yml
- terraform.ymlを以下のように更新します
処理の説明は後ほど行います
name: terraform apply test by OIDC
on:
pull_request:
branches:
- main
types: [closed]
permissions:
id-token: write
contents: read # actions/checkout のために必要
jobs:
get-caller-identity:
name: OIDC test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS credentials from test account
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
terraform_version: 1.1.4
- name: Terraform fmt
id: fmt
working-directory: ./terraform
run: terraform fmt -check
continue-on-error: true
- name: Terraform Init
id: init
working-directory: ./terraform
run: terraform init
- name: Terraform Validate
id: validate
working-directory: ./terraform
run: terraform validate -no-color
- name: Terraform Plan
id: plan
working-directory: ./terraform
run: terraform plan -no-color
continue-on-error: true
- name: Terraform Apply
id: apply
working-directory: ./terraform
run: terraform apply -auto-approve
- 編集が完了したら、コミットしてプッシュ
$ git add .
$ git commit -m "OIDCを利用してTerraformを実行するワークフローを追加"
$ git push
先ほど作成したterraform.ymlの説明をしていきます。
各ワークフロー共通部分
terraform.ymlのうち、以下はどのワークフローでも利用する箇所です。
name: terraform apply test by OIDC
on:
pull_request: # プルリクエストで
branches: # ブランチが
- main # mainに対して
types: [closed] # Closeされた時に実行
nameはワークフローの名前です。
適当でいいです
onはトリガー定義です。
いつGitHub Actionsでワークフローを実行するかを定義します。
今回の場合は、mainブランチへのPull Requestがclose(マージされたのと同義)されたタイミングで実行するようになっています。
OIDC認証箇所
terraform.ymlのうち、以下でOIDC認証をおこなっています!
permissions:
id-token: write # OIDCを利用する際に必須
contents: read # actions/checkout のために必要
jobs:
get-caller-identity: # ただの名前
name: OIDC test # このJobの名前。ログに出ます
runs-on: ubuntu-latest # 使用する環境。
steps:
- name: Checkout
uses: actions/checkout@v2 # リポジトリをチェックアウトして取得します
- name: Configure AWS credentials from test account
uses: aws-actions/configure-aws-credentials@v1 # GitHubのOIDCプロバイダーからJWTを受け取り、AWSにアクセストークンを要求します
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }} # 作成したIAMロール。ただし、リポジトリのsecretsに設定しています。
aws-region: ap-northeast-1 # 操作対象のリージョンを設定
permissionsはOIDCを使用するのに必要なid-token: writeと、actions/checkout@v2を利用する際に必要なcontens: readを設定しています。
公式ドキュメントの通りです。
jobsでは、リポジトリをチェックアウトした後、GitHubのOIDCプロバイダーからJWT(JSON Web Token)を受け取り、AWSにアクセストークンを要求します。
このシーケンスは公式の図やこの記事がわかりやすいです。
role-to-assumeでは上記で作成したIAMロールのARN(Amazon Resource Name)を指定しますが、アカウントIDが含まれるため一応secretsに登録しています。
IAMロールのARNのsecrets登録
- リポジトリのSettingsからSecretsのActiosを選択します
- New Repository secretsを選択して、secretsを作成していきます
- NameはAWS_ROLE_ARN、Valueには上記で作成したIAMロールのARN(arn:aws:iam::{アカウントID}:role/GitHubActionsTestByOIDC)を設定します
- 一覧に表示されればOKです!
これでGitHub Actionsのワークフローからsecretsが利用できます。
Terraform実行箇所
terraform.ymlのうち、以下でTerrafromを実行しています!
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1 # Terraformのインストール
with:
terraform_version: 1.1.4 # Terraformのバージョン指定
- name: Terraform fmt
id: fmt
working-directory: ./terraform # terraformディレクトリ内で実行
run: terraform fmt -check # fmtをチェックし、フォーマット漏れがあれば失敗となります
continue-on-error: true # エラーが出てもジョブが失敗にならないようにし、次に進む。
- name: Terraform Init
id: init
working-directory: ./terraform
run: terraform init # initを実行してTerraformを実行できるようにします。
- name: Terraform Validate
id: validate
working-directory: ./terraform
run: terraform validate -no-color # 事前にvalidate確認を実施します。-no-colorを指定しないとログの出力がおかしくなるようです。
- name: Terraform Plan
id: plan
working-directory: ./terraform
run: terraform plan -no-color # 実行内容を確認します。
continue-on-error: true
- name: Terraform Apply
id: apply
working-directory: ./terraform
run: terraform apply -auto-approve # applyします。-auto-approveで実行確認の入力が不要となる
GitHub ActionsでTerraformを使用する際は、hashicorpのsetup-terraformが参考になります。
流れとしては、Terraformをインストールして、リソース定義ファイルをチェックして、applyするだけです。
terraform fmt -checkコマンドは、フォーマット対象が存在すると終了ステータスが3(0が正常終了を表す)になってエラーとなります!
terraform validateコマンドも同様で、定義ファイルに問題があると終了ステータスが1となり、エラーになります!
実際に動かしてみよう
ワークフローを作成したので、実際に動かしてみましょう!
テスト用ファイル作成
ワークフローではterraformディレクトリでTerraformを動かす想定なので、ディレクトリの作成からリソース定義ファイルの作成まで実施していきます
- terraformディレクトリを作成します
$ pwd
/home/ec2-user/environment/GitHubActionsTestByOIDC
$ mkdir terraform
$ cd terraform/
- main.tfを作成します
詳細はコメントの通りです
terraform {
# 使用するAWSプロバイダーのバージョン指定(結構更新が速い)
required_providers {
aws = {
source = "hashicorp/aws"
version = "~>3.72"
}
}
}
# 明示的にAWSプロバイダを定義(暗黙的に理解してくれるけど)
provider "aws" {
profile = "default"
region = "ap-northeast-1"
# 作成する全リソースに自動的に付与するタグ設定
default_tags {
tags = {
env = "GitHubActionsTestByOIDC"
}
}
}
- テスト用にS3バケットを作成するリソース定義S3.tfを作成します
テスト用に作成するだけなので、詳細は割愛します
# -----------------------------------
# S3の作成
# -----------------------------------
### バケット作成 ###
resource "aws_s3_bucket" "terraform_test" {
# S3のバケット名
bucket = "test-bucket-20220202-githubactionstestbyoidc" ###要変更###
# アクセス管理
acl = "private"
# バージョニングの有効化
versioning {
enabled = true
}
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}
resource "aws_s3_bucket_public_access_block" "terraform_test" {
# 対象のバケット
bucket = aws_s3_bucket.terraform_test.id
# パブリックのアクセスをブロック
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
- 作成した内容をGitHubにPushします
$ git add .
$ git commit -m "テスト用のTerraformのリソース定義ファイル作成"
$ git push
- ここまでの作業でディレクトリ構造は以下のようになっています
これで準備は整いました!
ワークフローの実行
今回の作成したワークフローはプルリクをマージした際に動作します。
なので、適当にブランチを作成してプルリクマージを行います。
- ブランチを作成して、README.mdを編集してプッシュまでします
$ pwd
/home/ec2-user/environment/GitHubActionsTestByOIDC
$ git checkout -b github_test
Switched to a new branch 'github_test'
$ echo "GitHub workflow test." >> README.md
$ git add .
$ git commit -m "GitHubワークフローのテスト用コミット"
$ git push -u origin github_test
- GitHubのリポジトリのWEBページにアクセスしてプルリクを作成画面に移動します
- プルリクのコメントは適当でいいので、プルリクエストを作成
- 自分管理のリポジトリなので、そのままマージ!!!
- GitHub Actionsで実行されるので、Actionsタブからワークフローの実行状況が見れます
- 正常に実行されたら緑になります!
- AWSのS3でバケットが作成されていることが確認できました!!
まとめ
この記事ではGitHub ActionsでOIDC認証をしてTerrafomを実行してみました。
OIDC認証はアクセスキーID・シークレットアクセスキーを使用するよりかは安全なので、今後の主流になりそうな気がします。
みなさんには是非使ってほしいですね。
もし「設定できない!」や「うまくいかない!」などがありましたら著者のTwitterまでご連絡ください。
参考サイト・書籍
ワークフローでのOIDC認証
Zenn GitHub Actions の OpenID Connect サポートについて
GitHub Actions + OIDC Token の情報をAWSのセッションタグに設定してみた
GitHub aws-actions/configure-aws-credentials
GitHub Docs Configuring OpenID Connect in Amazon Web Services ⇒GitHub ActionsでOIDCを利用するための公式ドキュメント。とりあえずこれに従っとけ内容
IAM ロールの PassRole と AssumeRole をもう二度と忘れないために絵を描いてみた ⇒IAMロールについて、とにかく勢いで分かりやすい!
AWSの認証情報なしでGitHub Actionsからアクセスする with Terraform ⇒細かなところまでわかる
GitHub Actions の OIDC トークンの sub
にはなにが入るのか? ⇒GitHubのOIDCトークンのsubの設定内容が参考になる
DeveloperIO 【小ネタ】GitHub Actions用のIAMロールをAWSマネジメントコンソールから作成する際の注意点 & [要注意]GitHub Actions OIDC+AWS IAMロールで”token.actions.githubusercontent.com:sub”条件を書き忘れてはいけない ⇒Conditionを設定しない場合にどうなるかなどわかりやすい
GitHub Actionsのワークフロー
GitHub Docs GitHub Actionsのワークフロー構文 ⇒公式の解説なのでリファレンス
GitHub hashicorp/setup-terraform ⇒hashicorpのが提供しているGitHub Actionsのサンプル。Planの結果をプルリクのコメントに載せる方法もある!
Zenn GitHub ActionsでTerraformの実行を自動化する ⇒TerraformをGitHub Actionsで実行するわかりやすい例