From d2c46ca32877a2bc51f9c4baf91d5d83ba8a508d Mon Sep 17 00:00:00 2001 From: Thomas Judd-Cooper Date: Mon, 3 Jul 2023 15:39:03 +0100 Subject: [PATCH] Pass through parameters to root module --- Makefile | 4 +- example/terraform/main.tf | 18 +- main.tf | 418 ++++++++++++++---- modules/cloudfront-logs/main.tf | 2 +- modules/cloudfront-logs/s3__logs.tf | 2 +- modules/opennext-assets/kms.tf | 12 +- modules/opennext-assets/outputs.tf | 4 +- modules/opennext-assets/s3.tf | 14 +- modules/opennext-assets/variables.tf | 12 +- modules/opennext-cloudfront/cloudfront.tf | 44 +- modules/opennext-cloudfront/outputs.tf | 4 +- modules/opennext-cloudfront/variables.tf | 12 +- modules/opennext-lambda/data.tf | 7 +- modules/opennext-lambda/eventbridge.tf | 8 +- modules/opennext-lambda/lambda.tf | 14 +- modules/opennext-lambda/main.tf | 2 +- modules/opennext-lambda/variables.tf | 143 +++--- modules/opennext-revalidation-queue/kms.tf | 12 +- .../opennext-revalidation-queue/outputs.tf | 4 +- .../opennext-revalidation-queue/variables.tf | 8 +- outputs.tf | 27 ++ route53.tf | 4 +- variables.tf | 355 +++++++++++++-- 23 files changed, 883 insertions(+), 247 deletions(-) create mode 100644 outputs.tf diff --git a/Makefile b/Makefile index e3c9ca3..94d9e45 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ include scripts/makefile/Makefile.init ############### BUILD_FOLDER = build REQUIRED_BUILD_DEPENDENCIES = yarn -REQUIRED_RUNTIME_DEPENDENCIES = node +REQUIRED_RUNTIME_DEPENDENCIES = node terraform ##################### ## Install Targets ## @@ -23,7 +23,7 @@ check: check-runtime-deps check-build-deps # Checks if runtime and build require check-runtime-deps: $(foreach exec,${REQUIRED_RUNTIME_DEPENDENCIES},\ - $(if $(shell which ${exec}),@echo -e "${exec} is installed",$(error "No ${exec} in PATH"))) + $(if $(shell which ${exec}),@echo -e "${exec} is installed\n",$(error "No ${exec} in PATH"))) check-build-deps: $(foreach exec,${REQUIRED_BUILD_DEPENDENCIES},\ diff --git a/example/terraform/main.tf b/example/terraform/main.tf index 0014e73..7912e50 100644 --- a/example/terraform/main.tf +++ b/example/terraform/main.tf @@ -1,4 +1,5 @@ terraform { + required_version = "~> 1.5" required_providers { aws = { source = "hashicorp/aws" @@ -25,9 +26,16 @@ module "opennext" { source = "../../" prefix = "opennext-example" - aliases = [local.domain_name] - acm_certificate_arn = aws_acm_certificate_validation.ssl_certificate.certificate_arn - hosted_zone_id = data.aws_route53_zone.zone.zone_id opennext_build_path = "../.open-next" - assets_paths = ["/images/*"] -} \ No newline at end of file + hosted_zone_id = data.aws_route53_zone.zone.zone_id + + cloudfront = { + aliases = [local.domain_name] + acm_certificate_arn = aws_acm_certificate_validation.ssl_certificate.certificate_arn + assets_paths = ["/images/*"] + } +} + +output "cloudfront_distribution_id" { + value = module.opennext.cloudfront.cloudfront_distribution.id +} diff --git a/main.tf b/main.tf index 4e684cb..0b49e69 100644 --- a/main.tf +++ b/main.tf @@ -20,106 +20,344 @@ locals { data "aws_caller_identity" "current" {} +/** + * Assets & Cache S3 Bucket + **/ +module "assets" { + source = "./modules/opennext-assets" + + aws_account_id = data.aws_caller_identity.current.account_id + prefix = "${var.prefix}-assets" + assets_path = "${local.opennext_abs_path}/assets" + cache_path = "${local.opennext_abs_path}/cache" + server_function_role_arn = module.server_function.lambda_role.arn +} + + +/** + * Next.js Server Function + **/ +locals { + server_options = { + package = { + source_dir = try(var.server_options.package.source_dir, "${local.opennext_abs_path}/server-function/") + output_dir = try(var.server_options.package.output_dir, "/tmp/") + } + + lambda = { + function_name = try(var.server_options.lambda.function_name, null) + description = try(var.server_options.lambda.description, "Next.js Server") + handler = try(var.server_options.lambda.handler, "index.handler") + runtime = try(var.server_options.lambda.runtime, "nodejs18.x") + architectures = try(var.server_options.lambda.architectures, ["arm64"]) + memory_size = try(var.server_options.lambda.memory_size, 1024) + timeout = try(var.server_options.lambda.timeout, 30) + publish = try(var.server_options.lambda.publish, true) + dead_letter_config = try(var.server_options.lambda.dead_letter_config, null) + reserved_concurrent_executions = try(var.server_options.lambda.reserved_concurrent_executions, 10) + code_signing_config = try(var.server_options.lambda.code_signing_config, null) + } + + networking = { + vpc_id = try(var.server_options.networking.vpc_id, null) + subnet_ids = try(var.server_options.networking.subnet_ids, []) + security_group_ingress_rules = try(var.server_options.networking.sg_ingress_rules, []) + security_group_egress_rules = try(var.server_options.networking.sg_egress_rules, []) + } + + environment_variables = merge({ + CACHE_BUCKET_NAME = module.assets.assets_bucket.bucket + CACHE_BUCKET_KEY_PREFIX = "cache" + CACHE_BUCKET_REGION = "eu-west-2" + REVALIDATION_QUEUE_URL = module.revalidation_queue.queue.url + REVALIDATION_QUEUE_REGION = "eu-west-2" + }, try(var.server_options.environment_variables, {})) + + iam_policy_statements = concat([ + { + effect = "Allow" + actions = ["s3:GetObject", "s3:PutObject", "s3:ListObjects"] + resources = [module.assets.assets_bucket.arn, "${module.assets.assets_bucket.arn}/*"] + }, + { + effect = "Allow" + actions = ["sqs:SendMessage"] + resources = [module.revalidation_queue.queue.arn] + } + ], var.server_options.iam_policy != null ? var.server_options.iam_policy : []) + } +} + module "server_function" { source = "./modules/opennext-lambda" - prefix = "${var.prefix}-nextjs-server" - description = "Next.js Server" - publish = true - source_dir = "${local.opennext_abs_path}/server-function/" - - environment_variables = { - CACHE_BUCKET_NAME = module.assets.assets_bucket.bucket - CACHE_BUCKET_KEY_PREFIX = "cache" - CACHE_BUCKET_REGION = "eu-west-2" - REVALIDATION_QUEUE_URL = module.revalidation_queue.queue.url - REVALIDATION_QUEUE_REGION = "eu-west-2" - } + prefix = "${var.prefix}-nextjs-server" + + function_name = local.server_options.lambda.function_name + description = local.server_options.lambda.description + handler = local.server_options.lambda.handler + runtime = local.server_options.lambda.runtime + architectures = local.server_options.lambda.architectures + memory_size = local.server_options.lambda.memory_size + timeout = local.server_options.lambda.timeout + publish = local.server_options.lambda.publish + dead_letter_config = local.server_options.lambda.dead_letter_config + reserved_concurrent_executions = local.server_options.lambda.reserved_concurrent_executions + code_signing_config = local.server_options.lambda.code_signing_config + + source_dir = local.server_options.package.source_dir + output_dir = local.server_options.package.output_dir - iam_policy_statements = [ - { - effect = "Allow" - actions = ["s3:GetObject", "s3:PutObject", "s3:ListObjects"] - resources = [module.assets.assets_bucket.arn, "${module.assets.assets_bucket.arn}/*"] - }, - { - effect = "Allow" - actions = ["sqs:SendMessage"] - resources = [module.revalidation_queue.queue.arn] + vpc_id = local.server_options.networking.vpc_id + subnet_ids = local.server_options.networking.subnet_ids + security_group_ingress_rules = local.server_options.networking.security_group_ingress_rules + security_group_egress_rules = local.server_options.networking.security_group_egress_rules + + environment_variables = local.server_options.environment_variables + iam_policy_statements = local.server_options.iam_policy_statements +} + + +/** + * Image Optimization Function + **/ +locals { + image_optimization_options = { + package = { + source_dir = try(var.image_optimization_options.source_dir, "${local.opennext_abs_path}/image-optimization-function/") + output_dir = try(var.image_optimization_options.output_dir, "/tmp/") } - ] + + lambda = { + function_name = try(var.image_optimization_options.lambda.function_name, null) + description = try(var.image_optimization_options.lambda.description, "Next.js Image Optimization") + handler = try(var.image_optimization_options.lambda.handler, "index.handler") + runtime = try(var.image_optimization_options.lambda.runtime, "nodejs18.x") + architectures = try(var.image_optimization_options.lambda.architectures, ["arm64"]) + memory_size = try(var.image_optimization_options.lambda.memory_size, 512) + timeout = try(var.image_optimization_options.lambda.timeout, 30) + publish = try(var.image_optimization_options.lambda.publish, false) + dead_letter_config = try(var.image_optimization_options.lambda.dead_letter_config, null) + reserved_concurrent_executions = try(var.image_optimization_options.lambda.reserved_concurrent_executions, 3) + code_signing_config = try(var.image_optimization_options.lambda.code_signing_config, null) + + } + + networking = { + vpc_id = try(var.image_optimization_options.networking.vpc_id, null) + subnet_ids = try(var.image_optimization_options.networking.subnet_ids, []) + security_group_ingress_rules = try(var.image_optimization_options.networking.sg_ingress_rules, []) + security_group_egress_rules = try(var.image_optimization_options.networking.sg_egress_rules, []) + } + + environment_variables = merge({ + BUCKET_NAME = module.assets.assets_bucket.bucket, + BUCKET_KEY_PREFIX = "assets" + }, try(var.image_optimization_options.environment_variables, {})) + + iam_policy_statements = concat([ + { + effect = "Allow" + actions = ["s3:GetObject"] + resources = [module.assets.assets_bucket.arn, "${module.assets.assets_bucket.arn}/*"] + } + ], var.image_optimization_options.iam_policy != null ? var.image_optimization_options.iam_policy : []) + } } module "image_optimization_function" { source = "./modules/opennext-lambda" - prefix = "${var.prefix}-nextjs-image-optimization" - description = "Next.js Image Optimization" - memory_size = 512 - source_dir = "${local.opennext_abs_path}/image-optimization-function/" + prefix = "${var.prefix}-nextjs-image-optimization" - environment_variables = { - BUCKET_NAME = module.assets.assets_bucket.bucket, - BUCKET_KEY_PREFIX = "assets" - } + function_name = local.image_optimization_options.lambda.function_name + description = local.image_optimization_options.lambda.description + handler = local.image_optimization_options.lambda.handler + runtime = local.image_optimization_options.lambda.runtime + architectures = local.image_optimization_options.lambda.architectures + memory_size = local.image_optimization_options.lambda.memory_size + timeout = local.image_optimization_options.lambda.timeout + publish = local.image_optimization_options.lambda.publish + dead_letter_config = local.image_optimization_options.lambda.dead_letter_config + reserved_concurrent_executions = local.image_optimization_options.lambda.reserved_concurrent_executions + code_signing_config = local.image_optimization_options.lambda.code_signing_config + + source_dir = local.image_optimization_options.package.source_dir + output_dir = local.image_optimization_options.package.output_dir + + vpc_id = local.image_optimization_options.networking.vpc_id + subnet_ids = local.image_optimization_options.networking.subnet_ids + security_group_ingress_rules = local.image_optimization_options.networking.security_group_ingress_rules + security_group_egress_rules = local.image_optimization_options.networking.security_group_egress_rules - iam_policy_statements = [{ - effect = "Allow" - actions = ["s3:GetObject"] - resources = [module.assets.assets_bucket.arn, "${module.assets.assets_bucket.arn}/*"] - }] + environment_variables = local.image_optimization_options.environment_variables + iam_policy_statements = local.image_optimization_options.iam_policy_statements +} + +/** + * ISR Revalidation Function + **/ +locals { + revalidation_options = { + package = { + source_dir = try(var.revalidation_options.source_dir, "${local.opennext_abs_path}/revalidation-function/") + output_dir = try(var.revalidation_options.output_dir, "/tmp/") + } + + lambda = { + function_name = try(var.revalidation_options.lambda.function_name, null) + description = try(var.revalidation_options.lambda.description, "Next.js ISR Revalidation Function") + handler = try(var.revalidation_options.lambda.handler, "index.handler") + runtime = try(var.revalidation_options.lambda.runtime, "nodejs18.x") + architectures = try(var.revalidation_options.lambda.architectures, ["arm64"]) + memory_size = try(var.revalidation_options.lambda.memory_size, 128) + timeout = try(var.revalidation_options.lambda.timeout, 30) + publish = try(var.revalidation_options.lambda.publish, false) + dead_letter_config = try(var.revalidation_options.lambda.dead_letter_config, null) + reserved_concurrent_executions = try(var.revalidation_options.lambda.reserved_concurrent_executions, 3) + code_signing_config = try(var.revalidation_options.lambda.code_signing_config, null) + + } + + networking = { + vpc_id = try(var.revalidation_options.networking.vpc_id, null) + subnet_ids = try(var.revalidation_options.networking.subnet_ids, []) + security_group_ingress_rules = try(var.revalidation_options.networking.sg_ingress_rules, []) + security_group_egress_rules = try(var.revalidation_options.networking.sg_egress_rules, []) + } + + environment_variables = try(var.revalidation_options.environment_variables, {}) + + iam_policy_statements = concat([ + { + effect = "Allow" + actions = ["sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes"] + resources = [module.revalidation_queue.queue.arn] + } + ], var.revalidation_options.iam_policy != null ? var.revalidation_options.iam_policy : []) + } } module "revalidation_function" { source = "./modules/opennext-lambda" - prefix = "${var.prefix}-nextjs-revalidation-function" - description = "Next.js ISR Revalidation Function" - source_dir = "${local.opennext_abs_path}/image-optimization-function/" + prefix = "${var.prefix}-nextjs-revalidation" - memory_size = 128 + function_name = local.revalidation_options.lambda.function_name + description = local.revalidation_options.lambda.description + handler = local.revalidation_options.lambda.handler + runtime = local.revalidation_options.lambda.runtime + architectures = local.revalidation_options.lambda.architectures + memory_size = local.revalidation_options.lambda.memory_size + timeout = local.revalidation_options.lambda.timeout + publish = local.revalidation_options.lambda.publish + dead_letter_config = local.revalidation_options.lambda.dead_letter_config + reserved_concurrent_executions = local.revalidation_options.lambda.reserved_concurrent_executions + code_signing_config = local.revalidation_options.lambda.code_signing_config - iam_policy_statements = [ - { - effect = "Allow" - actions = ["sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes"] - resources = [module.revalidation_queue.queue.arn] - } - ] + source_dir = local.revalidation_options.package.source_dir + output_dir = local.revalidation_options.package.output_dir + + vpc_id = local.revalidation_options.networking.vpc_id + subnet_ids = local.revalidation_options.networking.subnet_ids + security_group_ingress_rules = local.revalidation_options.networking.security_group_ingress_rules + security_group_egress_rules = local.revalidation_options.networking.security_group_egress_rules + + environment_variables = local.revalidation_options.environment_variables + iam_policy_statements = local.revalidation_options.iam_policy_statements } +/** + * ISR Revalidation Queue + **/ +module "revalidation_queue" { + source = "./modules/opennext-revalidation-queue" + prefix = "${var.prefix}-revalidation-queue" + + aws_account_id = data.aws_caller_identity.current.account_id + revalidation_function_arn = module.revalidation_function.lambda_function.arn +} + +/** + * Warmer Function + **/ +locals { + warmer_options = { + package = { + source_dir = try(var.warmer_options.source_dir, "${local.opennext_abs_path}/warmer-function/") + output_dir = try(var.warmer_options.output_dir, "/tmp/") + } + + lambda = { + function_name = try(var.warmer_options.lambda.function_name, null) + description = try(var.warmer_options.lambda.description, "Next.js Warmer Function") + handler = try(var.warmer_options.lambda.handler, "index.handler") + runtime = try(var.warmer_options.lambda.runtime, "nodejs18.x") + architectures = try(var.warmer_options.lambda.architectures, ["arm64"]) + memory_size = try(var.warmer_options.lambda.memory_size, 128) + timeout = try(var.warmer_options.lambda.timeout, 30) + publish = try(var.warmer_options.lambda.publish, false) + dead_letter_config = try(var.warmer_options.lambda.dead_letter_config, null) + reserved_concurrent_executions = try(var.warmer_options.lambda.reserved_concurrent_executions, 3) + code_signing_config = try(var.warmer_options.lambda.code_signing_config, null) + + } + + networking = { + vpc_id = try(var.warmer_options.networking.vpc_id, null) + subnet_ids = try(var.warmer_options.networking.subnet_ids, []) + security_group_ingress_rules = try(var.warmer_options.networking.sg_ingress_rules, []) + security_group_egress_rules = try(var.warmer_options.networking.sg_egress_rules, []) + } + + environment_variables = merge({ + FUNCTION_NAME = module.server_function.lambda_function.function_name, + CONCURRENCY = 1 + }, try(var.warmer_options.environment_variables, {})) + + iam_policy_statements = concat([ + { + effect = "Allow" + actions = ["lambda:InvokeFunction"] + resources = [module.server_function.lambda_function.arn] + } + ], var.warmer_options.iam_policy != null ? var.warmer_options.iam_policy : []) + } +} module "warmer_function" { source = "./modules/opennext-lambda" - create_eventbridge_scheduled_rule = true prefix = "${var.prefix}-nextjs-warmer" - description = "Next.js Warmer" - memory_size = 128 - source_dir = "${local.opennext_abs_path}/warmer-function/" + create_eventbridge_scheduled_rule = true - environment_variables = { - FUNCTION_NAME = module.server_function.lambda_function.function_name, - CONCURRENCY = 1 - } - iam_policy_statements = [{ - effect = "Allow" - actions = ["lambda:InvokeFunction"] - resources = [module.server_function.lambda_function.arn] - }] -} + function_name = local.warmer_options.lambda.function_name + description = local.warmer_options.lambda.description + handler = local.warmer_options.lambda.handler + runtime = local.warmer_options.lambda.runtime + architectures = local.warmer_options.lambda.architectures + memory_size = local.warmer_options.lambda.memory_size + timeout = local.warmer_options.lambda.timeout + publish = local.warmer_options.lambda.publish + dead_letter_config = local.warmer_options.lambda.dead_letter_config + reserved_concurrent_executions = local.warmer_options.lambda.reserved_concurrent_executions + code_signing_config = local.warmer_options.lambda.code_signing_config -module "assets" { - source = "./modules/opennext-assets" + source_dir = local.warmer_options.package.source_dir + output_dir = local.warmer_options.package.output_dir - aws_account_id = data.aws_caller_identity.current.account_id - prefix = "${var.prefix}-assets" - assets_path = "${local.opennext_abs_path}/assets" - cache_path = "${local.opennext_abs_path}/cache" - server_function_role_arn = module.server_function.lambda_role.arn -} + vpc_id = local.warmer_options.networking.vpc_id + subnet_ids = local.warmer_options.networking.subnet_ids + security_group_ingress_rules = local.warmer_options.networking.security_group_ingress_rules + security_group_egress_rules = local.warmer_options.networking.security_group_egress_rules + environment_variables = local.warmer_options.environment_variables + iam_policy_statements = local.warmer_options.iam_policy_statements +} +/** + * CloudFront -> CloudWatch Logs + **/ module "cloudfront_logs" { source = "./modules/cloudfront-logs" @@ -128,25 +366,49 @@ module "cloudfront_logs" { retention = 365 } +/** + * Next.js CloudFront Distribution + **/ +locals { + cloudfront = { + aliases = var.cloudfront.aliases + acm_certificate_arn = var.cloudfront.acm_certificate_arn + assets_paths = coalesce(var.cloudfront.assets_paths, []) + custom_headers = coalesce(var.cloudfront.custom_headers, []) + cors = coalesce(var.cloudfront.cors, { + allow_credentials = false, + allow_headers = ["*"], + allow_methods = ["ALL"], + allow_origins = ["*"], + origin_override = true + }) + hsts = coalesce(var.cloudfront.hsts, { + access_control_max_age_sec = 31536000 + include_subdomains = true + override = true + preload = true + }) + waf_logging_configuration = var.cloudfront.waf_logging_configuration + } +} + module "cloudfront" { source = "./modules/opennext-cloudfront" prefix = "${var.prefix}-cloudfront" - aliases = var.aliases logging_bucket_domain_name = module.cloudfront_logs.logs_s3_bucket.bucket_regional_domain_name assets_origin_access_identity = module.assets.cloudfront_origin_access_identity.cloudfront_access_identity_path - acm_certificate_arn = var.acm_certificate_arn origins = { assets_bucket = module.assets.assets_bucket.bucket_regional_domain_name server_function = "${module.server_function.lambda_function_url.url_id}.lambda-url.eu-west-2.on.aws" image_optimization_function = "${module.image_optimization_function.lambda_function_url.url_id}.lambda-url.eu-west-2.on.aws" } -} -module "revalidation_queue" { - source = "./modules/opennext-revalidation-queue" - prefix = "${var.prefix}-revalidation-queue" - - aws_account_id = data.aws_caller_identity.current.account_id - revalidation_function_arn = module.revalidation_function.lambda_function.arn + aliases = local.cloudfront.aliases + acm_certificate_arn = local.cloudfront.acm_certificate_arn + assets_paths = local.cloudfront.assets_paths + custom_headers = local.cloudfront.custom_headers + cors = local.cloudfront.cors + hsts = local.cloudfront.hsts + waf_logging_configuration = local.cloudfront.waf_logging_configuration } diff --git a/modules/cloudfront-logs/main.tf b/modules/cloudfront-logs/main.tf index f29a32f..8cc753f 100644 --- a/modules/cloudfront-logs/main.tf +++ b/modules/cloudfront-logs/main.tf @@ -8,7 +8,7 @@ terraform { } archive = { - source = "hashicorp/archive" + source = "hashicorp/archive" version = "~> 2.4.0" } } diff --git a/modules/cloudfront-logs/s3__logs.tf b/modules/cloudfront-logs/s3__logs.tf index 36696a0..0e697f5 100644 --- a/modules/cloudfront-logs/s3__logs.tf +++ b/modules/cloudfront-logs/s3__logs.tf @@ -111,7 +111,7 @@ resource "aws_s3_bucket_replication_configuration" "logs" { depends_on = [aws_s3_bucket_versioning.logs] bucket = aws_s3_bucket.logs.bucket - role = var.log_bucket_replication_configuration.role + role = var.log_bucket_replication_configuration.role dynamic "rule" { for_each = toset(var.log_bucket_replication_configuration.rules) diff --git a/modules/opennext-assets/kms.tf b/modules/opennext-assets/kms.tf index 802a709..98136a8 100644 --- a/modules/opennext-assets/kms.tf +++ b/modules/opennext-assets/kms.tf @@ -1,15 +1,15 @@ data "aws_kms_key" "assets_key" { - count = var.kms_key_arn != null ? 1 : 0 - key_id = var.kms_key_arn + count = var.kms_key_arn != null ? 1 : 0 + key_id = var.kms_key_arn } resource "aws_kms_key" "assets_key" { - count = var.kms_key_arn == null ? 1 : 0 + count = var.kms_key_arn == null ? 1 : 0 - description = "${var.prefix} Assets S3 Bucket KMS Key" - deletion_window_in_days = 10 + description = "${var.prefix} Assets S3 Bucket KMS Key" + deletion_window_in_days = 10 - policy = data.aws_iam_policy_document.assets_key_policy[0].json + policy = data.aws_iam_policy_document.assets_key_policy[0].json } data "aws_iam_policy_document" "assets_key_policy" { diff --git a/modules/opennext-assets/outputs.tf b/modules/opennext-assets/outputs.tf index e8b0700..6b3cc90 100644 --- a/modules/opennext-assets/outputs.tf +++ b/modules/opennext-assets/outputs.tf @@ -1,7 +1,7 @@ output "cloudfront_origin_access_identity" { - value = aws_cloudfront_origin_access_identity.assets + value = aws_cloudfront_origin_access_identity.assets } output "assets_bucket" { - value = aws_s3_bucket.assets + value = aws_s3_bucket.assets } diff --git a/modules/opennext-assets/s3.tf b/modules/opennext-assets/s3.tf index 92ca5d0..9fc3dbb 100644 --- a/modules/opennext-assets/s3.tf +++ b/modules/opennext-assets/s3.tf @@ -59,7 +59,7 @@ resource "aws_s3_bucket_replication_configuration" "logs" { depends_on = [aws_s3_bucket_versioning.assets] bucket = aws_s3_bucket.assets.bucket - role = var.replication_configuration.role + role = var.replication_configuration.role dynamic "rule" { for_each = toset(var.replication_configuration.rules) @@ -171,12 +171,12 @@ data "aws_iam_policy_document" "read_assets_bucket" { resource "aws_s3_object" "assets" { for_each = fileset(var.assets_path, "**") - bucket = aws_s3_bucket.assets.bucket - key = "assets/${each.value}" - source = "${var.assets_path}/${each.value}" - etag = filemd5("${var.assets_path}/${each.value}") + bucket = aws_s3_bucket.assets.bucket + key = "assets/${each.value}" + source = "${var.assets_path}/${each.value}" + source_hash = filemd5("${var.assets_path}/${each.value}") cache_control = length(regexall(".*(_next).*$", each.value)) > 0 ? "public,max-age=31536000,immutable" : "public,max-age=0,s-maxage=31536000,must-revalidate" - content_type = lookup(local.content_type_lookup, split(".", each.value)[length(split(".", each.value)) - 1], "text/plain") + content_type = lookup(local.content_type_lookup, split(".", each.value)[length(split(".", each.value)) - 1], "text/plain") } # Cached Files @@ -186,6 +186,6 @@ resource "aws_s3_object" "cache" { bucket = aws_s3_bucket.assets.bucket key = "cache/${each.value}" source = "${var.cache_path}/${each.value}" - etag = filemd5("${var.cache_path}/${each.value}") + source_hash = filemd5("${var.cache_path}/${each.value}") content_type = lookup(local.content_type_lookup, split(".", each.value)[length(split(".", each.value)) - 1], "text/plain") } diff --git a/modules/opennext-assets/variables.tf b/modules/opennext-assets/variables.tf index e181580..bd84e20 100644 --- a/modules/opennext-assets/variables.tf +++ b/modules/opennext-assets/variables.tf @@ -4,18 +4,18 @@ variable "prefix" { } variable "assets_path" { - type = string - description = "The path of the open-next static assets" + type = string + description = "The path of the open-next static assets" } variable "cache_path" { - type = string - description = "The path of the open-next cache" + type = string + description = "The path of the open-next cache" } variable "server_function_role_arn" { - type = string - description = "The IAM role ARN of the Next.js server lambda function" + type = string + description = "The IAM role ARN of the Next.js server lambda function" } variable "logging_config" { diff --git a/modules/opennext-cloudfront/cloudfront.tf b/modules/opennext-cloudfront/cloudfront.tf index 53bd0d5..c91834e 100644 --- a/modules/opennext-cloudfront/cloudfront.tf +++ b/modules/opennext-cloudfront/cloudfront.tf @@ -1,6 +1,6 @@ locals { - server_origin_id = "${var.prefix}-server-origin" - assets_origin_id = "${var.prefix}-assets-origin" + server_origin_id = "${var.prefix}-server-origin" + assets_origin_id = "${var.prefix}-assets-origin" image_optimization_origin_id = "${var.prefix}-image-optimization-origin" } @@ -73,38 +73,42 @@ resource "aws_cloudfront_response_headers_policy" "response_headers_policy" { } } - custom_headers_config { - dynamic "items" { - for_each = toset(var.custom_headers) + dynamic "custom_headers_config" { + for_each = length(var.custom_headers) > 0 ? [true] : [] - content { - header = items.header - override = items.override - value = items.value + content { + dynamic "items" { + for_each = toset(var.custom_headers) + + content { + header = items.header + override = items.override + value = items.value + } } } } } provider "aws" { - alias = "global" + alias = "global" region = "us-east-1" } resource "aws_cloudfront_distribution" "distribution" { - provider = aws.global - price_class = "PriceClass_100" - enabled = true - is_ipv6_enabled = true - comment = "${var.prefix} - CloudFront Distribution for Next.js Application" - aliases = var.aliases - web_acl_id = aws_wafv2_web_acl.cloudfront_waf.arn + provider = aws.global + price_class = "PriceClass_100" + enabled = true + is_ipv6_enabled = true + comment = "${var.prefix} - CloudFront Distribution for Next.js Application" + aliases = var.aliases + web_acl_id = aws_wafv2_web_acl.cloudfront_waf.arn logging_config { include_cookies = false # bucket = module.cloudfront_logs.logs_s3_bucket.bucket_regional_domain_name bucket = var.logging_bucket_domain_name - prefix = one(var.aliases) + prefix = one(var.aliases) } viewer_certificate { @@ -136,7 +140,7 @@ resource "aws_cloudfront_distribution" "distribution" { origin { domain_name = var.origins.server_function # domain_name = "${module.server_function.lambda_function_url_id}.lambda-url.eu-west-2.on.aws" - origin_id = local.server_origin_id + origin_id = local.server_origin_id custom_origin_config { http_port = 80 @@ -248,7 +252,7 @@ resource "aws_cloudfront_distribution" "distribution" { path_pattern = ordered_cache_behavior.value allowed_methods = ["GET", "HEAD", "OPTIONS"] cached_methods = ["GET", "HEAD", "OPTIONS"] - target_origin_id = local.static_assets_origin_id + target_origin_id = local.assets_origin_id response_headers_policy_id = aws_cloudfront_response_headers_policy.response_headers_policy.id cache_policy_id = aws_cloudfront_cache_policy.cache_policy.id diff --git a/modules/opennext-cloudfront/outputs.tf b/modules/opennext-cloudfront/outputs.tf index 2802e43..5067968 100644 --- a/modules/opennext-cloudfront/outputs.tf +++ b/modules/opennext-cloudfront/outputs.tf @@ -1,7 +1,7 @@ output "cloudfront_distribution" { - value = aws_cloudfront_distribution.distribution + value = aws_cloudfront_distribution.distribution } output "wafv2_web_acl" { - value = aws_wafv2_web_acl.cloudfront_waf + value = aws_wafv2_web_acl.cloudfront_waf } diff --git a/modules/opennext-cloudfront/variables.tf b/modules/opennext-cloudfront/variables.tf index 98f4b93..dd8bcdb 100644 --- a/modules/opennext-cloudfront/variables.tf +++ b/modules/opennext-cloudfront/variables.tf @@ -3,10 +3,14 @@ variable "prefix" { description = "Prefix for created resource IDs" } +variable "acm_certificate_arn" { + type = string +} + variable "origins" { type = object({ - assets_bucket = string - server_function = string + assets_bucket = string + server_function = string image_optimization_function = string }) } @@ -103,7 +107,3 @@ variable "waf_logging_configuration" { default = null } - -variable "acm_certificate_arn" { - type = string -} diff --git a/modules/opennext-lambda/data.tf b/modules/opennext-lambda/data.tf index c5cabf7..95074f5 100644 --- a/modules/opennext-lambda/data.tf +++ b/modules/opennext-lambda/data.tf @@ -1,5 +1,6 @@ data "archive_file" "lambda_zip" { - type = "zip" - source_dir = var.source_dir - output_path = "${var.output_dir}${var.prefix}.zip" + type = "zip" + + source_dir = var.source_dir + output_path = "${var.output_dir}${var.prefix}.zip" } diff --git a/modules/opennext-lambda/eventbridge.tf b/modules/opennext-lambda/eventbridge.tf index 4dcf202..93ad3e0 100644 --- a/modules/opennext-lambda/eventbridge.tf +++ b/modules/opennext-lambda/eventbridge.tf @@ -1,11 +1,13 @@ resource "aws_cloudwatch_event_rule" "scheduled_lambda_event_rule" { - count = var.create_eventbridge_scheduled_rule ? 1 : 0 + count = var.create_eventbridge_scheduled_rule ? 1 : 0 + name = "${var.prefix}-scheduled-lambda-event-rule" schedule_expression = var.schedule_expression } resource "aws_cloudwatch_event_target" "lambda_target" { count = var.create_eventbridge_scheduled_rule ? 1 : 0 - arn = aws_lambda_function.function.arn - rule = aws_cloudwatch_event_rule.scheduled_lambda_event_rule[0].name + + arn = aws_lambda_function.function.arn + rule = aws_cloudwatch_event_rule.scheduled_lambda_event_rule[0].name } diff --git a/modules/opennext-lambda/lambda.tf b/modules/opennext-lambda/lambda.tf index 5234ed9..522ed96 100644 --- a/modules/opennext-lambda/lambda.tf +++ b/modules/opennext-lambda/lambda.tf @@ -20,12 +20,14 @@ resource "aws_lambda_function" "function" { filename = data.archive_file.lambda_zip.output_path source_code_hash = filebase64sha256(data.archive_file.lambda_zip.output_path) - description = var.description - function_name = var.prefix - handler = var.handler - runtime = var.runtime - architectures = var.architectures - role = aws_iam_role.lambda_role.arn + function_name = var.function_name != null ? var.function_name : var.prefix + description = var.description + + handler = var.handler + runtime = var.runtime + architectures = var.architectures + role = aws_iam_role.lambda_role.arn + kms_key_arn = var.kms_key_arn code_signing_config_arn = try(aws_lambda_code_signing_config.signing_config[0].arn, null) reserved_concurrent_executions = var.reserved_concurrent_executions diff --git a/modules/opennext-lambda/main.tf b/modules/opennext-lambda/main.tf index 9f74e0a..86ea302 100644 --- a/modules/opennext-lambda/main.tf +++ b/modules/opennext-lambda/main.tf @@ -7,7 +7,7 @@ terraform { version = "~> 4.0" } archive = { - source = "hashicorp/archive" + source = "hashicorp/archive" version = "~> 2.4.0" } } diff --git a/modules/opennext-lambda/variables.tf b/modules/opennext-lambda/variables.tf index ad35139..989c7a7 100644 --- a/modules/opennext-lambda/variables.tf +++ b/modules/opennext-lambda/variables.tf @@ -1,33 +1,62 @@ +/** + * Common Variables + **/ variable "prefix" { type = string description = "Prefix for created resource IDs" } +/** + * Create Toggles + **/ +variable "create_eventbridge_scheduled_rule" { + type = bool + description = "Toggle to create an scheduled rule in eventbridge to invoke the lambda function" + default = false +} + + +/** + * Lambda Package Variables + **/ variable "source_dir" { - type = string + type = string description = "The directory to use as the lambda deployment package" } variable "output_dir" { - type = string + type = string description = "The directory to use to store the lambda deployment packages" - default = "/tmp/" + default = "/tmp/" } -variable "create_eventbridge_scheduled_rule" { - type = bool - description = "Toggle to create an scheduled rule in eventbridge to invoke the lambda function" - default = false -} /** * Lambda Function Variables **/ +variable "function_name" { + type = string + description = "The name of the Lambda function. Defaults to var.prefix" + default = null +} + variable "description" { type = string description = "A description of the Lambda function" } +variable "handler" { + type = string + description = "The handler path for the lambda function" + default = "index.handler" +} + +variable "runtime" { + type = string + description = "The Lambda runtime to use" + default = "nodejs18.x" +} + variable "architectures" { type = list(string) description = "The architectures to use for the lambda function" @@ -46,21 +75,9 @@ variable "timeout" { default = 30 } -variable "runtime" { - type = string - description = "The Lambda runtime to use" - default = "nodejs18.x" -} - -variable "handler" { - type = string - description = "The handler path for the lambda function" - default = "index.handler" -} - variable "publish" { type = bool - description = "Publish the lambda function to lambda@edge" + description = "Publish the lambda function to Lambda@Edge" default = false } @@ -72,10 +89,38 @@ variable "environment_variables" { variable "kms_key_arn" { type = string - default = null description = "The KMS key to use for encrypting the Lambda function" + default = null } +variable "code_signing_config" { + description = "Code Signing Config for the Lambda Function" + type = object({ + description = optional(string) + signing_profile_version_arns = list(string) + untrusted_artfact_on_deployment = optional(string) + }) + default = null +} + +variable "dead_letter_config" { + description = "Lambda Dead Letter Queue (DLQ) Configuration" + default = null + type = object({ + target_arn = string + }) +} + +variable "reserved_concurrent_executions" { + description = "Concurrency limit for the lambda function" + type = number + default = 10 +} + + +/** + * Lambda Networking + **/ variable "vpc_id" { type = string description = "The VPC to attach the lambda function to" @@ -88,18 +133,8 @@ variable "subnet_ids" { default = [] } -variable "iam_policy_statements" { - type = set(object({ - effect = string - actions = list(string) - resources = list(string) - })) - description = "IAM policy statements to attach to the lambda function role" - default = [] -} - variable "security_group_ingress_rules" { - type = set(object({ + type = list(object({ description = string from_port = number to_port = number @@ -115,7 +150,7 @@ variable "security_group_ingress_rules" { } variable "security_group_egress_rules" { - type = set(object({ + type = list(object({ description = string from_port = number to_port = number @@ -130,32 +165,24 @@ variable "security_group_egress_rules" { default = [] } +/** + * Lambda IAM Policy + **/ +variable "iam_policy_statements" { + type = list(object({ + effect = string + actions = list(string) + resources = list(string) + })) + description = "IAM policy statements to attach to the lambda function role" + default = [] +} + +/** + * EventBridge Scheduled Rule + **/ variable "schedule_expression" { type = string description = "The schedule expression of the eventbridge lambda trigger rule (if enabled)" default = "rate(5 minutes)" } - -variable "code_signing_config" { - description = "Code Signing Config for the Lambda Function" - type = object({ - description = optional(string) - signing_profile_version_arns = list(string) - untrusted_artfact_on_deployment = optional(string) - }) - default = null -} - -variable "dead_letter_config" { - description = "Lambda Dead Letter Queue (DLQ) Configuration" - default = null - type = object({ - target_arn = string - }) -} - -variable "reserved_concurrent_executions" { - description = "Concurrency limit for the lambda function" - type = number - default = 10 -} diff --git a/modules/opennext-revalidation-queue/kms.tf b/modules/opennext-revalidation-queue/kms.tf index 0c8f458..1660aae 100644 --- a/modules/opennext-revalidation-queue/kms.tf +++ b/modules/opennext-revalidation-queue/kms.tf @@ -1,15 +1,15 @@ data "aws_kms_key" "revalidation_queue_key" { - count = var.kms_key_arn != null ? 1 : 0 - key_id = var.kms_key_arn + count = var.kms_key_arn != null ? 1 : 0 + key_id = var.kms_key_arn } resource "aws_kms_key" "revalidation_queue_key" { - count = var.kms_key_arn == null ? 1 : 0 + count = var.kms_key_arn == null ? 1 : 0 - description = "${var.prefix} Revalidation SQS Queue KMS Key" - deletion_window_in_days = 10 + description = "${var.prefix} Revalidation SQS Queue KMS Key" + deletion_window_in_days = 10 - policy = data.aws_iam_policy_document.revalidation_queue_key_policy[0].json + policy = data.aws_iam_policy_document.revalidation_queue_key_policy[0].json } data "aws_iam_policy_document" "revalidation_queue_key_policy" { diff --git a/modules/opennext-revalidation-queue/outputs.tf b/modules/opennext-revalidation-queue/outputs.tf index abf2adc..92695e0 100644 --- a/modules/opennext-revalidation-queue/outputs.tf +++ b/modules/opennext-revalidation-queue/outputs.tf @@ -1,7 +1,7 @@ output "queue" { - value = aws_sqs_queue.revalidation_queue + value = aws_sqs_queue.revalidation_queue } output "queue_kms_key" { - value = try(aws_kms_key.revalidation_queue_key[0], data.aws_kms_key.revalidation_queue_key[0]) + value = try(aws_kms_key.revalidation_queue_key[0], data.aws_kms_key.revalidation_queue_key[0]) } diff --git a/modules/opennext-revalidation-queue/variables.tf b/modules/opennext-revalidation-queue/variables.tf index 3806d20..95e2805 100644 --- a/modules/opennext-revalidation-queue/variables.tf +++ b/modules/opennext-revalidation-queue/variables.tf @@ -4,17 +4,17 @@ variable "prefix" { } variable "aws_account_id" { - type = string + type = string description = "The account ID of the current AWS account" } variable "kms_key_arn" { - type = string + type = string description = "The ARN of the KMS key used to encrypt the SQS queue" - default = null + default = null } variable "revalidation_function_arn" { - type = string + type = string description = "The ARN of the revalidation lambda function" } diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..0b9cb5f --- /dev/null +++ b/outputs.tf @@ -0,0 +1,27 @@ +output "cloudfront_logs" { + value = module.cloudfront_logs +} + +output "server" { + value = module.server_function +} + +output "image_optimization" { + value = module.image_optimization_function +} + +output "revalidation" { + value = module.revalidation_function +} + +output "warmer" { + value = module.warmer_function +} + +output "revalidation_queue" { + value = module.revalidation_queue +} + +output "cloudfront" { + value = module.cloudfront +} diff --git a/route53.tf b/route53.tf index f7701c3..14c04b0 100644 --- a/route53.tf +++ b/route53.tf @@ -1,5 +1,5 @@ resource "aws_route53_record" "dns_record_a" { - for_each = var.create_route53_records ? toset(var.aliases) : toset([]) + for_each = var.create_route53_records ? toset(var.cloudfront.aliases) : toset([]) zone_id = var.hosted_zone_id name = each.value @@ -13,7 +13,7 @@ resource "aws_route53_record" "dns_record_a" { } resource "aws_route53_record" "dns_record_aaaa" { - for_each = var.create_route53_records ? toset(var.aliases) : toset([]) + for_each = var.create_route53_records ? toset(var.cloudfront.aliases) : toset([]) zone_id = var.hosted_zone_id name = each.value diff --git a/variables.tf b/variables.tf index e794816..2e0c250 100644 --- a/variables.tf +++ b/variables.tf @@ -1,12 +1,20 @@ + +/** + * Common Variables + **/ variable "prefix" { type = string description = "Prefix for created resource IDs" default = "opennext" } -variable "acm_certificate_arn" { - type = string - description = "The ACM (SSL) certificate ARN for the domain name" +/** + * Route53 (DNS) Variables + **/ +variable "create_route53_records" { + type = bool + default = true + description = "Create Route53 DNS Records for CloudFront distribution" } variable "hosted_zone_id" { @@ -14,38 +22,333 @@ variable "hosted_zone_id" { description = "The Route 53 hosted zone ID of the domain name" } +variable "evaluate_target_health" { + type = bool + default = false + description = "Allow Route53 to determine whether to respond to DNS queries by checking the health of the record set" +} + +/** + * OpenNext Variables + **/ variable "opennext_build_path" { type = string description = "The path to the folder containing the .open-next build output" } -# variable "kms_key_arn" { -# type = string -# default = null -# description = "The KMS key to use for encrypting the Lambda functions" -# } +variable "server_options" { + description = "Variables passed to the opennext-lambda module for the Next.js server" + type = object({ + package = optional(object({ + source_dir = optional(string) + output_dir = optional(string) + })) -# variable "assets_paths" { -# type = list(string) -# default = [] -# description = "Paths to expose as static assets (i.e. /images/*)" -# } + function = optional(object({ + function_name = optional(string) + description = optional(string) + handler = optional(string) + runtime = optional(string) + architectures = optional(list(string)) + memory_size = optional(number) + timeout = optional(number) + publish = optional(bool) + environment_variables = optional(map(string)) + reserved_concurrent_executions = optional(number) + dead_letter_config = optional(object({ + target_arn = string + })) + code_signing_config = optional(object({ + description = optional(string) + signing_profile_version_arns = list(string) + untrusted_artfact_on_deployment = optional(string) + })) + })) -# Route53 (DNS) Variables -variable "create_route53_records" { - type = bool - default = true - description = "Create Route53 DNS Records for CloudFront distribution" + iam_policy = optional(list(object({ + effect = string + actions = list(string) + resources = list(string) + }))) + + networking = optional(object({ + vpc_id = optional(string) + subnet_ids = optional(list(string)) + sg_ingress_rules = optional(list(object({ + description = string + from_port = number + to_port = number + cidr_blocks = optional(list(string)) + ipv6_cidr_blocks = optional(list(string)) + prefix_list_ids = optional(list(string)) + protocol = optional(string) + security_groups = optional(list(string)) + self = optional(bool) + }))) + sg_egress_rules = optional(list(object({ + description = string + from_port = number + to_port = number + cidr_blocks = optional(list(string)) + ipv6_cidr_blocks = optional(list(string)) + prefix_list_ids = optional(list(string)) + protocol = optional(string) + security_groups = optional(list(string)) + self = optional(bool) + }))) + })) + }) + default = {} } -variable "evaluate_target_health" { - type = bool - default = false - description = "Allow Route53 to determine whether to respond to DNS queries by checking the health of the record set" +variable "image_optimization_options" { + description = "Variables passed to the opennext-lambda module for the Next.js Image Optimization function" + type = object({ + package = optional(object({ + source_dir = optional(string) + output_dir = optional(string) + })) + + function = optional(object({ + function_name = optional(string) + description = optional(string) + handler = optional(string) + runtime = optional(string) + architectures = optional(list(string)) + memory_size = optional(number) + timeout = optional(number) + publish = optional(bool) + reserved_concurrent_executions = optional(number) + dead_letter_config = optional(object({ + target_arn = string + })) + code_signing_config = optional(object({ + description = optional(string) + signing_profile_version_arns = list(string) + untrusted_artfact_on_deployment = optional(string) + })) + })) + + environment_variables = optional(map(string)) + + + iam_policy = optional(list(object({ + effect = string + actions = list(string) + resources = list(string) + }))) + + networking = optional(object({ + vpc_id = optional(string) + subnet_ids = optional(list(string)) + sg_ingress_rules = optional(list(object({ + description = string + from_port = number + to_port = number + cidr_blocks = optional(list(string)) + ipv6_cidr_blocks = optional(list(string)) + prefix_list_ids = optional(list(string)) + protocol = optional(string) + security_groups = optional(list(string)) + self = optional(bool) + }))) + sg_egress_rules = optional(list(object({ + description = string + from_port = number + to_port = number + cidr_blocks = optional(list(string)) + ipv6_cidr_blocks = optional(list(string)) + prefix_list_ids = optional(list(string)) + protocol = optional(string) + security_groups = optional(list(string)) + self = optional(bool) + }))) + })) + }) + default = {} +} + +variable "revalidation_options" { + description = "Variables passed to the opennext-lambda module for the Next.js ISR Revalidation function" + type = object({ + package = optional(object({ + source_dir = optional(string) + output_dir = optional(string) + })) + + function = optional(object({ + function_name = optional(string) + description = optional(string) + handler = optional(string) + runtime = optional(string) + architectures = optional(list(string)) + memory_size = optional(number) + timeout = optional(number) + publish = optional(bool) + reserved_concurrent_executions = optional(number) + dead_letter_config = optional(object({ + target_arn = string + })) + code_signing_config = optional(object({ + description = optional(string) + signing_profile_version_arns = list(string) + untrusted_artfact_on_deployment = optional(string) + })) + })) + + environment_variables = optional(map(string)) + + + iam_policy = optional(list(object({ + effect = string + actions = list(string) + resources = list(string) + }))) + + networking = optional(object({ + vpc_id = optional(string) + subnet_ids = optional(list(string)) + sg_ingress_rules = optional(list(object({ + description = string + from_port = number + to_port = number + cidr_blocks = optional(list(string)) + ipv6_cidr_blocks = optional(list(string)) + prefix_list_ids = optional(list(string)) + protocol = optional(string) + security_groups = optional(list(string)) + self = optional(bool) + }))) + sg_egress_rules = optional(list(object({ + description = string + from_port = number + to_port = number + cidr_blocks = optional(list(string)) + ipv6_cidr_blocks = optional(list(string)) + prefix_list_ids = optional(list(string)) + protocol = optional(string) + security_groups = optional(list(string)) + self = optional(bool) + }))) + })) + }) + default = {} +} + +variable "warmer_options" { + description = "Variables passed to the opennext-lambda module for the Next.js Warmer function" + type = object({ + package = optional(object({ + source_dir = optional(string) + output_dir = optional(string) + })) + + function = optional(object({ + function_name = optional(string) + description = optional(string) + handler = optional(string) + runtime = optional(string) + architectures = optional(list(string)) + memory_size = optional(number) + timeout = optional(number) + publish = optional(bool) + reserved_concurrent_executions = optional(number) + dead_letter_config = optional(object({ + target_arn = string + })) + code_signing_config = optional(object({ + description = optional(string) + signing_profile_version_arns = list(string) + untrusted_artfact_on_deployment = optional(string) + })) + })) + + environment_variables = optional(map(string)) + + + iam_policy = optional(list(object({ + effect = string + actions = list(string) + resources = list(string) + }))) + + networking = optional(object({ + vpc_id = optional(string) + subnet_ids = optional(list(string)) + sg_ingress_rules = optional(list(object({ + description = string + from_port = number + to_port = number + cidr_blocks = optional(list(string)) + ipv6_cidr_blocks = optional(list(string)) + prefix_list_ids = optional(list(string)) + protocol = optional(string) + security_groups = optional(list(string)) + self = optional(bool) + }))) + sg_egress_rules = optional(list(object({ + description = string + from_port = number + to_port = number + cidr_blocks = optional(list(string)) + ipv6_cidr_blocks = optional(list(string)) + prefix_list_ids = optional(list(string)) + protocol = optional(string) + security_groups = optional(list(string)) + self = optional(bool) + }))) + })) + }) + default = {} } -# CloudFront Variables -variable "aliases" { - type = list(string) - description = "The aliases (domain names) to be used for the Next.js application" +variable "cloudfront" { + type = object({ + aliases = list(string) + acm_certificate_arn = string + assets_paths = optional(list(string)) + custom_headers = optional(list(object({ + header = string + override = bool + value = string + }))) + cors = optional(object({ + allow_credentials = bool, + allow_headers = list(string) + allow_methods = list(string) + allow_origins = list(string) + origin_override = bool + })) + hsts = optional(object({ + access_control_max_age_sec = number + include_subdomains = bool + override = bool + preload = bool + })) + waf_logging_configuration = optional(object({ + log_destination_configs = list(string) + logging_filter = optional(object({ + default_behavior = string + filter = list(object({ + behavior = string + requirement = string + action_condition = optional(list(object({ + action = string + }))) + label_name_condition = optional(list(object({ + label_name = string + }))) + })) + })) + redacted_fields = optional(list(object({ + method = optional(bool) + query_string = optional(bool) + single_header = optional(object({ + name = string + })) + uri_path = optional(bool) + }))) + })) + + }) }