Github Actionsを使ってAWS Lambdaを自動デプロイしてみた

## 概要
AWS Lambdaに設定している関数を修正・機能追加する際にコードを手動でコピペするのは手間なので、Githubで管理しているコードが更新される度に自動でLambdaに反映(デプロイ)する方法をまとめました。

管理対象のコードは[こちら](https://qiita.com/hasesho/items/262204013cd4a77e35ac)の記事で作成したものを想定しております。

![スクリーンショット 2024-08-16 16.50.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/7ee1dc62-fb58-8f80-9dda-4331573cdff1.png)

基本的に以下の記事を参考にさせていただきました。
https://dev.classmethod.jp/articles/lambda-github-actions/

## 前提
- 既にLambda関数に使用しているソースコードはGithubで管理している状態。
    - 構成は以下を想定

```
.
├── .github
│   └── workflows
├── README.md
├── lambda
│   ├── lambda_function.py
│   ├── line.py
│   └── notion.py
└── tests
```


## 大まかな手順
- 手順1：IAM IDプロバイダの登録
- 手順2：対象のLambda関数のARNを確認
- 手順3：IAMポリシーの登録
- 手順4：AWS IAMロールの登録
- 手順5：Github ActionsへのSecret登録
- 手順6：デプロイ用のyamlファイルを作成

## 詳細手順
### 手順1：IAM IDプロバイダの登録

[IAM IDプロバイダ](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers.html)とは、AWSの外部で管理されているユーザーID（例：Google、GitHubなど）を利用して、AWSリソースへのアクセスを許可する仕組みです。
AWS内でIAMユーザーを作成せず、既存のIDシステムやアプリケーションのIDを利用して認証を行うことができます。

IAMのページの左側からAccess management > Identity providers を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/9155cdc5-6313-8553-72e9-b0026164fe6b.png)

ID プロバイダ > プロバイダを追加 をクリックします。

以下の値で設定し、プロバイダを追加をクリックします。
- プロバイダのタイプ：OpenID Connect
- プロバイダのURL：https://token.actions.githubusercontent.com
- 対象者：sts.amazonaws.com
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/abfc6c4c-5ead-459d-89a7-9ba16189a9e7.png" width=50%>

追加したプロバイダの名前(token.actions.githubusercontent.com)は後ほど手順4で使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/0594cea1-06fc-6e84-0803-da687bc994bb.png)


### 手順2：対象のLambda関数のARNを確認

ARNとはAmazonリソースネーム (ARN)の略で、AWSリソースを一意に識別するIDのようなものです。

AWS Lambdaのページにアクセスします。

Lambda > 関数 > {自身の作成した関数名} > 関数の概要 から、関数のARNを確認し、メモしておきます。
こちらは手順3で使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/0e8a615a-7cbd-9f42-3415-42266168f9e8.png)

### 手順3：IAMポリシーの登録

IAMのページの左側からAccess management > Policies を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/5001108c-b2b0-98a3-71d8-f9976cb113e2.png)

ポリシーの作成 をクリックします。

JSONタブをクリックし、以下の通り入力し次へを押します。
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:UpdateFunctionCode"
            ],
            "Resource": "{手順2でメモしたLambdaのARNを入力}"
        }
    ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/77ffbfba-f92f-9053-7276-115e18d40ff4.png)

### 手順4：AWS IAMロールの登録
IAMのページの左側からAccess management > Roles を選択します。

ロールを作成 をクリックします。
以下の通り設定し次へをクリックします。
- 信頼されたエンティティタイプ：ウェブアイデンティティ
- ウェブアイデンティティ
    - アイデンティティプロバイダー：token.actions.githubusercontent.com
    - Audience：sts.amazonaws.com
    - GitHub 組織：自身のアカウント名
        - ※githubにログインしてYour profileにアクセスした際のURL(https://github.com/xxxx)のxxxxの部分
    - GitHub リポジトリ-オプション：対象のレポジトリ名
    - GitHub ブランチ-オプション：対象のブランチ名
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/4104aad5-635c-a4fb-8577-db6d07ea9c04.png)

許可を追加 > 許可ポリシー で手順3で作成したポリシーを選択し次へ。

名前、確認、および作成 > ロールの詳細 でロール名や説明を入力後、ロールを作成をクリック。

### 手順5：Github ActionsへのSecret登録

Githubの対象リポジトリ画面を開く。

Settings > Secrets and Variables > Actions クリックします。

New repository secretをクリックします。

以下のパラメータをそれぞれ設定する。(パラメータ名は任意)
- AWS_REGION：自身が作成したLambdaが配置されているリージョン名を指定
    - 例：ap-southeast-2
- AWS_ROLE_ARN：先ほど手順4で作成したロールのARN
    - IAM > ロール > {ロール名} > 概要 > ARN から確認可能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/2ee6f9c7-db53-382e-a8d8-75d8c5491c83.png)

### 手順6：デプロイ用のyamlファイルを作成

リポジトリのルートに .github/workflows ディレクトリを作成し、その中に deploy.yml ファイルを作成します。

このファイルではGitHub Actionsを使用して、指定したブランチ(mainと想定)にプッシュされるたびに自動的にLambda関数を更新するように設定しています。
この中で先ほど手順5で設定したsecretのパラメータが利用されています。

--function-name 等は各々で適した値を設定してください。
```
name: AWS Lambda Deploy

# トリガー条件
on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - name: checkout
        uses: actions/checkout@v3

      - name: configure-aws-credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-region: ${{ secrets.AWS_REGION }}
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          role-session-name: GitHubActions

      - name: get-caller-identity is allowed to run on role.
        run: aws sts get-caller-identity

      - name: lambda update
        run: |
          cd lambda && zip -r package.zip ./*
          aws lambda update-function-code --function-name LINEtoNotionHandler --zip-file fileb://package.zip --publish
```

以上でmainブランチにpushした際に自動でAWS Lambdaの関数も更新されるようになりました！

参考までにyaml内の処理を紐解くと以下のような流れです。
- 1.トリガーを検知
- 2.コードのチェックアウト: リポジトリのコードを取得
- 3.AWS認証情報の設定: 指定されたIAMロールを使用してAWSにアクセス
- 4.呼び出し元の確認: aws sts get-caller-identity で認証情報の確認
- 5.Lambda関数の更新: lambdaディレクトリの内容をZIPファイルに圧縮し、そのZIPファイルを使用して指定されたLambda関数を更新

実際にトリガーのアクションを実施することでデプロイ処理が走っているのがGithubリポジトリのActionsや、AWSの対象のLambda関数のページの下の方を見ていただくとお分かりいただけると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/1a86bd16-ddc6-bc80-a9cf-fc4784d00e78.png)


余談ですが、私は実際にはmainにpushされた際にlintやformatチェック、単体テストのCIを走らせてそれを通過した後にデプロイを実施する設定にしておりまして、トリガー条件を以下のように設定することでその設定を反映できます。

```
on:
  workflow_run:
    workflows: ["Ruff, Mypy, Pydocstyle, and Pytest Check"] # CIワークフロー名を指定
    types:
      - completed
```

## おわりに
意外と簡単にLambdaの自動デプロイが実装できました。
特にIAM IDプロバイダという便利な仕組みを知らなかったので大変勉強になりました。
これらの技術を活かしてスマートに機能追加を実施していければと思います。