From abc903d9d3aabbb2fbb51e47679c0b2c61b3f6e7 Mon Sep 17 00:00:00 2001 From: Kurt Gardiner Date: Wed, 6 Apr 2022 06:46:28 +1000 Subject: [PATCH 1/8] Better example objects links and bootstrapping (#45) --- docs/examples/main.tf | 10 +++++----- docs/examples/vpc_setup/vpc.tf | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/examples/main.tf b/docs/examples/main.tf index c5375db..b5d96b6 100644 --- a/docs/examples/main.tf +++ b/docs/examples/main.tf @@ -14,15 +14,15 @@ module "peterdotcloud_vpc" { module "peterdotcloud_website" { source = "TechToSpeech/serverless-static-wordpress/aws" version = "0.1.2" - main_vpc_id = "vpc-e121c09b" - subnet_ids = ["subnet-04b97235", "subnet-08fb235", "subnet-04b97734"] + main_vpc_id = module.peterdotcloud_vpc.main_vpc_id + subnet_ids = tolist(module.peterdotcloud_vpc.subnet_ids) aws_account_id = data.aws_caller_identity.current.account_id # site_name will be used to prepend resource names - use no spaces or special characters site_name = local.site_name site_domain = local.site_domain wordpress_subdomain = "wordpress" - hosted_zone_id = "Z00437553UWAVIRHANGCN" + hosted_zone_id = aws_route53_zone.apex.id s3_region = local.aws_region slack_webhook = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" ecs_cpu = 1024 @@ -47,7 +47,7 @@ module "docker_pullpush" { aws_account_id = data.aws_caller_identity.current.account_id aws_region = local.aws_region docker_source = "wordpress:php7.4-apache" - aws_profile = "peterdotcloud" + aws_profile = local.profile ecr_repo_name = module.peterdotcloud_website.wordpress_ecr_repository ecr_repo_tag = "base" depends_on = [module.peterdotcloud_website] @@ -80,7 +80,7 @@ resource "null_resource" "update_nameservers" { nameservers = aws_route53_zone.apex.id } provisioner "local-exec" { - command = "aws route53domains update-domain-nameservers --region us-east-1 --domain-name ${local.site_domain} --nameservers Name=${aws_route53_zone.apex.name_servers.0} Name=${aws_route53_zone.apex.name_servers.1} Name=${aws_route53_zone.apex.name_servers.2} Name=${aws_route53_zone.apex.name_servers.3} --profile peterdotcloud" + command = "aws route53domains update-domain-nameservers --region us-east-1 --domain-name ${local.site_domain} --nameservers Name=${aws_route53_zone.apex.name_servers.0} Name=${aws_route53_zone.apex.name_servers.1} Name=${aws_route53_zone.apex.name_servers.2} Name=${aws_route53_zone.apex.name_servers.3} --profile ${local.profile}" } depends_on = [aws_route53_zone.apex] } diff --git a/docs/examples/vpc_setup/vpc.tf b/docs/examples/vpc_setup/vpc.tf index d42ae59..4723032 100644 --- a/docs/examples/vpc_setup/vpc.tf +++ b/docs/examples/vpc_setup/vpc.tf @@ -89,14 +89,14 @@ resource "aws_route_table" "main_private" { } resource "aws_route_table_association" "main_subnets_public" { - count = length(data.aws_subnet_ids.main_public.ids) - subnet_id = tolist(data.aws_subnet_ids.main_public.ids)[count.index] + count = length(data.aws_subnet_ids.main_public) > 0 ? length(data.aws_subnet_ids.main_public) : 0 + subnet_id = element(aws_subnet.main_public.*.id, count.index) route_table_id = aws_route_table.main_public.id } resource "aws_route_table_association" "main_subnets_private" { - count = length(data.aws_subnet_ids.main_private.ids) - subnet_id = tolist(data.aws_subnet_ids.main_private.ids)[count.index] + count = length(data.aws_subnet_ids.main_private) > 0 ? length(data.aws_subnet_ids.main_private) : 0 + subnet_id = element(aws_subnet.main_private.*.id, count.index) route_table_id = aws_route_table.main_private.id } From 5dd07b885ea93b7db30a9301ee47e73a4b62afc9 Mon Sep 17 00:00:00 2001 From: n p Date: Thu, 28 Apr 2022 14:04:28 +0200 Subject: [PATCH 2/8] feat(redirect): Refactors Lambda@Edge to CloudFront Function --- modules/cloudfront/distribution.tf | 6 +- .../function_rewrite/index.js.tftpl | 29 +++++++ .../lambda_redirect/index_html/index.js | 30 ------- modules/cloudfront/main.tf | 83 ++++--------------- modules/cloudfront/variables.tf | 8 ++ variables.tf | 8 ++ 6 files changed, 62 insertions(+), 102 deletions(-) create mode 100644 modules/cloudfront/function_rewrite/index.js.tftpl delete mode 100644 modules/cloudfront/lambda_redirect/index_html/index.js diff --git a/modules/cloudfront/distribution.tf b/modules/cloudfront/distribution.tf index d95cfad..4296f26 100644 --- a/modules/cloudfront/distribution.tf +++ b/modules/cloudfront/distribution.tf @@ -61,9 +61,9 @@ resource "aws_cloudfront_distribution" "wordpress_distribution" { } } - lambda_function_association { - event_type = "origin-request" - lambda_arn = "${aws_lambda_function.object_redirect.arn}:${aws_lambda_function.object_redirect.version}" + function_association { + event_type = "viewer-request" + function_arn = aws_cloudfront_function.object_rewrite.arn } viewer_protocol_policy = "redirect-to-https" diff --git a/modules/cloudfront/function_rewrite/index.js.tftpl b/modules/cloudfront/function_rewrite/index.js.tftpl new file mode 100644 index 0000000..5799fdc --- /dev/null +++ b/modules/cloudfront/function_rewrite/index.js.tftpl @@ -0,0 +1,29 @@ +function handler(event) { + var request = event.request; + var uri = request.uri; + + try { + %{ for match, destination in REDIRECTS } + if (/${match}/.test(uri)) { + return { + statusCode: 301, + statusDescription: 'Moved Permanently', + headers: { + 'location': { value: uri.replace(/${match}/, '${destination}') } + } + }; + } + %{ endfor ~} + + // Check whether the URI is missing a file name. + if (uri.endsWith('/')) { + request.uri += 'index.html'; + return request; + } + } + catch (e) { + console.log(e); + } + + return request; +} diff --git a/modules/cloudfront/lambda_redirect/index_html/index.js b/modules/cloudfront/lambda_redirect/index_html/index.js deleted file mode 100644 index 44b6d6a..0000000 --- a/modules/cloudfront/lambda_redirect/index_html/index.js +++ /dev/null @@ -1,30 +0,0 @@ -// Add index.html to any request URLs that end in / -// This allows "friendly" URLs in static websites, e.g. -// /about-us/ is converted to /about-us/index.html - -// https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/ - -'use strict'; -exports.handler = (event, context, callback) => { - // Extract the request from the CloudFront event that is sent to Lambda@Edge - var request = event.Records[0].cf.request; - - // Extract the URI from the request - var olduri = request.uri; - - // Match any '/' that occurs at the end of a URI. Replace it with a default index - // Match also any calls to 'index.php' which Wordpress would ordinarily look for - - var newuri = olduri.replace(/\/$/, '\/index.html'); - newuri = newuri.replace(/\/index.php$/, '\/index.html'); - - // For debugging: Log the URI as received by CloudFront and the new URI to be used to fetch from origin - // console.log("Old URI: " + olduri); - // console.log("New URI: " + newuri); - - // Replace the received URI with the URI that includes the index page - request.uri = newuri; - - // Return to CloudFront - return callback(null, request); -}; diff --git a/modules/cloudfront/main.tf b/modules/cloudfront/main.tf index 7659151..8ed5d55 100644 --- a/modules/cloudfront/main.tf +++ b/modules/cloudfront/main.tf @@ -1,76 +1,21 @@ -data "archive_file" "index_html" { - type = "zip" - source_dir = "${path.module}/lambda_redirect/index_html" - output_path = "${path.module}/lambda_redirect/dst/index_html.zip" -} - -#tfsec:ignore:AWS089 -resource "aws_cloudwatch_log_group" "object_redirect" { - name = "/aws/lambda/${var.site_name}_redirect_index_html" - retention_in_days = 7 -} - -#tfsec:ignore:AWS089 -resource "aws_cloudwatch_log_group" "object_redirect_ue1_local" { - name = "/aws/lambda/us-east-1.${var.site_name}_redirect_index_html" - retention_in_days = 7 -} - -# TODO: A solution to create/manage default log groups in all Edge Cache Regions #tfsec:ignore:AWS089 -resource "aws_cloudwatch_log_group" "object_redirect_ue1" { - name = "/aws/lambda/us-east-1.${var.site_name}_redirect_index_html" +resource "aws_cloudwatch_log_group" "object_rewrite" { + name = "/aws/cloudfront/function/${var.site_name}_rewrite" retention_in_days = 7 + # CloudFront Functions always creates log streams in us-east-1, + # no matter which edge location ran the function. + # The purpose of this resource is to set the retention days. provider = aws.ue1 } -resource "aws_lambda_function" "object_redirect" { - provider = aws.ue1 - filename = data.archive_file.index_html.output_path - function_name = "${var.site_name}_redirect_index_html" - role = aws_iam_role.lambda-edge.arn - handler = "index.handler" - source_code_hash = data.archive_file.index_html.output_base64sha256 - runtime = "nodejs12.x" - publish = true - memory_size = 128 - timeout = 3 - depends_on = [ - aws_cloudwatch_log_group.object_redirect, - aws_cloudwatch_log_group.object_redirect_ue1, - aws_cloudwatch_log_group.object_redirect_ue1_local - ] -} - -data "aws_iam_policy_document" "lambda-edge-service-role" { - statement { - actions = ["sts:AssumeRole"] - principals { - type = "Service" - identifiers = ["edgelambda.amazonaws.com", "lambda.amazonaws.com"] +resource "aws_cloudfront_function" "object_rewrite" { + name = "${var.site_name}_rewrite" + runtime = "cloudfront-js-1.0" + publish = true + code = templatefile( + "${path.module}/function_rewrite/index.js.tftpl", + { + REDIRECTS = var.cloudfront_function_redirects } - } -} - -resource "aws_iam_role" "lambda-edge" { - name = "${var.site_name}-lambda-edge-service-role" - assume_role_policy = data.aws_iam_policy_document.lambda-edge-service-role.json -} - -resource "aws_iam_role_policy_attachment" "basic" { - role = aws_iam_role.lambda-edge.name - policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" -} - -data "aws_iam_policy_document" "lambda-edge-cloudwatch-logs" { - statement { - actions = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"] - resources = ["arn:aws:logs:*:*:*"] - } -} - -resource "aws_iam_role_policy" "lambda-edge-cloudwatch-logs" { - name = "${var.site_name}-lambda-edge-cloudwatch-logs" - role = aws_iam_role.lambda-edge.name - policy = data.aws_iam_policy_document.lambda-edge-cloudwatch-logs.json + ) } diff --git a/modules/cloudfront/variables.tf b/modules/cloudfront/variables.tf index ad773fa..6b6bf9e 100644 --- a/modules/cloudfront/variables.tf +++ b/modules/cloudfront/variables.tf @@ -36,3 +36,11 @@ variable "waf_acl_arn" { default = null description = "The ARN of the WAF ACL applied to the CloudFront distribution." } + +variable "cloudfront_function_redirects" { + type = map + default = { + "^(.*)index\\.php$": "$1" + } + description = "A list of key value pairs of Regex match to destination for CloudFront to do 301 redirects." +} diff --git a/variables.tf b/variables.tf index 0c6acc6..e4355aa 100644 --- a/variables.tf +++ b/variables.tf @@ -104,6 +104,14 @@ variable "cloudfront_class" { default = "PriceClass_All" } +variable "cloudfront_function_redirects" { + type = map + default = { + "^(.*)index\\.php$": "$1" + } + description = "A list of key value pairs of Regex match to destination for CloudFront to do 301 redirects." +} + variable "hosted_zone_id" { type = string description = "The Route53 HostedZone ID to use to create records in." From f6e1d526bb6775815efc8fc8ef216f6f49313f04 Mon Sep 17 00:00:00 2001 From: n p Date: Thu, 28 Apr 2022 14:11:57 +0200 Subject: [PATCH 3/8] Better wording --- modules/cloudfront/main.tf | 3 +-- modules/cloudfront/variables.tf | 2 +- variables.tf | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/cloudfront/main.tf b/modules/cloudfront/main.tf index 8ed5d55..d893684 100644 --- a/modules/cloudfront/main.tf +++ b/modules/cloudfront/main.tf @@ -2,8 +2,7 @@ resource "aws_cloudwatch_log_group" "object_rewrite" { name = "/aws/cloudfront/function/${var.site_name}_rewrite" retention_in_days = 7 - # CloudFront Functions always creates log streams in us-east-1, - # no matter which edge location ran the function. + # CloudFront Functions always creates log streams in us-east-1, no matter which edge location ran the function. # The purpose of this resource is to set the retention days. provider = aws.ue1 } diff --git a/modules/cloudfront/variables.tf b/modules/cloudfront/variables.tf index 6b6bf9e..4385458 100644 --- a/modules/cloudfront/variables.tf +++ b/modules/cloudfront/variables.tf @@ -42,5 +42,5 @@ variable "cloudfront_function_redirects" { default = { "^(.*)index\\.php$": "$1" } - description = "A list of key value pairs of Regex match to destination for CloudFront to do 301 redirects." + description = "A list of key value pairs of Regex match and destination for 301 redirects at CloudFront." } diff --git a/variables.tf b/variables.tf index e4355aa..893ae88 100644 --- a/variables.tf +++ b/variables.tf @@ -109,7 +109,7 @@ variable "cloudfront_function_redirects" { default = { "^(.*)index\\.php$": "$1" } - description = "A list of key value pairs of Regex match to destination for CloudFront to do 301 redirects." + description = "A list of key value pairs of Regex match and destination for 301 redirects at CloudFront." } variable "hosted_zone_id" { From fc84b2af0b9a17c16f5d95687c5568f512478f8b Mon Sep 17 00:00:00 2001 From: n p Date: Thu, 28 Apr 2022 14:13:00 +0200 Subject: [PATCH 4/8] Explicit variable name --- modules/cloudfront/main.tf | 2 +- modules/cloudfront/variables.tf | 2 +- variables.tf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/cloudfront/main.tf b/modules/cloudfront/main.tf index d893684..a5a108a 100644 --- a/modules/cloudfront/main.tf +++ b/modules/cloudfront/main.tf @@ -14,7 +14,7 @@ resource "aws_cloudfront_function" "object_rewrite" { code = templatefile( "${path.module}/function_rewrite/index.js.tftpl", { - REDIRECTS = var.cloudfront_function_redirects + REDIRECTS = var.cloudfront_function_301_redirects } ) } diff --git a/modules/cloudfront/variables.tf b/modules/cloudfront/variables.tf index 4385458..0366e22 100644 --- a/modules/cloudfront/variables.tf +++ b/modules/cloudfront/variables.tf @@ -37,7 +37,7 @@ variable "waf_acl_arn" { description = "The ARN of the WAF ACL applied to the CloudFront distribution." } -variable "cloudfront_function_redirects" { +variable "cloudfront_function_301_redirects" { type = map default = { "^(.*)index\\.php$": "$1" diff --git a/variables.tf b/variables.tf index 893ae88..e42e1fd 100644 --- a/variables.tf +++ b/variables.tf @@ -104,7 +104,7 @@ variable "cloudfront_class" { default = "PriceClass_All" } -variable "cloudfront_function_redirects" { +variable "cloudfront_function_301_redirects" { type = map default = { "^(.*)index\\.php$": "$1" From 7b0e92b10011d13319a4a7b5b037881a2fc9a292 Mon Sep 17 00:00:00 2001 From: n p Date: Thu, 28 Apr 2022 14:20:38 +0200 Subject: [PATCH 5/8] Adds function for permanent redirect --- .../function_rewrite/index.js.tftpl | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/modules/cloudfront/function_rewrite/index.js.tftpl b/modules/cloudfront/function_rewrite/index.js.tftpl index 5799fdc..a2ddac8 100644 --- a/modules/cloudfront/function_rewrite/index.js.tftpl +++ b/modules/cloudfront/function_rewrite/index.js.tftpl @@ -3,15 +3,9 @@ function handler(event) { var uri = request.uri; try { - %{ for match, destination in REDIRECTS } + %{ for match, target in REDIRECTS } if (/${match}/.test(uri)) { - return { - statusCode: 301, - statusDescription: 'Moved Permanently', - headers: { - 'location': { value: uri.replace(/${match}/, '${destination}') } - } - }; + return permanentRedirect(/${match}/, '${target}'); } %{ endfor ~} @@ -27,3 +21,13 @@ function handler(event) { return request; } + +function permanentRedirect(match, target) { + return { + statusCode: 301, + statusDescription: 'Moved Permanently', + headers: { + 'location': { value: uri.replace(match, target) } + } + }; +} From 0dc9314984566d381b08ce5d6ce96890c8458456 Mon Sep 17 00:00:00 2001 From: n p Date: Thu, 28 Apr 2022 14:35:10 +0200 Subject: [PATCH 6/8] Adds note one why log is being used for errors --- modules/cloudfront/function_rewrite/index.js.tftpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/cloudfront/function_rewrite/index.js.tftpl b/modules/cloudfront/function_rewrite/index.js.tftpl index a2ddac8..c466b1e 100644 --- a/modules/cloudfront/function_rewrite/index.js.tftpl +++ b/modules/cloudfront/function_rewrite/index.js.tftpl @@ -2,7 +2,7 @@ function handler(event) { var request = event.request; var uri = request.uri; - try { + try { %{ for match, target in REDIRECTS } if (/${match}/.test(uri)) { return permanentRedirect(/${match}/, '${target}'); @@ -16,6 +16,7 @@ function handler(event) { } } catch (e) { + // console.error is not supported console.log(e); } From 3e989c4863cdc0ca6beb8782e0be2ad8a77a316b Mon Sep 17 00:00:00 2001 From: n p Date: Thu, 28 Apr 2022 15:50:44 +0200 Subject: [PATCH 7/8] Adds dependency of rewrite function to log_group --- modules/cloudfront/main.tf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/cloudfront/main.tf b/modules/cloudfront/main.tf index a5a108a..5465752 100644 --- a/modules/cloudfront/main.tf +++ b/modules/cloudfront/main.tf @@ -8,6 +8,10 @@ resource "aws_cloudwatch_log_group" "object_rewrite" { } resource "aws_cloudfront_function" "object_rewrite" { + depends_on = [ + aws_cloudwatch_log_group.object_rewrite + ] + name = "${var.site_name}_rewrite" runtime = "cloudfront-js-1.0" publish = true From 2ff73f9c94b72a0e9edce842446bbb768da86289 Mon Sep 17 00:00:00 2001 From: n p Date: Thu, 28 Apr 2022 15:57:46 +0200 Subject: [PATCH 8/8] Revert "Merge remote-tracking branch 'origin/master' into cf-function" This reverts commit 9f99c3d91dc98b54c52a273f32e7f8082f49971b, reversing changes made to 0dc9314984566d381b08ce5d6ce96890c8458456. --- docs/examples/main.tf | 10 +++++----- docs/examples/vpc_setup/vpc.tf | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/examples/main.tf b/docs/examples/main.tf index b5d96b6..c5375db 100644 --- a/docs/examples/main.tf +++ b/docs/examples/main.tf @@ -14,15 +14,15 @@ module "peterdotcloud_vpc" { module "peterdotcloud_website" { source = "TechToSpeech/serverless-static-wordpress/aws" version = "0.1.2" - main_vpc_id = module.peterdotcloud_vpc.main_vpc_id - subnet_ids = tolist(module.peterdotcloud_vpc.subnet_ids) + main_vpc_id = "vpc-e121c09b" + subnet_ids = ["subnet-04b97235", "subnet-08fb235", "subnet-04b97734"] aws_account_id = data.aws_caller_identity.current.account_id # site_name will be used to prepend resource names - use no spaces or special characters site_name = local.site_name site_domain = local.site_domain wordpress_subdomain = "wordpress" - hosted_zone_id = aws_route53_zone.apex.id + hosted_zone_id = "Z00437553UWAVIRHANGCN" s3_region = local.aws_region slack_webhook = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" ecs_cpu = 1024 @@ -47,7 +47,7 @@ module "docker_pullpush" { aws_account_id = data.aws_caller_identity.current.account_id aws_region = local.aws_region docker_source = "wordpress:php7.4-apache" - aws_profile = local.profile + aws_profile = "peterdotcloud" ecr_repo_name = module.peterdotcloud_website.wordpress_ecr_repository ecr_repo_tag = "base" depends_on = [module.peterdotcloud_website] @@ -80,7 +80,7 @@ resource "null_resource" "update_nameservers" { nameservers = aws_route53_zone.apex.id } provisioner "local-exec" { - command = "aws route53domains update-domain-nameservers --region us-east-1 --domain-name ${local.site_domain} --nameservers Name=${aws_route53_zone.apex.name_servers.0} Name=${aws_route53_zone.apex.name_servers.1} Name=${aws_route53_zone.apex.name_servers.2} Name=${aws_route53_zone.apex.name_servers.3} --profile ${local.profile}" + command = "aws route53domains update-domain-nameservers --region us-east-1 --domain-name ${local.site_domain} --nameservers Name=${aws_route53_zone.apex.name_servers.0} Name=${aws_route53_zone.apex.name_servers.1} Name=${aws_route53_zone.apex.name_servers.2} Name=${aws_route53_zone.apex.name_servers.3} --profile peterdotcloud" } depends_on = [aws_route53_zone.apex] } diff --git a/docs/examples/vpc_setup/vpc.tf b/docs/examples/vpc_setup/vpc.tf index 4723032..d42ae59 100644 --- a/docs/examples/vpc_setup/vpc.tf +++ b/docs/examples/vpc_setup/vpc.tf @@ -89,14 +89,14 @@ resource "aws_route_table" "main_private" { } resource "aws_route_table_association" "main_subnets_public" { - count = length(data.aws_subnet_ids.main_public) > 0 ? length(data.aws_subnet_ids.main_public) : 0 - subnet_id = element(aws_subnet.main_public.*.id, count.index) + count = length(data.aws_subnet_ids.main_public.ids) + subnet_id = tolist(data.aws_subnet_ids.main_public.ids)[count.index] route_table_id = aws_route_table.main_public.id } resource "aws_route_table_association" "main_subnets_private" { - count = length(data.aws_subnet_ids.main_private) > 0 ? length(data.aws_subnet_ids.main_private) : 0 - subnet_id = element(aws_subnet.main_private.*.id, count.index) + count = length(data.aws_subnet_ids.main_private.ids) + subnet_id = tolist(data.aws_subnet_ids.main_private.ids)[count.index] route_table_id = aws_route_table.main_private.id }