目的
・AWS上の静的Webサイトホスティングを有効にしたS3をCloudFrontで公開。
・S3のコンテンツを更新した際に、CloudFrontのキャッシュ削除を行うLambdaを実装。
前提条件
・Terraformを使用してAWS上にリソースを作成する。
・Pythonを使用してLambdaを実装する。
・作成する内容は以下と同様
TFファイル
resource "aws_s3_bucket_notification" "WebBucket_notification" {
bucket = aws_s3_bucket.WebBucket.id
lambda_function {
lambda_function_arn = aws_lambda_function.DeleteCache.arn
events = ["s3:ObjectCreated:*","s3:ObjectRemoved:*"]
filter_suffix = "index.html"
}
}
data "archive_file" "lambda_delete_cache" {
type = "zip"
source_file = "${path.module}/lambda/delete_cache.py"
output_path = "${path.module}/lambda_zip/delete_cache.zip"
}
resource "aws_lambda_function" "DeleteCache" {
filename = "${path.module}/lambda_zip/delete_cache.zip"
function_name = "delete_cache"
role = aws_iam_role.delete_cache_lambda_role.arn
handler = "delete_cache.lambda_handler"
runtime = "python3.11"
source_code_hash = filebase64sha256("${path.module}/lambda/delete_cache.py")
environment {
variables = {
DISTRIBUTION_ID = aws_cloudfront_distribution.WebBucketDistribution.id
}
}
}
resource "aws_lambda_permission" "allow_s3_to_invoke" {
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.DeleteCache.function_name
principal = "s3.amazonaws.com"
source_account = data.aws_caller_identity.self.account_id
source_arn = aws_s3_bucket.WebBucket.arn
}
data "aws_iam_policy_document" "allow_access_to_WebBucket" {
statement {
principals {
type = "Service"
identifiers = ["cloudfront.amazonaws.com"]
}
effect = "Allow"
actions = ["s3:GetObject"]
resources = ["${aws_s3_bucket.WebBucket.arn}/*"]
condition {
test = "StringEquals"
variable = "aws:SourceArn"
values = [aws_cloudfront_distribution.WebBucketDistribution.arn]
}
}
}
resource "aws_iam_role" "delete_cache_lambda_role" {
name = "DeleteCacheLambdaRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
},
]
})
}
resource "aws_iam_role_policy" "delete_cache_lambda_policy" {
role = aws_iam_role.delete_cache_lambda_role.id
policy = jsonencode({
Statement = [
{
Action = ["cloudfront:CreateInvalidation","cloudfront:ListDistributions"]
Effect = "Allow"
Resource = "*"
},
{
Action = ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"]
Effect = "Allow"
Resource = ["arn:aws:logs:*:*:*"]
},
]
})
}
◆aws_s3.tf
・WebBucket_notification:WebBucketでindex.htmlが作成・削除された際にLambda関数を呼び出すS3通知
◆aws_lambda.tf
・lambda_delete_cache:Lambda関数用のPythonファイルをZip圧縮
・DeleteCache:Lambda関数定義
a. source_code_hash:TerraformがLambda関数のソースコードが変更を検出するために使用するハッシュ値
b. environment:ディストリビューションIDを環境変数として設定
・allow_s3_to_invoke:Lambdaに付与するリソースベースのポリシー
◆aws_iam.tf
・allow_access_to_WebBucket:aws_s3.tfより移管したもの(前回記事より)
・delete_cache_lambda_role:キャッシュ削除Lambda用IAMロール
・delete_cache_lambda_policy:「delete_cache_lambda_role」に付与するポリシー
Lambda
import os
import boto3
def lambda_handler(event, context):
cloudfront_client = boto3.client('cloudfront')
distribution_id = os.environ['DISTRIBUTION_ID']
paths_to_invalidate = ['/index.html']
#CloudFrontのキャッシュ削除
cloudfront_client.create_invalidation(
DistributionId=distribution_id,
InvalidationBatch={
'Paths': {
'Quantity': len(paths_to_invalidate),
'Items': paths_to_invalidate
},
'CallerReference': str(context.aws_request_id)
}
)
動作確認
①作成されたS3バケットへ「index.html」をアップロードする
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>My Website Home Page</title>
</head>
<body>
<h1>Welcome to my website(CloudFront)</h1>
<p>Now hosted on Amazon S3 using Terraform(Before)!</p>
</body>
</html>
③S3バケットへ「index.html」をアップロードする(更新)
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>My Website Home Page</title>
</head>
<body>
<h1>Welcome to my website(CloudFront)</h1>
<p>Now hosted on Amazon S3 using Terraform(After)!</p>
</body>
</html>
④ブラウザの更新
・表示される画面が更新され最新のコンテンツが配信されていることを確認
⑤ログ(CloudWatch)にエラーが出ていないことの確認
参考(前回記事)