静的キーレス CI/CD ワークフロー実装 — git push から本番反映まで
前記事で OIDC + IAM Role の準備ができたので、いよいよ 「git push したら自動デプロイ」 のワークフローを書きます。本記事では .github/workflows/frontend-deploy.yml を 1 行ずつ解説していきます。
ワークフロー全文
name: frontend-deploy
on:
push:
branches: [main]
paths:
- 'frontend/**'
- '.github/workflows/frontend-deploy.yml'
workflow_dispatch: {}
permissions:
id-token: write
contents: read
concurrency:
group: frontend-deploy-${{ github.ref }}
cancel-in-progress: true
env:
AWS_REGION: ap-northeast-1
AWS_ROLE_TO_ASSUME: arn:aws:iam::XXXXXXXXXXXX:role/iigtn-github-actions-deploy
S3_BUCKET: iigtn-lab-web-prod-XXXXXXXXXXXX
CF_DISTRIBUTION_ID: EXXXXXXXXXXXXX
SITE_DIR: frontend
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.AWS_ROLE_TO_ASSUME }}
role-session-name: gha-frontend-deploy-${{ github.run_id }}
aws-region: ${{ env.AWS_REGION }}
- name: Verify caller identity
run: aws sts get-caller-identity
- name: Deploy to S3
run: |
aws s3 sync ./${{ env.SITE_DIR }}/ s3://${{ env.S3_BUCKET }}/ \
--delete \
--exclude ".git/*" \
--exclude "*.md" \
--exclude ".gitignore" \
--exclude ".gitkeep"
- name: Invalidate CloudFront
run: |
INV_ID=$(aws cloudfront create-invalidation \
--distribution-id ${{ env.CF_DISTRIBUTION_ID }} \
--paths "/*" \
--query 'Invalidation.Id' --output text)
aws cloudfront wait invalidation-completed \
--distribution-id ${{ env.CF_DISTRIBUTION_ID }} \
--id "$INV_ID"
- name: Verify deployment
run: curl -sI https://lab.iigtn.com/ | head -10
各セクション解説
1. on: — トリガー条件
on:
push:
branches: [main]
paths:
- 'frontend/**'
- '.github/workflows/frontend-deploy.yml'
workflow_dispatch: {}
- main への push のみ: feature ブランチからは走らない
- paths フィルタ:
frontend/配下が変わった時 + ワークフロー自身が変わった時のみ実行(terraform/ や docs/ の変更では走らない) - workflow_dispatch: 手動実行ボタンを GitHub UI に追加
2. permissions: — Job が要求する権限
permissions:
id-token: write # OIDC token 発行に必須
contents: read # actions/checkout でコードを clone するのに必要
デフォルトでは GitHub Actions の GITHUB_TOKEN はリポジトリへの広い権限を持ちますが、明示的に絞る ことでセキュリティを強化。issues / pull-requests への書き込みは要らないので最小権限。
3. concurrency: — 同時実行制御
concurrency:
group: frontend-deploy-${{ github.ref }}
cancel-in-progress: true
同じ main ブランチで連続 push した時、古い実行をキャンセルして最新だけ走らせる。デプロイレースが起きません。
4. env: — グローバル環境変数
env:
AWS_REGION: ap-northeast-1
AWS_ROLE_TO_ASSUME: arn:aws:iam::XXXXXXXXXXXX:role/...
S3_BUCKET: iigtn-lab-web-prod-XXXXXXXXXXXX
CF_DISTRIBUTION_ID: EXXXXXXXXXXXXX
SITE_DIR: frontend
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
ハードコードされた ARN や ID はここに集約。変更する時はこの 1 ブロックだけ触ればいい設計。
最後の FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 は、Node.js 20 の deprecation 対応。actions/checkout@v4 や aws-actions/configure-aws-credentials@v4 を強制的に Node.js 24 で動かす。
5. Step: Checkout
- name: Checkout
uses: actions/checkout@v4
リポジトリのソースを Runner の作業ディレクトリに clone。
6. Step: OIDC で AWS 認証
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.AWS_ROLE_TO_ASSUME }}
role-session-name: gha-frontend-deploy-${{ github.run_id }}
aws-region: ${{ env.AWS_REGION }}
裏側の挙動:
- GitHub に「OIDC token 発行して」を要求 → JWT 受信
- JWT を STS の AssumeRoleWithWebIdentity に渡す
- 1 時間有効の AccessKey/SecretKey/SessionToken を環境変数として注入
role-session-name に github.run_id を入れることで、CloudTrail で「どのワークフロー実行か」が追跡可能になります。
7. Step: 確認
- name: Verify caller identity
run: aws sts get-caller-identity
「自分が誰として動いているか」を表示。デバッグ用途。本番では削っても良いが、初回は入れておくと安心。
8. Step: S3 sync
- name: Deploy to S3
run: |
aws s3 sync ./${{ env.SITE_DIR }}/ s3://${{ env.S3_BUCKET }}/ \
--delete \
--exclude ".git/*" \
--exclude "*.md" \
--exclude ".gitignore" \
--exclude ".gitkeep"
aws s3 sync はディレクトリ間の差分同期。重要オプション:
--delete: ローカルに無いファイルを S3 から削除(完全ミラー)--exclude: 同期対象から除外するパターン
--delete は強力。frontend/ 配下が空のままで実行すると S3 が全削除されます。空のリポジトリ初回 push 等で事故が起きやすいので注意。
9. Step: CloudFront 無効化
- name: Invalidate CloudFront
run: |
INV_ID=$(aws cloudfront create-invalidation \
--distribution-id ${{ env.CF_DISTRIBUTION_ID }} \
--paths "/*" \
--query 'Invalidation.Id' --output text)
aws cloudfront wait invalidation-completed \
--distribution-id ${{ env.CF_DISTRIBUTION_ID }} \
--id "$INV_ID"
/* 全体無効化を 1 path カウントで実行。月 1,000 paths 無料枠内に余裕。
aws cloudfront wait で完了まで待ち、後続 step で確実に新版が見られるようにする。
10. Step: デプロイ確認
- name: Verify deployment
run: curl -sI https://lab.iigtn.com/ | head -10
本番 URL に HTTPS GET して、レスポンスヘッダを表示。HTTP 200 が返れば成功。失敗ヘッダなら GitHub Actions の job が赤くなります。
初回 push の動き
git push 後、GitHub Actions のページで実行を見ると、各 step が順に green で完了します。本シリーズの初回実行は 54 秒 で完了。
✓ Set up job
✓ Checkout
✓ Configure AWS credentials (OIDC)
✓ Verify caller identity
✓ Deploy to S3
✓ Invalidate CloudFront
✓ Verify deployment
✓ Complete job
失敗時の典型例
| 症状 | 原因 | 対処 |
|---|---|---|
| OIDC step で AssumeRole 失敗 | Trust Policy の sub 不一致 | repo:owner/repo:ref:refs/heads/main 表記が正しいか確認 |
| S3 sync で AccessDenied | Permissions Policy の resource ARN ミス | バケット ARN と /* 付加が正しいか確認 |
| CloudFront invalidation 失敗 | Distribution ID ミス or 権限不足 | env の ID と Permissions Policy 確認 |
| Verify step で 5xx | Origin (S3) で問題発生 / OAC 設定ミス | S3 の中身を aws s3 ls で確認 |
本シリーズで使うワークフロー数
現状は frontend-deploy.yml の 1 個だけ。今後追加予定:
terraform-plan.yml— PR 時に terraform plan を commentterraform-apply.yml— main merge 時に terraform apply(手動承認付き)backend-deploy.yml— Lambda コード更新
原則は「1 ワークフロー = 1 責務」。フロント / バック / Terraform を別ワークフローにすることで、片方の失敗が他に波及しない。
次の記事
静的サイトのデプロイ自動化が完了しました。次の記事から、いよいよ 動的バックエンド(API Gateway + Lambda + DynamoDB)の構築に入ります。問い合わせフォームを作って、ブラウザから POST されたデータを Lambda で処理し、DynamoDB に保存する、という流れです。
📚 用語集
- GitHub Actions
- GitHub 上で動く CI/CD サービス。ワークフローを YAML で書き、push や手動トリガーで実行する。
- workflow (ワークフロー)
.github/workflows/*.ymlファイル 1 つ = 1 ワークフロー。複数の Job を順次・並行で実行できる。- job
- ワークフロー内の独立した実行単位。Runner 1 台で動く。
- step
- Job 内の 1 ステップ。コマンド or アクション。
- Action
- 再利用可能な処理ユニット。
actions/checkout@v4等、コミュニティや公式が提供している。 - Runner
- ワークフローを実行するサーバ。GitHub-hosted Runner(無料枠あり)/ self-hosted Runner(自分のサーバ)。
- on (ワークフロートリガー)
- ワークフローが起動する条件。
push/pull_request/schedule/workflow_dispatch(手動)等。 - paths filter
on.push.pathsで指定する起動パスフィルタ。指定したパスのファイルが変更された時だけワークフローを起動。- workflow_dispatch
- 手動実行トリガー。GitHub UI に「Run workflow」ボタンが追加される。
- permissions (ワークフロー)
- Job が要求する
GITHUB_TOKENの権限。最小権限で書くのが推奨。 - concurrency
- 同時実行制御の設定。同じ group の実行を 1 つだけにする等の制御。
- env (グローバル環境変数)
- ワークフロー全体で使える環境変数。
${{ env.NAME }}で参照。 - aws s3 sync
- AWS CLI の S3 ディレクトリ同期コマンド。
--deleteでローカル不在ファイルを S3 から削除(完全ミラー)。 - aws cloudfront create-invalidation
- CloudFront のキャッシュを無効化する CLI コマンド。
--paths "/*"で全パス無効化。 - aws cloudfront wait invalidation-completed
- 無効化完了まで待機する CLI コマンド。CI/CD で「無効化が終わってから次の step」を保証するのに使う。
- github.run_id
- GitHub Actions が実行ごとに払い出す一意 ID。CloudTrail との突き合わせに使う。
- role-session-name
- AssumeRole 時の session 名。CloudTrail でこの名前で session が記録される。
- FORCE_JAVASCRIPT_ACTIONS_TO_NODE24
- Node.js 20 で動く Action を Node.js 24 で強制実行する環境変数。Node.js 20 の deprecation 対応。
- --exclude (aws s3 sync)
- 同期対象から除外するパターン指定。複数指定可。
.gitや.mdファイルを S3 に置きたくない時に使う。