GitHub Actions で Lambda のデプロイを自動化する
概要
AWS Lambda を手動でデプロイしていると、更新のたびに「zip を作って」「コンソールにアップロードして」「環境変数を確認して」という作業が発生します。ちょっとした修正でもこの手順を踏むのは負担で、手作業のぶんだけデプロイ漏れや事故の温床にもなります。
この記事では、GitHub Actions を使って Lambda のデプロイを自動化する手順をハンズオン形式でまとめます。特に OIDC による IAM ロール連携(長期的なアクセスキーを GitHub に置かない方式)を中心に据えます。
対象読者は、Lambda を触ったことがあり、GitHub Actions の基本的な YAML が読める人です。
環境
- ランタイム: Node.js 20.x(Python 3.12 でも考え方は同じ)
- デプロイ対象: 単一の Lambda 関数
- トリガー:
mainブランチへの push - AWS 側: OIDC プロバイダ + デプロイ用 IAM ロール
- CLI:
awsv2
全体像
やることは大きく3つです。
- AWS 側に GitHub Actions を信頼する OIDC プロバイダと IAM ロールを作る
- GitHub Actions のワークフローで、そのロールを一時的に引き受ける(AssumeRole)
- ビルドした成果物を
aws lambda update-function-codeで反映する
アクセスキーを GitHub Secrets に長期保存しないのがポイントです。OIDC を使うと、ワークフロー実行時に発行される短命なトークンで AWS のロールを引き受けられます。
Step 1: AWS 側に OIDC プロバイダを作る
まず、GitHub の OIDC を信頼するプロバイダを IAM に登録します。
aws iam create-open-id-connect-provider \ --url https://token.actions.githubusercontent.com \ --client-id-list sts.amazonaws.com \ --thumbprint-list <指紋>
すでに同一 URL のプロバイダがアカウントに存在する場合は作成不要です。
Step 2: デプロイ用 IAM ロールを作る
このロールの信頼ポリシーで「どのリポジトリ・どのブランチからなら引き受けを許すか」を絞ります。ここが緩いと、他人のリポジトリからロールを引き受けられてしまうため重要です。
信頼ポリシーの例:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:<OWNER>/<REPO>:ref:refs/heads/main"
}
}
}
]
}
sub の条件を repo:<OWNER>/<REPO>:ref:refs/heads/main にすることで、「そのリポジトリの main ブランチのワークフローからのみ」に限定できます。
権限ポリシー(何ができるか)は最小限にします。関数コードの更新だけなら以下で足ります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["lambda:UpdateFunctionCode", "lambda:GetFunction"],
"Resource": "arn:aws:lambda:<REGION>:<ACCOUNT_ID>:function:<FUNCTION_NAME>"
}
]
}
設定変更まで自動化する場合だけ lambda:UpdateFunctionConfiguration を足しますが、必要になるまで付けないのが安全です。
Step 3: GitHub Actions ワークフロー
.github/workflows/deploy.yml を作ります。
name: Deploy Lambda
on:
push:
branches: [main]
permissions:
id-token: write # OIDC トークン発行に必須
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm ci --omit=dev
- name: Package
run: zip -r function.zip . -x "*.git*" "tests/*"
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<ACCOUNT_ID>:role/<DEPLOY_ROLE_NAME>
aws-region: <REGION>
- name: Deploy to Lambda
run: |
aws lambda update-function-code \
--function-name <FUNCTION_NAME> \
--zip-file fileb://function.zip \
--publish
ポイントは以下です。
permissions.id-token: writeを忘れると OIDC トークンが発行されず AssumeRole に失敗します(ハマりどころ No.1)configure-aws-credentialsにrole-to-assumeを渡すだけで、以降のステップは一時クレデンシャルで動きます--publishを付けると新しいバージョンが発行され、ロールバックや alias 運用がしやすくなります
デプロイ完了を待って確認する
update-function-code はコードの反映を非同期で開始します。直後にトラフィックを流す運用なら、更新完了を待つのが安全です。
aws lambda wait function-updated \ --function-name <FUNCTION_NAME>
設定更新直後にコード更新をかけると ResourceConflictException が出ることがあるので、連続更新するワークフローでは wait を挟むと安定します。
実装例: alias を使った安全なリリース
いきなり本番トラフィックに新バージョンを当てるのが不安なら、alias を使います。
VERSION=$(aws lambda update-function-code \ --function-name <FUNCTION_NAME> \ --zip-file fileb://function.zip \ --publish \ --query 'Version' --output text) aws lambda update-alias \ --function-name <FUNCTION_NAME> \ --name prod \ --function-version "$VERSION"
alias にトラフィックの重み付けを設定すれば、カナリアリリースも可能です。
確認方法
mainに push し、Actions のログでConfigure AWS credentialsが成功しているか確認するaws lambda get-function --function-name <FUNCTION_NAME> --query 'Configuration.LastModified'で更新時刻が変わっているか確認する- 実際に関数を叩いて挙動を確認する
aws lambda invoke \
--function-name <FUNCTION_NAME> \
--payload '{}' \
--cli-binary-format raw-in-base64-out \
out.json && cat out.json
注意点
id-token: writeの付け忘れ — 最頻出のエラー原因- 信頼ポリシーの
subの書き方 — ブランチ限定・タグ限定・環境限定を使い分ける。ワイルドカードを広げすぎない - 権限は最小限 — まず
UpdateFunctionCodeだけで始める - 大きな成果物 — zip が 50MB を超える場合は S3 経由にする。コンテナイメージ運用なら ECR +
--image-uri - 依存の同梱 —
npm ci --omit=devで本番依存だけにする
まとめ
- GitHub Actions からの Lambda デプロイは、OIDC + IAM ロールで秘密鍵を持たずに実現できる
- 信頼ポリシーの
sub条件でリポジトリ・ブランチを絞り、権限は最小限にする id-token: writeの付与を忘れない- 連続更新するなら
wait function-updated、安全にリリースしたいなら alias を活用する
最初のセットアップさえ済ませれば、以降は main に merge するだけでデプロイが回ります。手作業から解放されるだけでなく、「誰が・いつ・どのコミットを」デプロイしたかがログに残るのも大きな利点です。
