GitHub Actions + AWSでterraform apply
OIDCでGitHub ActionsとAWSを連携し、terraform apply
してVPC作成をやってみました。
環境
Terraform v1.9.3
aws s3 ls
ができることを確認
【準備】GitHub Actionsでaws s3 ls
ができることを確認します。
ドキュメントをほぼなぞっているだけです。
AWS
IDプロバイダー
IDプロバイダーを追加します。
- プロバイダのタイプ :
OpenID Connect
- プロバイダURL :
https://token.actions.githubusercontent.com
- 対象者 :
sts.amazonaws.com
IAMロール
IAMロールを作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::[AWSアカウントID]:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:[GitHubのリポジトリの所有者]/[GitHubのリポジトリ名]:*"
},
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
}
]
}
StringLike
でアクセスしたいGitHubリポジトリを設定しています。
このGitHubリポジトリの設定が抜けてしまうと、全てのGitHubリポジトリからアクセスできてしまうので、気をつけねばなりません(怖いよぉ)。
ちなみに上記の設定ではブランチを指定していないので、specific github repo and branch recommended
という警告が出ました。が、スルーします。
ブランチ指定したい場合は、
- "StringLike": {
- "token.actions.githubusercontent.com:sub": "repo:[GitHubのリポジトリの所有者]/[GitHubのリポジトリ名]:*"
- },
"StringEquals": {
+ "token.actions.githubusercontent.com:sub": "repo:[GitHubのリポジトリの所有者]/[GitHubのリポジトリ名]::ref:refs/heads/[ブランチ名]",
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
と書けばよいです。
次にGitHub Actionsでaws s3 ls
コマンドを実行してみようと思うので、IAMポリシーはReadOnlyAccess
を付与します。
ロール名を好きな名前に設定して、作成をポチります。
GitHub
ワークフローファイルを作成します。
name: Check Access AWS
on:
pull_request
env:
AWS_REGION : "ap-northeast-1"
permissions:
id-token: write
contents: read
jobs:
LsS3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure aws credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.IAM_ROLE_NAME }}
role-session-name: MyGithubActionsSession
aws-region: ${{ env.AWS_REGION }}
- name: s3 ls
run: |
aws s3 ls
AWS_ACCOUNT_IDとIAM_ROLE_NAMEをGitHub上でsecretに登録しておきます。
IAM_ROLE_NAMEはsecretには当たらないですが、IAMロールのGitHubリポジトリの設定をみすり、かつIAMロールのARNもお漏らししてしまったときに、被害を最小限にするためにsecretに登録します。
これでPRを作成すると、結果は写しませんが、無事s3 lsでS3バケット一覧を取得できました。
GitHub ActionsでAWSにterraform applyする
ここまできたら詰まりそうなところはほぼ完了です。
TerraformでVPC作成をしてみようと思います。
AWS
tfstate用S3バケット作成
tfstateを保存するためのS3バケットを作成しておきます。
IAMロールの編集
先ほど作成した
- IAMロールにVPCを作成できる
- tfstate用S3バケットをコネコネする
ためのインラインポリシー追加します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AmazonVPCCreateRole",
"Effect": "Allow",
"Action": [
"ec2:CreateVpc",
"ec2:DescribeVpcs",
"ec2:CreateTags",
"ec2:DescribeVpcAttribute"
],
"Resource": "*"
},
{
"Sid": "AmazonS3ListRole",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::[作成したtfstate保存用s3バケット名]"
},
{
"Sid": "AmazonS3OperateRole",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::[作成したtfstate保存用s3バケット名]/*"
]
}
]
}
ポリシー名をつけて保存をポチります。
GitHub
terraform
構成は下記の通りです。
./
└── terraform
├── env
│ └── dev
│ ├── local.tf
│ ├── main.tf
│ └── provider.tf
└── modules
└── vpc
├── varriables.tf
└── vpc.tf
VPCを作成するためのファイルを新規追加していきます。
locals {
env = "dev"
region = "ap-northeast-1"
name_prefix = "githubactions-oidc-${local.env}"
}
module "vpc" {
source = "../../modules/vpc"
name_prefix = local.name_prefix
}
provider "aws" {
region = local.region
default_tags {
tags = {
Environment = local.env
}
}
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.61.0"
}
}
required_version = "~>1.9.0"
backend "s3" {
bucket = "[tfstate用S3バケット名]"
key = "dev.tfstate"
region = "ap-northeast-1"
}
}
variable "name_prefix" {
type = string
}
resource "aws_vpc" "main" {
cidr_block = "10.1.0.0/16"
tags = {
Name = "${var.name_prefix}-vpc"
}
}
ワークフローファイル
terraform apply
するようにワークフローファイルを編集します。
name: Check Access AWS
on:
pull_request
env:
AWS_REGION : "ap-northeast-1"
permissions:
id-token: write
contents: read
jobs:
TerraformApply:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./terraform/env/dev
steps:
- uses: actions/checkout@v4
- name: Configure aws credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.IAM_ROLE_NAME }}
role-session-name: MyGithubActionsSession
aws-region: ${{ env.AWS_REGION }}
- name: Setup terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.9.3"
- name: Terraform init
run: terraform init
- name: Terraform plan
run: terraform plan
- name: Terraform apply
run: terraform apply -auto-approve
これでPRを作成すると無事にGitHub ActionsでAWSにVPCを作成することができました。
Terraform will perform the following actions:
# module.vpc.aws_vpc.main will be created
+ resource "aws_vpc" "main" {
+ arn = (known after apply)
+ cidr_block = "10.1.0.0/16"
+ default_network_acl_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_group_id = (known after apply)
+ dhcp_options_id = (known after apply)
+ enable_dns_hostnames = (known after apply)
+ enable_dns_support = true
+ enable_network_address_usage_metrics = (known after apply)
+ id = (known after apply)
+ instance_tenancy = "default"
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ ipv6_cidr_block_network_border_group = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
+ tags = {
+ "Name" = "***-dev-vpc"
}
+ tags_all = {
+ "Environment" = "dev"
+ "Name" = "***-dev-vpc"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
改良ポイント
実際に開発を行うときは、追加でやっておきたい点を挙げます。
- 手動で作成したOIDCプロバイダーとIAMロールもTerraform管理にする
- PR作成でapplyしたいことはないと思うので、
- PR作成時は
terraform plan
まで - mainブランチなど特定ブランチへのマージ時に
terraform apply
をするようにする
- PR作成時は
-
terraform apply
前に承認プロセスを入れる - GitHub Actionsのワークフローを手動でも実行できるようにする
-
github/workflows/oidc-check.yml
のworking-directory: ./terraform/env/dev
とベタ書きしているのを環境指定で実行できるようにする
参考
Discussion