[AWS] S3を更新するたびにCloudFrontのキャッシュが自動で削除されるようにしたい。


![s32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/0cfb7b9e-5efe-13b6-5ce4-ebf832bacc1d.jpeg)

# 前提
こんな感じの構成で静的なWebサイトを運用していて、
S3バケット内のファイルを更新するたびに
CloudFrontのキャッシュクリアを手動で作成しなければならず
非常にストレスを感じている人向けです！！！

![zentei01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/227a7887-8ee9-a1b6-e543-934b11b51ea5.jpeg)

※ 上記の作り方がわからない方は以下
https://qiita.com/GeneLab_999/items/e34a01af3f39f2d544b6

※ この方法は時間がない時の簡易的なやりかたです。ほんとは以下みたいな方法でやった方が良いです。
https://qiita.com/GeneLab_999/items/017af937345c39e64ecb

# 完成図
CloudFrontのキャッシュを無効化するLambdaを作って、
S3ファイル変更を検知してイベント通知をその関数に飛ばして自動化する！

![kansei01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/0f2b0b7b-c242-d940-cd61-893660d3c404.jpeg)



# 1.Lambda関数の作成
#### 1-1.関数の作成
Lambda関数の新規作成画面に来たら以下の設定で関数を作成する。
**1から作成** を選択し、以下のように設定をする。

| 項目                 | 値                                             |
|----------------------|------------------------------------------------|
| 関数名               | 任意の名前 (例:CacheClearCF)|
| ランタイム           | Python3.12                                     |
| アーキテクチャ       | arm64                                          |
| デフォルト実行ロール | 基本的な Lambda アクセス権限で新しいロールを作成 |
| その他の構成         | デフォルト設定でOK                             |


![スクリーンショット 2025-02-01 17.20.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/1c296638-17a7-13aa-c02d-2964a2240705.png)

#### 1-2.コードのデプロイ
先の設定にてLambda関数'CacheClearCF'新規作成したら、
'CacheClearCF'コードソースからのlambda_function.pyに以下のコードを挿入し
Deployを実行する。

![スクリーンショット 2025-02-01 17.26.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/43c073c5-6592-5781-2b91-495b842e955e.png)


```
import json
import boto3
import os
from datetime import datetime

# CloudFrontのディストリビューションIDは環境変数などで管理
CLOUDFRONT_DIST_ID = os.environ.get('CLOUDFRONT_DIST_ID')
client = boto3.client('cloudfront')

def lambda_handler(event, context):
    # event 内に S3 の情報が入っているので、必要に応じて処理
    paths = []
    for record in event.get('Records', []):
        s3_info = record.get('s3', {})
        object_key = s3_info.get('object', {}).get('key')
        if object_key:
            # CloudFront で無効化するパスの形式に合わせる
            paths.append('/' + object_key)
    
    # 重複除外や必要なパスをまとめる
    if not paths:
        return {
            'statusCode': 200,
            'body': json.dumps('No paths to invalidate.')
        }

    # CreateInvalidation API を呼び出す
    caller_reference = str(datetime.utcnow().timestamp())
    invalidation = client.create_invalidation(
        DistributionId=CLOUDFRONT_DIST_ID,
        InvalidationBatch={
            'Paths': {
                'Quantity': len(paths),
                'Items': paths
            },
            'CallerReference': caller_reference
        }
    )

    return {
        'statusCode': 200,
        'body': json.dumps(f"Invalidation created: {invalidation['Invalidation']['Id']}")
    }
```

#### 1-3.環境変数の設定
Lambda 関数内のコードで参照している CLOUDFRONT_DIST_ID を設定する。
キー: CLOUDFRONT_DIST_ID
値: 対象のCloudFrontディストリビューションID

#### 1-4.アクセス権限を追加
**AWSのサービス** を選択し、他は以下のように入力する。
| 項目             | 値                                                      |
|------------------|---------------------------------------------------------|
| サービス         | S3                                                      |
| ステートメントID | <任意の命名: 例: AllowS3InvokeLambda>                      |
| プリンシパル     | s3.amazonaws.com                                        |
| ソースアカウント | <自身のAWS アカウントID(12桁の数字)>                     |
| ソース ARN       | <対象のS3バケットのARN>                                  |
| アクション       | lambda:InvokeFunction                                   |


![スクリーンショット 2025-02-01 17.48.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/ad1a9eab-8c65-7c5a-d313-47c244f2de93.png)



#### 1-5.ポリシーを編集

##### 1-5-1.コンソールで対象のロールを開く
対象のLambda関数のコンソールから、設定(タブ)/ アクセス権限(タブ) / と進む
**実行ロール**の項目内に**ロール名**というタイトルでリンクがあるはずなので、それをクリックすると、
IAMのコンソール画面へ移動する。

##### 1-5-2.インラインポリシーを作成
アクセス管理 / ロール / 許可(タブ) / 許可ポリシー /と進むと
**許可を追加**というプルダウンがあるので、そこで**インラインポリシーを作成**を選択する。
![スクリーンショット 2025-02-01 18.32.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/622417b7-19b4-188d-9647-33d7fedd84da.png)


![スクリーンショット 2025-02-01 18.39.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/8d41bc26-d0b4-e604-0ed8-c9bf9825a743.png)

**JSON**タブを選択し、以下のように入力する。

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "cloudfront:CreateInvalidation",
      "Resource": "arn:aws:cloudfront::<あなたのAWSアカウントID>:distribution/<対象のディストリビューションID>"
    }
  ]
}

```
次の画面に進んだら、任意のポリシー名(例: **Policy_CashClearCF**)を設定し、「ポリシーの作成」ボタンをクリックし、この設定を完了させる。


![スクリーンショット 2025-02-01 18.42.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/c3e8f037-bc53-81cb-a219-61bb9eafd2ec.png)

---

## 2.S3 イベントの設定
#### 2-1.対象のオブジェクト更新を検知するようにイベント通知」を設定
このイベントが Lambda 関数を起動するように設定します。

[階層]　AMAZON S3/バケット/プロパティ(タブ)/
[操作] **イベント通知を作成** ボタンをクリック
![スクリーンショット 2025-02-01 16.59.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/68481dcf-c609-fc05-bd75-a227fa44f96d.png)


#### 2-2.イベント通知を作成画面
##### 一般的な設定
 ![スクリーンショット 2025-02-01 17.10.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/391e0043-d807-2adc-cd29-fc1e13a17357.png)
**・イベント名**
　└ 何でも良い。今回は **CloudFrontInvalidationTrigger** とした。

**・プレフィックス**
　└ すべてのオブジェクトに対してイベントを発火させる場合は空欄のままで大丈夫。
    ※もし特定のディレクトリ（例: assets/ や static/）のみ更新対象にしたい場合は、そのディレクトリ名     （末尾にスラッシュ「/」を含める）を設定。
**・サフィックス**
　└ 全てのファイルを対象にするなら空欄でOK。
    ※特定の拡張子（例: .html や .css など）だけに限定したい場合は、その拡張子を設定。


##### イベントタイプの設定
![スクリーンショット 2025-02-01 18.07.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/486f3b0a-bc09-a426-74c1-8a6844c69c07.png)

以下の2つをチェック
s3:ObjectCreated:* 
s3:ObjectRemoved:*

##### 送信先
![スクリーンショット 2025-02-01 18.05.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3908981/4aad9d93-ecc9-34a6-558b-75e8eb1df798.png)
**送信先**
**Lambda関数** をチェック

**Lambda関数**
先ほど作成したLambda関数を選択

##### その他
デフォルトで問題なし。
**変更を保存** ボタンで新規作成が完了する。


# 3.テスト

#### 3-1.S3バケットのファイルを更新
実際のサイトを見てみて、対象のファイルが更新できていたらOK!
うまくかなかったらCloudWatch Logsをチェックしてみてね！