はじめに

S3上のコンテンツをCloudFrontを使用し配信している。

参照:独自ドメインを使用してS3上の静的ウェブサイトをRoute53を使用し公開する

また、githubへpushした際、CodePipeLineを使用し自動build、自動deployは対応済

参照:GithubへのpushをトリガーとしてCode PipelineでJekyllをビルドしてS3にデプロイする

S3の更新をトリガーとし、LambdaからCodeFrontのInvalidationを実行する

手順

IAM ロールの作成

IAM コンソールから新しいロールを作成する

ロールの作成を選択

信頼されたエンティティの種類を選択

AWSサービス選択

ユースケースの選択

Lambdaを選択

次のステップを選択

ポリシーの作成を選択

権限内容は以下の JSON で指定する

※「Automatic Cloudfront invalidation with Amazon Lambda」より引用

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
        "Effect": "Allow",
        "Action": [
            "cloudfront:CreateInvalidation"
        ],
        "Resource": [
            "*"
        ]
    }
  ]
}

タグは任意で必要であれば作成する

名前も任意で自分のわかりやすい名称をつける

例:lambda_cloud_front_invalidation

先ほど作成したポリシーを検索し、選択

次のステップを選択

タグは任意で必要であれば作成する

名前も任意で自分のわかりやすい名称をつける

例:lambda_cloud_front_invalidation

ポリシーと区別する必要もないと考えたので同じ名前

Lambda 関数の作成

Lambda コンソールから新しい関数を作成する

一から作成を選択

関数名は任意で入力

ランタイムで使用する言語は「Python 3.8」、実行ロールは既存のロールから「先ほど作成した IAM ロール」を指定する

トリガーを追加を選択

YOUR_DISTRIBUTION_IDは自身のDISTRIBUTION IDに置き換える

from __future__ import print_function

import boto3
import time

def lambda_handler(event, context):
    for items in event["Records"]:
        if path in items["s3"]["object"]["key"]:
            client = boto3.client('cloudfront')
            invalidation = client.create_invalidation(DistributionId='YOUR_DISTRIBUTION_ID',
                InvalidationBatch={
                    'Paths': {
                        'Quantity': 1,
                        'Items': ['/*']
                },
                'CallerReference': str(time.time())
            })
            break

問題なく、S3を更新した際にLambdaが実行されたことを確認できた。

おわりに

問題なく実行はされたが、CodePipeLineにてdeployした場合、更新対象ファイル分Lambdaが実行される。

その為、トリガーをS3が更新された場合ではなく、CodePipeLineにてLambdaを実行する。

参考