最終的なコードはこちらです。
GithubActionsに永続的な認証を渡さない方法を使用しています。
環境
- Terraform 1.1.9
※Docker Imageを使用しました。 - provider hashicorp/aws 4.12.0
- docker 20.10.10

.gitignoreを作成
.gitignore
*.tfstate
# Local .terraform directories
**/.terraform/*
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include override files you do wish to add to version control using negated pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc
誤ってAWSのアクセスキー等をGithubに上げてしまわないよう.gitignoreを設定します。
Terraformのバージョン、プロバイダーの指定
provider.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "4.12.0"
}
}
required_version = "1.1.9"
}
provider "aws" {
region = "ap-northeast-1"
}
Terraformはバージョンによってstateファイル等の仕様が違うのでトラブルを未然に防ぐためにバージョンを指定しておきます。
ECRを作成
ecr.tf
resource "aws_ecr_repository" "sample" {
name = "sample"
}
resource "aws_ecr_lifecycle_policy" "sample" {
policy = jsonencode(
{
"rules" : [
{
"rulePriority" : 1,
"description" : "Hold only 10 images, expire all others",
"selection" : {
"tagStatus" : "any",
"countType" : "imageCountMoreThan",
"countNumber" : 10,
},
"action" : {
"type" : "expire"
}
}
]
}
)
repository = aws_ecr_repository.sample.name
}
sh
terraform init
terraform apply
yes
Dockerイメージをプッシュするためのリポジトリを作成しています。
ライフサイクルポリシーは無くても動きますが今回は10枚のイメージだけを保持するように設定しています。
IAMロールを作成
iam.tf
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
resource "aws_iam_role" "github" {
name = "github"
assume_role_policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Federated" : "${aws_iam_openid_connect_provider.github.arn}"
},
"Action" : "sts:AssumeRoleWithWebIdentity",
"Condition" : {
"StringLike" : {
"token.actions.githubusercontent.com:sub" : "repo:${var.github_user_name}/${var.github_repository_name}:*"
}
}
}
]
}
)
}
resource "aws_iam_policy" "github" {
name = "github"
policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"ecr:GetAuthorizationToken",
],
"Resource" : "*"
},
{
"Effect" : "Allow",
"Action" : [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
],
"Resource" : "${aws_ecr_repository.sample.arn}"
}
]
}
)
}
resource "aws_iam_role_policy_attachment" "role_deployer_policy_ecr_power_user" {
role = aws_iam_role.github.name
policy_arn = aws_iam_policy.github.arn
}
variables.tf
variable "github_repository_name" {
type = string
}
variable "github_user_name" {
type = string
}
terraform.tfvars
github_repository_name = "<リポジトリ名>"
github_user_name = "<ユーザー名>"
自分のユーザー名、リポジトリ名を入力してください。
sh
terraform init
terraform apply
yes
AWSの認証情報をOpenIDプロバイダを使用して付与します。
これによって永続的な認証情報を持たせずGithubアクションからAWSサービスを呼び出すことができます。
IAMロールは特定のリポジトリのみが引き受けられるようにし、付与するポリシーも使用する最小限のものにしています。
許可するリポジトリを実行時に指定できるようにvariables.tfに変数を定義しています。
Dockerfileを作成
docker/Dockerfile
FROM hello-world
プッシュするイメージを作成します。
今回はサンプルなのでhello-worldイメージを読み込むだけにしています。
Github Secretsを設定
ECRリポジトリのURLとIAMロールのARNをメモします。
sh
terraform state show aws_ecr_repository.sample
terraform state show aws_iam_role.github
Githubにアクセスしてリポジトリの[Settings]を開きます。

先ほどメモしたURLとARNを[Secrets]に追加します。

こちらはGithubアクションで使用します。
Githubアクションを作成
.github/workflows/deploy.yml
name: deploy
on:
push:
branches:
- main
env:
IMAGE_TAG: ${{ github.sha }}
jobs:
deploy:
name: Push Image to AWS ECR
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
REPOSITORY_URL: ${{ secrets.ECR_REPOSITORY_URL }}
run: |
docker build -t $REPOSITORY_URL:$IMAGE_TAG ./docker/
docker push $REPOSITORY_URL:$IMAGE_TAG
mainブランチにプッシュするとGithubActionsが起動しECRにイメージがデプロイされます。
処理の大まかな流れはこんな感じです。
- Checkout
Githubアクションがリポジトリにアクセスできるようにする - Configure AWS credentials
AWSのサービスを呼び出す権限を取得(IAMロールを引き受ける) - Login to Amazon ECR
ECRにログイン - Build, tag, and push image to Amazon ECR
イメージをビルドしてECRにプッシュ
I have read several excellent stuff here. Definitely
worth bookmarking for revisiting. I wonder how a lot attempt
you set to create this kind of wonderful
informative website.