Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 107 additions & 7 deletions deployment/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,42 @@ locals {
images_bucket = "localstack-thumbnails-app-images"
image_resized_bucket = "localstack-thumbnails-app-resized"
website_bucket = "localstack-website"
failure_notifications_email = "my-email@example.com"

failure_notifications_email = "failure-notifications@example.com"
}

# AWS profile should not be set here since
# it needs to be blank for .github/workflows/integration_tests.yml
# to work with the default LocalStack profile. Use environment variables instead.
#
# bash example: AWS_PROFILE=my-profile AWS_REGION=us-east-1 terraform apply
#
#provider "aws" {
# region = "us-east-1"
# profile = "myuser-sso-admin"
#}

# S3
resource "aws_s3_bucket" "images_bucket" {
bucket = local.images_bucket
force_destroy = true
}

resource "aws_s3_bucket" "image_resized_bucket" {
bucket = local.image_resized_bucket
force_destroy = true
}

resource "aws_s3_bucket_cors_configuration" "images_bucket_cors" {
bucket = aws_s3_bucket.images_bucket.id

cors_rule {
allowed_headers = ["*"]
allowed_methods = ["POST", "PUT"]
allowed_origins = ["https://${aws_cloudfront_distribution.cdn.domain_name}"]
expose_headers = ["ETag"]
max_age_seconds = 3000
}
}

# SSM
Expand Down Expand Up @@ -82,6 +108,14 @@ resource "aws_lambda_function" "presign_lambda" {
resource "aws_lambda_function_url" "presign_lambda_function" {
function_name = aws_lambda_function.presign_lambda.function_name
authorization_type = "NONE"

cors {
allow_credentials = false
allow_origins = ["https://${aws_cloudfront_distribution.cdn.domain_name}"]
allow_methods = ["GET"]
allow_headers = ["content-type"]
max_age = 86400
}
}

# List images lambda
Expand Down Expand Up @@ -126,6 +160,14 @@ resource "aws_lambda_function" "list_lambda" {
resource "aws_lambda_function_url" "list_lambda_function" {
function_name = aws_lambda_function.list_lambda.function_name
authorization_type = "NONE"

cors {
allow_credentials = false
allow_origins = ["https://${aws_cloudfront_distribution.cdn.domain_name}"]
allow_methods = ["GET"]
allow_headers = ["content-type"]
max_age = 86400
}
}

# Resize lambda
Expand All @@ -138,6 +180,7 @@ resource "aws_iam_role" "resize_lambda_role" {
resource "aws_iam_policy" "resize_lambda_s3_buckets" {
name = "ResizeLambdaS3Buckets"
policy = templatefile("policies/resize_lambda_s3_buckets.json.tpl", {
images_bucket = aws_s3_bucket.images_bucket.bucket,
images_resized_bucket = aws_s3_bucket.image_resized_bucket.bucket
})
}
Expand All @@ -150,8 +193,7 @@ resource "aws_iam_role_policy_attachment" "resize_lambda_s3_buckets" {
resource "aws_iam_policy" "resize_lambda_sns" {
name = "ResizeLambdaSNS"
policy = templatefile("policies/resize_lambda_sns.json.tpl", {
failure_notifications_topic_arn = aws_sns_topic.failure_notifications.arn,
resize_lambda_arn = aws_lambda_function.resize_lambda.arn
failure_notifications_topic_arn = aws_sns_topic.failure_notifications.arn
})
}

Expand All @@ -170,6 +212,7 @@ resource "aws_lambda_function" "resize_lambda" {
filename = "${local.root_dir}/lambdas/resize/lambda.zip"
handler = "handler.handler"
runtime = "python3.11"
timeout = 30
role = aws_iam_role.resize_lambda_role.arn
source_code_hash = filebase64sha256("${local.root_dir}/lambdas/resize/lambda.zip")

Expand Down Expand Up @@ -230,7 +273,6 @@ resource "aws_s3_object" "website_file_index" {
source = "${local.root_dir}/website/index.html"
etag = filemd5("${local.root_dir}/website/index.html")
content_type = "text/html"
acl = "public-read"
}

resource "aws_s3_object" "website_file_js" {
Expand All @@ -239,7 +281,6 @@ resource "aws_s3_object" "website_file_js" {
source = "${local.root_dir}/website/app.js"
etag = filemd5("${local.root_dir}/website/app.js")
content_type = "application/javascript"
acl = "public-read"
}

resource "aws_s3_object" "website_file_icon" {
Expand All @@ -248,7 +289,6 @@ resource "aws_s3_object" "website_file_icon" {
source = "${local.root_dir}/website/favicon.ico"
etag = filemd5("${local.root_dir}/website/favicon.ico")
content_type = "image/x-icon"
acl = "public-read"
}

resource "aws_cloudfront_origin_access_identity" "cdn_identity" {
Expand Down Expand Up @@ -284,13 +324,20 @@ resource "aws_cloudfront_distribution" "cdn" {
default_cache_behavior {
target_origin_id = aws_s3_bucket.website_bucket.bucket

allowed_methods = ["GET", "HEAD"]
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]

viewer_protocol_policy = "redirect-to-https"
min_ttl = 0
default_ttl = 86400
max_ttl = 31536000

forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
}

restrictions {
Expand All @@ -309,6 +356,59 @@ resource "aws_s3_bucket_public_access_block" "website_block_public_access" {
restrict_public_buckets = true
}

# CloudWatch Log Groups

resource "aws_cloudwatch_log_group" "presign_lambda_logs" {
name = "/aws/lambda/presign"
retention_in_days = 14
}

resource "aws_cloudwatch_log_group" "list_lambda_logs" {
name = "/aws/lambda/list"
retention_in_days = 14
}

resource "aws_cloudwatch_log_group" "resize_lambda_logs" {
name = "/aws/lambda/resize"
retention_in_days = 14
}

resource "aws_iam_policy" "lambda_cloudwatch_logs" {
name = "LambdasCloudWatchLogs"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = [
"${aws_cloudwatch_log_group.presign_lambda_logs.arn}:*",
"${aws_cloudwatch_log_group.list_lambda_logs.arn}:*",
"${aws_cloudwatch_log_group.resize_lambda_logs.arn}:*"
]
}
]
})
}

resource "aws_iam_role_policy_attachment" "presign_lambda_cloudwatch" {
role = aws_iam_role.presign_lambda_role.name
policy_arn = aws_iam_policy.lambda_cloudwatch_logs.arn
}

resource "aws_iam_role_policy_attachment" "list_lambda_cloudwatch" {
role = aws_iam_role.list_lambda_role.name
policy_arn = aws_iam_policy.lambda_cloudwatch_logs.arn
}

resource "aws_iam_role_policy_attachment" "resize_lambda_cloudwatch" {
role = aws_iam_role.resize_lambda_role.name
policy_arn = aws_iam_policy.lambda_cloudwatch_logs.arn
}

# Outputs

output "presign_lambda_function_url" {
Expand Down
4 changes: 2 additions & 2 deletions deployment/terraform/policies/lambda_ssm.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
{
"Effect": "Allow",
"Action": [
"ssm:GetParameters"
"ssm:GetParameter"
],
"Resource": [
"arn:aws:ssm:::parameter/localstack-thumbnail-app/*"
"arn:aws:ssm:*:*:parameter/localstack-thumbnail-app/*"
]
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::${images_bucket}",
"arn:aws:s3:::${images_bucket}/*",
"arn:aws:s3:::${images_resized_bucket}",
"arn:aws:s3:::${images_resized_bucket}/*"
]
Expand Down
5 changes: 0 additions & 5 deletions deployment/terraform/policies/resize_lambda_sns.json.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
],
"Effect": "Allow",
"Resource": "${failure_notifications_topic_arn}"
},
{
"Action": "lambda:InvokeFunction",
"Effect": "Allow",
"Resource": "${resize_lambda_arn}"
}
]
}