MackefileとactでGHAワークフローのaws-cliをローカルでテストする
はじめに
GitHub Actionsは、CI/CD環境を簡単に構築できる便利なツールですが、実際にワークフローを開発する際、GitHub上で動かしながらテストするのは少し手間がかかりますよね。
そこでおすすめなのが、ローカル環境でGitHub Actionsをシミュレートできるツール「act」です。このツールを使えば、ローカルで素早くワークフローを確認でき、作業効率が大幅にアップします。
たとえば、act
を使えばaws-cliを利用したテストも可能です。また、Makefileを活用することで、テストの実行をさらに効率化できます。
この記事では、act
とMakefileを組み合わせてワークフローのaws-cliをテストする方法をご紹介します!
サンプルのワークフローとMakefile
以下のサンプルを使用して解説していきます。
1.ワークフロー
このワークフローではAWS CLIを使用してS3バケットにファイルを同期します。
name: deploy
on:
pull_request:
types: [opened, reopened, synchronize]
permissions:
contents: read
id-token: write
env:
AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }}
AWS_REGION: us-east-1
BUCKET: dummy-bucket
jobs:
job1:
runs-on: ubuntu-latest
steps:
- name: Setup for act
# actで実行した場合は、処理を行います。
if: github.actor == 'nektos/act'
run: |
curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip -q awscliv2.zip
sudo ./aws/install
rm -fr awscliv2.zip ./aws
aws --version
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials
# actで実行した場合は、処理を行いません。
if: github.actor != 'nektos/act'
id: aws-credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Sync html
run: |
aws s3 sync --delete ./html/ s3://${{ env.BUCKET }}/
- name: List bucket for debug
# actで実行した場合は、処理を行います。
if: github.actor == 'nektos/act'
run: |
echo "**** local"
ls -al html/
echo "**** remote"
aws s3 ls s3://${{ env.BUCKET }}/
Setup for act
- actの場合に実行する。
- actのDockerイメージに含まれていないaws-cliをインストールしている。
Cofigure AWS Credentials
- actの場合は実行しません。
- かわりに、環境変数に設定したAWSクレデンシャルを使用。
2.Makefile
actを実行するために以下のようなMakefileを使用します。
AWS CLIのsts assume-role
コマンドを使い、一時的なAWSクレデンシャルを生成してactを実行します。
PROFILE := dummy
REGION := us-east-1
IAM_ROLE_FOR_ACT := arn:aws:iam::000000000000:role/dummy
ACT_MICRO_IMAGE := node:16-buster-slim
ACT_MEDIUM_IMAGE := catthehacker/ubuntu:act-latest
# act実行
act: aws_creds
-act -P ubuntu-latest=$(ACT_MEDIUM_IMAGE) \
--container-architecture linux/amd64 \
-s AWS_ROLE_ARN="dummy" \
--env-file .act_env \
-W .github/workflows/deploy.yml
rm -f .act_env
# 一時的なAWSクレデンシャルの生成
aws_creds:
@echo "create temporaly aws credentials"
@aws sts assume-role \
--role-arn $(IAM_ROLE_FOR_ACT) \
--role-session-name act \
--duration-second 900 \
--profile $(PROFILE) \
--query 'Credentials' \
| jq -r '.|[.AccessKeyId,.SecretAccessKey,.SessionToken]|@csv' \
| awk -F, '{printf("AWS_ACCESS_KEY_ID=%s\nAWS_SECRET_ACCESS_KEY=%s\nAWS_SESSION_TOKEN=%s\nAWS_REGION=$(REGION)\n",$$1,$$2,$$3)}' \
> .act_env
- actはMEDIUMイメージを使っています。MICROはコマンドが色々不足しており、LARGEはイメージサイズが大きすぎるため。
- act実行時には
secret.AWS_ROLE_ARN
は使用しないので、"dummy"としている。 - act実行時に
--env-file .act_env
を使用して、環境変数にAWSクレデンシャルを設定。
ローカルでのテスト手順
私のローカル環境は、Lubuntu22.04です。
1. IAMロールの作成
actで使用するクレデンシャルを作成するためのIAMロールを作成します。
以下は、AWS STSを使用して一時的なクレデンシャルを作成する際に使用するIAMロールのポリシーを記載した例です。このロールには、aws s3 sync
コマンドを実行するために必要な最小限の権限が含まれています。
IAMロールの信頼ポリシー
このポリシーを設定することで、STSがロールを引き受けることを許可します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "sts.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
IAMロールのポリシー (S3 Sync 用)
以下のポリシーでは、特定のS3バケットへのsync
操作に必要な権限を指定しています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::example-bucket",
"arn:aws:s3:::example-bucket/*"
]
}
]
}
2. ディレクトリ構成
以下のようなディレクトリ構成であることとします。
.
├── .github
│ └── workflows
│ └── deploy.yml
├── .gitignore
├── Makefile
└── html
└── index.html
3. テストの実行
make act
を実行するだけで、以下の一連の操作が行われます。
(1) 一時的なAWSクレデンシャルの生成
make aws_creds
ターゲットが実行され、.act_env
ファイルにクレデンシャルが保存されます。
(2) GitHub Actionsワークフローの実行
act
が実行され、ワークフローがローカル環境で実行されます。
(3) クレデンシャルの削除
.act_env
ファイルが削除され、セキュリティが保たれます。
実行結果は以下のようになります。
実行例
$ make act
create temporaly aws credentials
act -P ubuntu-latest=catthehacker/ubuntu:act-latest \
--container-architecture linux/amd64 \
-s AWS_ROLE_ARN="dummy" \
--env-file .act_env \
-W .github/workflows/deploy.yml
INFO[0000] Using docker host 'unix:///var/run/docker.sock', and daemon socket 'unix:///var/run/docker.sock'
[deploy/job1] 🚀 Start image=catthehacker/ubuntu:act-latest
[deploy/job1] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform=linux/amd64 username= forcePull=true
[deploy/job1] 🐳 docker create image=catthehacker/ubuntu:act-latest platform=linux/amd64 entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[deploy/job1] 🐳 docker run image=catthehacker/ubuntu:act-latest platform=linux/amd64 entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[deploy/job1] 🐳 docker exec cmd=[node --no-warnings -e console.log(process.execPath)] user= workdir=
[deploy/job1] ☁ git clone 'https://github.com/aws-actions/configure-aws-credentials' # ref=v4
[deploy/job1] Non-terminating error while running 'git clone': some refs were not updated
[deploy/job1] ⭐ Run Main Setup for act
[deploy/job1] 🐳 docker exec cmd=[bash -e /var/run/act/workflow/0] user= workdir=
| You can now run: /usr/local/bin/aws --version
| aws-cli/2.22.26 Python/3.12.6 Linux/6.8.0-50-generic exe/x86_64.ubuntu.22
[deploy/job1] ✅ Success - Main Setup for act
[deploy/job1] ⭐ Run Main Checkout
[deploy/job1] 🐳 docker cp src=/home/blog/act_awscli/. dst=/home/blog/act_awscli
[deploy/job1] ✅ Success - Main Checkout
[deploy/job1] ⭐ Run Main Sync html
[deploy/job1] 🐳 docker exec cmd=[bash -e /var/run/act/workflow/3] user= workdir=
[deploy/job1] ✅ Success - Main Sync html
[deploy/job1] ⭐ Run Main List bucket for debug
[deploy/job1] 🐳 docker exec cmd=[bash -e /var/run/act/workflow/4] user= workdir=
| **** local
| total 12
| drwxr-xr-x 2 root root 4096 Dec 28 08:17 .
| drwxr-xr-x 4 root root 4096 Dec 28 08:17 ..
| -rw-rw-r-- 1 root root 3 Dec 22 02:26 index.html
| **** remote
| 2024-12-22 02:26:23 3 index.html
[deploy/job1] ✅ Success - Main List bucket for debug
[deploy/job1] Cleaning up container for job job1
[deploy/job1] 🏁 Job succeeded
rm -f .act_env
まとめ
今回紹介したMakefileとactを活用することで、以下のメリットが得られます。
-
効率的なローカルテスト
Githubに依存せず、ローカルで素早くテストが実行可能。 -
セキュリティの確保
一時的なクレデンシャルを使用し、セキュリティリスクを最小限に抑える。 -
再利用可能な仕組み
Makefileにより、複雑な手順を簡潔に再現できる。
Discussion