diff --git a/apps/infrastructure/src/.terraform.lock.hcl b/apps/infrastructure/src/.terraform.lock.hcl index 8d1fcf8019..ebe1c89ece 100644 --- a/apps/infrastructure/src/.terraform.lock.hcl +++ b/apps/infrastructure/src/.terraform.lock.hcl @@ -3,9 +3,9 @@ provider "registry.terraform.io/hashicorp/aws" { version = "5.33.0" - constraints = ">= 3.54.0, >= 4.0.0, >= 4.63.0, 5.33.0" + constraints = ">= 2.49.0, >= 3.54.0, >= 4.0.0, >= 4.22.0, >= 4.29.0, >= 4.37.0, >= 4.40.0, >= 4.63.0, >= 4.66.1, >= 5.0.0, >= 5.20.0, >= 5.21.0, >= 5.26.0, >= 5.27.0, >= 5.30.0, >= 5.33.0, 5.33.0" hashes = [ - "h1:sZQmGTahSetfC6RObmlg3LGYIUxrnXsj/IGzJg90Zgc=", + "h1:6PKlIl26h6QJHXEYk1QEQvuzlGupJ0n5sX1aRE3XsxA=", "zh:10bb683f2a9306e881f51a971ad3b2bb654ac94b54945dd63769876a343b5b04", "zh:3916406db958d5487ea0c2d2320012d1907c29e6d01bf693560fe05e38ee0601", "zh:3cb54b76b2f9e30620f3281ab7fb20633b1e4584fc84cc4ecd5752546252e86f", @@ -25,42 +25,42 @@ provider "registry.terraform.io/hashicorp/aws" { } provider "registry.terraform.io/hashicorp/external" { - version = "2.3.2" + version = "2.3.3" constraints = ">= 1.0.0" hashes = [ - "h1:o3YpEB5BjeHiVi/1W0QDYhMUFmNsUZ7/3UombYD75e0=", - "zh:020bf652739ecd841d696e6c1b85ce7dd803e9177136df8fb03aa08b87365389", - "zh:0c7ea5a1cbf2e01a8627b8a84df69c93683f39fe947b288e958e72b9d12a827f", - "zh:25a68604c7d6aa736d6e99225051279eaac3a7cf4cab33b00ff7eae7096166f6", - "zh:34f46d82ca34604f6522de3b36eda19b7ad3be1e38947afc6ac31656eab58c8a", - "zh:6959f8f2f3de93e61e0abb90dbec41e28a66daec1607c46f43976bd6da50bcfd", + "h1:Up2xaIhiNYomK8Lhe29U2FcojpbRWZYDtSeS03OhI94=", + "zh:03d81462f9578ec91ce8e26f887e34151eda0e100f57e9772dbea86363588239", + "zh:37ec2a20f6a3ec3a0fd95d3f3de26da6cb9534b30488bc45723e118a0911c0d8", + "zh:4eb5b119179539f2749ce9de0e1b9629d025990f062f4f4dddc161562bb89d37", + "zh:5a31bb58414f41bee5e09b939012df5b88654120b0238a89dfd6691ba197619a", + "zh:6221a05e52a6a2d4f520ffe7cbc741f4f6080e0855061b0ed54e8be4a84eb9b7", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:a81e5d65a343da9caa6f1d17ae0aced9faecb36b4f8554bd445dbd4f8be21ab6", - "zh:b1d3f1557214d652c9120862ce27e9a7b61cb5aec5537a28240a5a37bf0b1413", - "zh:b71588d006471ae2d4a7eca2c51d69fd7c5dec9b088315599b794e2ad0cc5e90", - "zh:cfdaae4028b644dff3530c77b49d31f7e6f4c4e2a9e5c8ac6a88e383c80c9e9c", - "zh:dbde15154c2eb38a5f54d0e7646bc67510004179696f3cc2bc1d877cecacf83b", - "zh:fb681b363f83fb5f64dfa6afbf32d100d0facd2a766cf3493b8ddb0398e1b0f7", + "zh:8bb068496b4679bef625e4710d9f3432e301c3a56602271f04e60eadf7f8a94c", + "zh:94742aa5378bab626ce34f79bcef6a373e4f86ea7a8b762e9f71270a899e0d00", + "zh:a485831b5a525cd8f40e8982fa37da40ff70b1ae092c8b755fcde123f0b1238d", + "zh:a647ff16d071eabcabd87ea8183eb90a775a0294ddd735d742075d62fff09193", + "zh:b74710c5954aaa3faf262c18d36a8c2407862d9f842c63e7fa92fa4de3d29df6", + "zh:fa73d83edc92af2e551857594c2232ba6a9e3603ad34b0a5940865202c08d8d7", ] } provider "registry.terraform.io/hashicorp/local" { - version = "2.4.1" + version = "2.5.1" constraints = ">= 1.0.0" hashes = [ - "h1:V2G4qygMV0uHy+QTMlrjSyYgzpYmYyB6gWuE09+5CPI=", - "zh:244b445bf34ddbd167731cc6c6b95bbed231dc4493f8cc34bd6850cfe1f78528", - "zh:3c330bdb626123228a0d1b1daa6c741b4d5d484ab1c7ae5d2f48d4c9885cc5e9", - "zh:5ff5f9b791ddd7557e815449173f2db38d338e674d2d91800ac6e6d808de1d1d", - "zh:70206147104f4bf26ae67d730c995772f85bf23e28c2c2e7612c74f4dae3c46f", - "zh:75029676993accd6bef933c196b2fad51a9ec8a69a847dbbe96ec8ebf7926cdc", + "h1:fm2EuMlsdPTuv2tKwx3PMJzWJUh7aMtU9Eky7t4fMys=", + "zh:0af29ce2b7b5712319bf6424cb58d13b852bf9a777011a545fac99c7fdcdf561", + "zh:126063ea0d79dad1f68fa4e4d556793c0108ce278034f101d1dbbb2463924561", + "zh:196bfb49086f22fd4db46033e01655b0e5e036a5582d250412cc690fa7995de5", + "zh:37c92ec084d059d37d6cffdb683ccf68e3a5f8d2eb69dd73c8e43ad003ef8d24", + "zh:4269f01a98513651ad66763c16b268f4c2da76cc892ccfd54b401fff6cc11667", + "zh:51904350b9c728f963eef0c28f1d43e73d010333133eb7f30999a8fb6a0cc3d8", + "zh:73a66611359b83d0c3fcba2984610273f7954002febb8a57242bbb86d967b635", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:7d48d5999fe1fcdae9295a7c3448ac1541f5a24c474bd82df6d4fa3732483f2b", - "zh:b766b38b027f0f84028244d1c2f990431a37d4fc3ac645962924554016507e77", - "zh:bfc7ad301dada204cf51c59d8bd6a9a87de5fddb42190b4d6ba157d6e08a1f10", - "zh:c902b527702a8c5e2c25a6637d07bbb1690cb6c1e63917a5f6dc460efd18d43f", - "zh:d68ae0e1070cf429c46586bc87580c3ed113f76241da2b6e4f1a8348126b3c46", - "zh:f4903fd89f7c92a346ae9e666c2d0b6884c4474ae109e9b4bd15e7efaa4bfc29", + "zh:7ae387993a92bcc379063229b3cce8af7eaf082dd9306598fcd42352994d2de0", + "zh:9e0f365f807b088646db6e4a8d4b188129d9ebdbcf2568c8ab33bddd1b82c867", + "zh:b5263acbd8ae51c9cbffa79743fbcadcb7908057c87eb22fd9048268056efbc4", + "zh:dfcd88ac5f13c0d04e24be00b686d069b4879cc4add1b7b1a8ae545783d97520", ] } @@ -68,7 +68,7 @@ provider "registry.terraform.io/hashicorp/null" { version = "3.2.2" constraints = ">= 2.0.0" hashes = [ - "h1:vWAsYRd7MjYr3adj8BVKRohVfHpWQdvkIwUQ2Jf5FVM=", + "h1:Gef5VGfobY5uokA5nV/zFvWeMNR2Pmq79DH94QnNZPM=", "zh:3248aae6a2198f3ec8394218d05bd5e42be59f43a3a7c0b71c66ec0df08b69e7", "zh:32b1aaa1c3013d33c245493f4a65465eab9436b454d250102729321a44c8ab9a", "zh:38eff7e470acb48f66380a73a5c7cdd76cc9b9c9ba9a7249c7991488abe22fe3", @@ -85,28 +85,28 @@ provider "registry.terraform.io/hashicorp/null" { } provider "registry.terraform.io/hashicorp/random" { - version = "3.6.0" + version = "3.6.2" hashes = [ - "h1:p6WG1IPHnqx1fnJVKNjv733FBaArIugqy58HRZnpPCk=", - "zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d", - "zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211", - "zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829", - "zh:30ffb297ffd1633175d6545d37c2217e2cef9545a6e03946e514c59c0859b77d", - "zh:454ce4b3dbc73e6775f2f6605d45cee6e16c3872a2e66a2c97993d6e5cbd7055", + "h1:UQlmHGddu39vVzG8kruMsde4GHlG+1S7OLqFApbJvtc=", + "zh:0ef01a4f81147b32c1bea3429974d4d104bbc4be2ba3cfa667031a8183ef88ec", + "zh:1bcd2d8161e89e39886119965ef0f37fcce2da9c1aca34263dd3002ba05fcb53", + "zh:37c75d15e9514556a5f4ed02e1548aaa95c0ecd6ff9af1119ac905144c70c114", + "zh:4210550a767226976bc7e57d988b9ce48f4411fa8a60cd74a6b246baf7589dad", + "zh:562007382520cd4baa7320f35e1370ffe84e46ed4e2071fdc7e4b1a9b1f8ae9b", + "zh:5efb9da90f665e43f22c2e13e0ce48e86cae2d960aaf1abf721b497f32025916", + "zh:6f71257a6b1218d02a573fc9bff0657410404fb2ef23bc66ae8cd968f98d5ff6", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:91df0a9fab329aff2ff4cf26797592eb7a3a90b4a0c04d64ce186654e0cc6e17", - "zh:aa57384b85622a9f7bfb5d4512ca88e61f22a9cea9f30febaa4c98c68ff0dc21", - "zh:c4a3e329ba786ffb6f2b694e1fd41d413a7010f3a53c20b432325a94fa71e839", - "zh:e2699bc9116447f96c53d55f2a00570f982e6f9935038c3810603572693712d0", - "zh:e747c0fd5d7684e5bfad8aa0ca441903f15ae7a98a737ff6aca24ba223207e2c", - "zh:f1ca75f417ce490368f047b63ec09fd003711ae48487fba90b4aba2ccf71920e", + "zh:9647e18f221380a85f2f0ab387c68fdafd58af6193a932417299cdcae4710150", + "zh:bb6297ce412c3c2fa9fec726114e5e0508dd2638cad6a0cb433194930c97a544", + "zh:f83e925ed73ff8a5ef6e3608ad9225baa5376446349572c2449c0c0b3cf184b7", + "zh:fbef0781cb64de76b1df1ca11078aecba7800d82fd4a956302734999cfd9a4af", ] } provider "registry.terraform.io/hashicorp/template" { version = "2.2.0" hashes = [ - "h1:0wlehNaxBX7GJQnPfQwTNvvAf38Jm0Nv7ssKGMaG6Og=", + "h1:12Bac8B6Aq2+18xe8iqp5iYytav2Bw+jG43z/VaK5zI=", "zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386", "zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53", "zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603", diff --git a/apps/infrastructure/src/ecs.tf b/apps/infrastructure/src/ecs.tf deleted file mode 100644 index da649c9fa0..0000000000 --- a/apps/infrastructure/src/ecs.tf +++ /dev/null @@ -1,85 +0,0 @@ -## ECS for CMS Strapi -module "cms_ecs_cluster" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-ecs.git//modules/cluster?ref=8b97783def49997d18a6fcb00dc21ce1edc0f538" # v5.9.0 - - cluster_name = "cms-ecs-cluster" -} - -data "template_file" "cms_app" { - template = file("./task-definitions/cms_app.json.tpl") - - vars = { - image = module.ecr.repository_url - fargate_cpu = var.cms_app_cpu - fargate_memory = var.cms_app_memory - aws_region = var.aws_region - db_host = module.cms_rds.cluster_endpoint - db_user = module.cms_rds.cluster_master_username - db_password_arn = module.secret_cms_database_password.ssm_parameter_arn - bucket_name = module.s3_bucket_cms.s3_bucket_id - admin_jwt_secret_arn = module.secret_cms_admin_jwt_secret.ssm_parameter_arn - db_name = module.cms_rds.cluster_database_name - db_client = "postgres" - container_port = var.cms_app_port - app_keys = module.secret_cms_app_keys.ssm_parameter_arn - api_token_salt = module.secret_cms_api_token_salt.ssm_parameter_arn - transfer_token_salt = module.secret_cms_transfer_token_salt.ssm_parameter_arn - jwt_secret = module.secret_cms_jwt_secret.ssm_parameter_arn - access_key_id = module.secret_cms_access_key_id.ssm_parameter_arn - access_key_secret = module.secret_cms_access_key_secret.ssm_parameter_arn - bucket_full_url = module.s3_bucket_cms.s3_bucket_bucket_regional_domain_name - cdn_url = "https://${aws_route53_record.strapi_media_library.name}" - aws_bucket_endpoint = "https://s3.${var.aws_region}.amazonaws.com" - repo_owner = "pagopa" - repo_name = "developer-portal" - workflow_id = "deploy_website.yaml" - target_branch = "main" - github_pat = module.secret_cms_github_pat.ssm_parameter_arn - log_group = module.cms_log_group.cloudwatch_log_group_name - google_gsuite_hd = module.secret_cms_google_gsuite_hd.ssm_parameter_arn - google_oauth_client_id = module.secret_cms_google_oauth_client_id.ssm_parameter_arn - google_oauth_client_secret = module.secret_cms_google_oauth_client_secret.ssm_parameter_arn - google_oauth_redirect_uri = format("https://cms.%s/strapi-plugin-sso/google/callback", var.dns_domain_name) - } -} - -resource "aws_ecs_task_definition" "cms_task_def" { - family = "cms-task-def" - execution_role_arn = module.iam_role_ecs_task_execution.iam_role_arn - task_role_arn = module.iam_role_task_role.iam_role_arn - network_mode = "awsvpc" - requires_compatibilities = ["FARGATE"] - cpu = var.cms_app_cpu - memory = var.cms_app_memory - container_definitions = data.template_file.cms_app.rendered -} - -module "cms_ecs_service" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-ecs.git//modules/service?ref=8b97783def49997d18a6fcb00dc21ce1edc0f538" # v5.9.0 - - name = "cms-ecs" - cluster_arn = module.cms_ecs_cluster.arn - desired_count = 1 - create_task_definition = false - create_iam_role = false - create_task_exec_iam_role = false - create_security_group = false - launch_type = "FARGATE" - force_new_deployment = true - task_definition_arn = aws_ecs_task_definition.cms_task_def.arn - tasks_iam_role_arn = module.iam_role_task_role.iam_role_arn - task_exec_iam_role_arn = module.iam_role_ecs_task_execution.iam_role_arn - ignore_task_definition_changes = true # CMS Deployment is managed by the "Deploy CMS" GitHub Action - - security_group_ids = [aws_security_group.ecs_tasks.id] - subnet_ids = module.vpc.private_subnets - assign_public_ip = false - - load_balancer = { - cms-target-group = { - target_group_arn = module.cms_load_balancer.target_groups["cms-target-group"].arn - container_name = "cms-docker" - container_port = var.cms_app_port - } - } -} diff --git a/apps/infrastructure/src/main.tf b/apps/infrastructure/src/main.tf index b1912784f1..20e0d7ca2d 100644 --- a/apps/infrastructure/src/main.tf +++ b/apps/infrastructure/src/main.tf @@ -32,3 +32,59 @@ module "identity" { source = "./identity" github_repository = var.github_repository } + +module "core" { + source = "./modules/core" + + environment = var.environment + tags = var.tags + + dns_domain_name = var.dns_domain_name + dns_delegate_records = var.dns_delegate_records +} + +module "website" { + source = "./modules/website" + + providers = { + aws = aws + aws.us-east-1 = aws.us-east-1 + } + + environment = var.environment + github_repository = var.github_repository + tags = var.tags + + cdn_custom_headers = var.cdn_custom_headers + publish_cloudfront_functions = var.publish_cloudfront_functions + dns_domain_name = var.dns_domain_name + dns_delegate_records = var.dns_delegate_records + use_custom_certificate = var.use_custom_certificate + hosted_zone_id = module.core.hosted_zone_id + ses_domain_identity_arn = module.core.ses_domain_identity_arn +} + +module "cms" { + source = "./modules/cms" + + providers = { + aws = aws + aws.us-east-1 = aws.us-east-1 + } + + environment = var.environment + github_repository = var.github_repository + tags = var.tags + + dns_domain_name = var.dns_domain_name + dns_domain_name_cms = var.dns_domain_name_cms + hosted_zone_id = module.core.hosted_zone_id +} + +module "chatbot" { + source = "./modules/chatbot" + + aws_region = "eu-west-3" + environment = var.environment + tags = var.tags +} diff --git a/apps/infrastructure/src/modules/chatbot/providers.tf b/apps/infrastructure/src/modules/chatbot/providers.tf new file mode 100644 index 0000000000..9fddf689ff --- /dev/null +++ b/apps/infrastructure/src/modules/chatbot/providers.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.33.0" + } + } +} \ No newline at end of file diff --git a/apps/infrastructure/src/modules/chatbot/s3_bucket.tf b/apps/infrastructure/src/modules/chatbot/s3_bucket.tf new file mode 100644 index 0000000000..d061b453dd --- /dev/null +++ b/apps/infrastructure/src/modules/chatbot/s3_bucket.tf @@ -0,0 +1,19 @@ +resource "random_integer" "ai_kb_bucket_random_integer" { + min = 1 + max = 9999 +} + +module "s3_bucket_ai_kb" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git?ref=3a1c80b29fdf8fc682d2749456ec36ecbaf4ce14" # v4.1.0 + + bucket = "ai-knowledge-base-${random_integer.ai_kb_bucket_random_integer.result}" + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true + + versioning = { + status = true + enabled = true + } +} diff --git a/apps/infrastructure/src/modules/chatbot/variables.tf b/apps/infrastructure/src/modules/chatbot/variables.tf new file mode 100644 index 0000000000..98b50ee263 --- /dev/null +++ b/apps/infrastructure/src/modules/chatbot/variables.tf @@ -0,0 +1,17 @@ +variable "aws_region" { + type = string + description = "AWS region to create resources. Default Milan" + default = "eu-south-1" +} + +variable "environment" { + type = string + description = "Environment" +} + +variable "tags" { + type = map(any) + default = { + CreatedBy = "Terraform" + } +} \ No newline at end of file diff --git a/apps/infrastructure/src/acm.tf b/apps/infrastructure/src/modules/cms/acm.tf similarity index 59% rename from apps/infrastructure/src/acm.tf rename to apps/infrastructure/src/modules/cms/acm.tf index ae3abd42c1..cc501c4884 100644 --- a/apps/infrastructure/src/acm.tf +++ b/apps/infrastructure/src/modules/cms/acm.tf @@ -1,34 +1,9 @@ -resource "aws_acm_certificate" "website" { - domain_name = var.dns_domain_name - validation_method = "DNS" - subject_alternative_names = [format("www.%s", var.dns_domain_name)] - - lifecycle { - create_before_destroy = true - } - - # TLS certificate generated in us-east because it is related to the CDN which is a global resource - provider = aws.us-east-1 -} - -resource "aws_acm_certificate" "auth" { - domain_name = format("auth.%s", var.dns_domain_name) - validation_method = "DNS" - - lifecycle { - create_before_destroy = true - } - - # TLS certificate generated in us-east because it is related to the CDN which is a global resource - provider = aws.us-east-1 -} - ## Certificate HTTPS for CMS Strapi module "cms_ssl_certificate" { source = "git::https://github.com/terraform-aws-modules/terraform-aws-acm.git?ref=8d0b22f1f242a1b36e29b8cb38aaeac9b887500d" # v5.0.0 domain_name = keys(var.dns_domain_name_cms)[0] - zone_id = aws_route53_zone.dev_portal.id + zone_id = var.hosted_zone_id subject_alternative_names = [ "www.${keys(var.dns_domain_name_cms)[0]}" @@ -44,7 +19,7 @@ module "strapi_media_library_ssl_certificate" { source = "git::https://github.com/terraform-aws-modules/terraform-aws-acm.git?ref=8d0b22f1f242a1b36e29b8cb38aaeac9b887500d" # v5.0.0 domain_name = format("cdn.%s", var.dns_domain_name) - zone_id = aws_route53_zone.dev_portal.id + zone_id = var.hosted_zone_id providers = { aws = aws.us-east-1 diff --git a/apps/infrastructure/src/alb.tf b/apps/infrastructure/src/modules/cms/alb.tf similarity index 100% rename from apps/infrastructure/src/alb.tf rename to apps/infrastructure/src/modules/cms/alb.tf diff --git a/apps/infrastructure/src/modules/cms/cloudfront.tf b/apps/infrastructure/src/modules/cms/cloudfront.tf new file mode 100644 index 0000000000..e45a476873 --- /dev/null +++ b/apps/infrastructure/src/modules/cms/cloudfront.tf @@ -0,0 +1,53 @@ +## CDN to Media Library for CMS Strapi +module "cloudfront_cms" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-cloudfront.git?ref=ed0f1f983f606304e00ad9f48399bd2fe0b79233" # v3.2.2 + + create_origin_access_identity = true + origin_access_identities = { + s3_cms = "Identity to access S3 bucket" + } + + origin = { + s3_one = { + domain_name = module.s3_bucket_cms.s3_bucket_bucket_regional_domain_name + s3_origin_config = { + origin_access_identity = "s3_cms" + } + } + } + + enabled = true + is_ipv6_enabled = true + comment = "CloudFront distribution for the CMS Media Library" + + viewer_certificate = { + cloudfront_default_certificate = false + acm_certificate_arn = module.strapi_media_library_ssl_certificate.acm_certificate_arn + ssl_support_method = "sni-only" + minimum_protocol_version = "TLSv1.2_2021" + } + + aliases = module.strapi_media_library_ssl_certificate.distinct_domain_names + + default_cache_behavior = { + allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] + cached_methods = ["GET", "HEAD", "OPTIONS"] + target_origin_id = "s3_one" + viewer_protocol_policy = "redirect-to-https" + min_ttl = 0 # min time for objects to live in the distribution cache + default_ttl = 3600 # default time for objects to live in the distribution cache + max_ttl = 86400 # max time for objects to live in the distribution cache + + forwarded_values = { + query_string = false + headers = [] + cookies = { + forward = "none" + } + } + } + + geo_restriction = { + restriction_type = "none" + } +} diff --git a/apps/infrastructure/src/cloudwatch_log_group.tf b/apps/infrastructure/src/modules/cms/cloudwatch_log_group.tf similarity index 100% rename from apps/infrastructure/src/cloudwatch_log_group.tf rename to apps/infrastructure/src/modules/cms/cloudwatch_log_group.tf diff --git a/apps/infrastructure/src/ecr.tf b/apps/infrastructure/src/modules/cms/ecr.tf similarity index 100% rename from apps/infrastructure/src/ecr.tf rename to apps/infrastructure/src/modules/cms/ecr.tf diff --git a/apps/infrastructure/src/modules/cms/ecs.tf b/apps/infrastructure/src/modules/cms/ecs.tf new file mode 100644 index 0000000000..75ecc35091 --- /dev/null +++ b/apps/infrastructure/src/modules/cms/ecs.tf @@ -0,0 +1,81 @@ +## ECS for CMS Strapi +module "cms_ecs_cluster" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-ecs.git//modules/cluster?ref=8b97783def49997d18a6fcb00dc21ce1edc0f538" # v5.9.0 + + cluster_name = "cms-ecs-cluster" +} + +resource "aws_ecs_task_definition" "cms_task_def" { + family = "cms-task-def" + execution_role_arn = module.iam_role_ecs_task_execution.iam_role_arn + task_role_arn = module.iam_role_task_role.iam_role_arn + network_mode = "awsvpc" + requires_compatibilities = ["FARGATE"] + cpu = var.cms_app_cpu + memory = var.cms_app_memory + container_definitions = templatefile( + "${path.module}/task-definitions/cms_app.json.tpl", + { + image = module.ecr.repository_url + fargate_cpu = var.cms_app_cpu + fargate_memory = var.cms_app_memory + aws_region = var.aws_region + db_host = module.cms_rds.cluster_endpoint + db_user = module.cms_rds.cluster_master_username + db_password_arn = module.secret_cms_database_password.ssm_parameter_arn + bucket_name = module.s3_bucket_cms.s3_bucket_id + admin_jwt_secret_arn = module.secret_cms_admin_jwt_secret.ssm_parameter_arn + db_name = module.cms_rds.cluster_database_name + db_client = "postgres" + container_port = var.cms_app_port + app_keys = module.secret_cms_app_keys.ssm_parameter_arn + api_token_salt = module.secret_cms_api_token_salt.ssm_parameter_arn + transfer_token_salt = module.secret_cms_transfer_token_salt.ssm_parameter_arn + jwt_secret = module.secret_cms_jwt_secret.ssm_parameter_arn + access_key_id = module.secret_cms_access_key_id.ssm_parameter_arn + access_key_secret = module.secret_cms_access_key_secret.ssm_parameter_arn + bucket_full_url = module.s3_bucket_cms.s3_bucket_bucket_regional_domain_name + cdn_url = "https://${aws_route53_record.strapi_media_library.name}" + aws_bucket_endpoint = "https://s3.${var.aws_region}.amazonaws.com" + repo_owner = "pagopa" + repo_name = "developer-portal" + workflow_id = "deploy_website.yaml" + target_branch = "main" + github_pat = module.secret_cms_github_pat.ssm_parameter_arn + log_group = module.cms_log_group.cloudwatch_log_group_name + google_gsuite_hd = module.secret_cms_google_gsuite_hd.ssm_parameter_arn + google_oauth_client_id = module.secret_cms_google_oauth_client_id.ssm_parameter_arn + google_oauth_client_secret = module.secret_cms_google_oauth_client_secret.ssm_parameter_arn + google_oauth_redirect_uri = format("https://cms.%s/strapi-plugin-sso/google/callback", var.dns_domain_name) + }) +} + +module "cms_ecs_service" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-ecs.git//modules/service?ref=8b97783def49997d18a6fcb00dc21ce1edc0f538" # v5.9.0 + + name = "cms-ecs" + cluster_arn = module.cms_ecs_cluster.arn + desired_count = 1 + create_task_definition = false + create_iam_role = false + create_task_exec_iam_role = false + create_security_group = false + launch_type = "FARGATE" + force_new_deployment = true + task_definition_arn = aws_ecs_task_definition.cms_task_def.arn + tasks_iam_role_arn = module.iam_role_task_role.iam_role_arn + task_exec_iam_role_arn = module.iam_role_ecs_task_execution.iam_role_arn + ignore_task_definition_changes = true # CMS Deployment is managed by the "Deploy CMS" GitHub Action + + security_group_ids = [aws_security_group.ecs_tasks.id] + subnet_ids = module.vpc.private_subnets + assign_public_ip = false + + load_balancer = { + cms-target-group = { + target_group_arn = module.cms_load_balancer.target_groups["cms-target-group"].arn + container_name = "cms-docker" + container_port = var.cms_app_port + } + } +} diff --git a/apps/infrastructure/src/iam_policy.tf b/apps/infrastructure/src/modules/cms/iam_policy.tf similarity index 73% rename from apps/infrastructure/src/iam_policy.tf rename to apps/infrastructure/src/modules/cms/iam_policy.tf index b2ad23b7f4..c85c54da29 100644 --- a/apps/infrastructure/src/iam_policy.tf +++ b/apps/infrastructure/src/modules/cms/iam_policy.tf @@ -29,47 +29,6 @@ data "aws_iam_policy_document" "deploy_github" { } } -resource "aws_iam_policy" "deploy_website" { - name = "DeployWebsite" - description = "Policy to allow to deploy the website" - - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Action = [ - "s3:PutObject", - "s3:GetObject", - "s3:PutObjectAcl", - "s3:DeleteObject" - ] - Effect = "Allow" - Resource = [ - format("%s/*", aws_s3_bucket.website.arn) - ] - }, - { - Action = [ - "s3:ListBucket" - ] - Effect = "Allow" - Resource = [ - aws_s3_bucket.website.arn - ] - }, - { - Action = [ - "cloudfront:CreateInvalidation" - ] - Effect = "Allow" - Resource = [ - aws_cloudfront_distribution.website.arn - ] - } - ] - }) -} - resource "aws_iam_policy" "deploy_cms" { name = "DeployCms" description = "Policy to allow to deploy the cms" @@ -208,21 +167,6 @@ module "iam_policy_cms" { }) } -data "aws_iam_policy_document" "website_iam_policy" { - statement { - actions = ["s3:GetObject", "s3:ListBucket"] - resources = [ - aws_s3_bucket.website.arn, - "${aws_s3_bucket.website.arn}/*" - ] - - principals { - type = "AWS" - identifiers = [aws_cloudfront_origin_access_identity.main.iam_arn] - } - } -} - data "aws_iam_policy_document" "s3_iam_policy_cms" { statement { actions = ["s3:GetObject", "s3:ListBucket"] @@ -236,28 +180,4 @@ data "aws_iam_policy_document" "s3_iam_policy_cms" { identifiers = module.cloudfront_cms.cloudfront_origin_access_identity_iam_arns } } -} - -data "aws_iam_policy_document" "authenticated_users_policy" { - statement { - effect = "Allow" - actions = ["sts:AssumeRoleWithWebIdentity"] - - principals { - type = "Federated" - identifiers = ["cognito-identity.amazonaws.com"] - } - - condition { - test = "StringEquals" - variable = "cognito-identity.amazonaws.com:aud" - values = [aws_cognito_identity_pool.devportal.id] - } - - condition { - test = "ForAnyValue:StringLike" - variable = "cognito-identity.amazonaws.com:amr" - values = ["authenticated"] - } - } -} +} \ No newline at end of file diff --git a/apps/infrastructure/src/modules/cms/iam_role.tf b/apps/infrastructure/src/modules/cms/iam_role.tf new file mode 100644 index 0000000000..4d3a1d8ba4 --- /dev/null +++ b/apps/infrastructure/src/modules/cms/iam_role.tf @@ -0,0 +1,54 @@ +############################################################################### +# Define IAM Role to use on strapi deploy # +############################################################################### +resource "aws_iam_role" "deploy_cms" { + name = "GitHubActionDeployCms" + description = "Role to assume to deploy the cms" + assume_role_policy = data.aws_iam_policy_document.deploy_github.json +} + +resource "aws_iam_role_policy_attachment" "deploy_cms" { + role = aws_iam_role.deploy_cms.name + policy_arn = aws_iam_policy.deploy_cms.arn +} + +############################################################################### +# IAM Role used by task execution agent # +############################################################################### +module "iam_role_ecs_task_execution" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-assumable-role?ref=f37809108f86d8fbdf17f735df734bf4abe69315" # v5.34.0 + + create_role = true + role_name = "ecs-task-execution-role" + + custom_role_policy_arns = [ + "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy", + "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", + module.iam_policy_ecs_task_execution.arn, + ] + number_of_custom_role_policy_arns = 3 + trusted_role_services = [ + "ecs-tasks.amazonaws.com" + ] + role_requires_mfa = false +} + +############################################################################### +# IAM Role used by strapi # +############################################################################### +module "iam_role_task_role" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-assumable-role?ref=f37809108f86d8fbdf17f735df734bf4abe69315" # v5.34.0 + + create_role = true + role_name = "ecs-task-role" + + custom_role_policy_arns = [ + "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role", + module.iam_policy_ecs_task_role_s3.arn, + ] + number_of_custom_role_policy_arns = 2 + trusted_role_services = [ + "ecs-tasks.amazonaws.com" + ] + role_requires_mfa = false +} \ No newline at end of file diff --git a/apps/infrastructure/src/modules/cms/iam_user.tf b/apps/infrastructure/src/modules/cms/iam_user.tf new file mode 100644 index 0000000000..c394938cb8 --- /dev/null +++ b/apps/infrastructure/src/modules/cms/iam_user.tf @@ -0,0 +1,9 @@ +## IAM User Strapi with Access and Secret Key for CMS Strapi +module "iam_user_cms" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-user?ref=f37809108f86d8fbdf17f735df734bf4abe69315" # v5.34.0 + + name = "strapi" + create_iam_user_login_profile = false + create_iam_access_key = true + policy_arns = [module.iam_policy_cms.arn] +} diff --git a/apps/infrastructure/src/modules/cms/providers.tf b/apps/infrastructure/src/modules/cms/providers.tf new file mode 100644 index 0000000000..680b132740 --- /dev/null +++ b/apps/infrastructure/src/modules/cms/providers.tf @@ -0,0 +1,10 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.33.0" + + configuration_aliases = [aws.us-east-1] + } + } +} \ No newline at end of file diff --git a/apps/infrastructure/src/rds_aurora.tf b/apps/infrastructure/src/modules/cms/rds_aurora.tf similarity index 100% rename from apps/infrastructure/src/rds_aurora.tf rename to apps/infrastructure/src/modules/cms/rds_aurora.tf diff --git a/apps/infrastructure/src/modules/cms/route53.tf b/apps/infrastructure/src/modules/cms/route53.tf new file mode 100644 index 0000000000..3455e249af --- /dev/null +++ b/apps/infrastructure/src/modules/cms/route53.tf @@ -0,0 +1,55 @@ +locals { + domain_validations_options = setunion( + module.cms_ssl_certificate.acm_certificate_domain_validation_options, + module.strapi_media_library_ssl_certificate.acm_certificate_domain_validation_options + ) +} + +resource "aws_route53_record" "certificate" { + for_each = { + for dvo in local.domain_validations_options : dvo.domain_name => { + name = dvo.resource_record_name + record = dvo.resource_record_value + type = dvo.resource_record_type + } + } + + allow_overwrite = true + name = each.value.name + records = [each.value.record] + ttl = 3600 # 1 hour + type = each.value.type + zone_id = var.hosted_zone_id +} + +# Add DNS record for CMS Strapi +module "cms_dns_records" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-route53.git//modules/records?ref=bc63328714550fd903d2574b263833c9ce1c867e" # v2.11.0" + + zone_id = var.hosted_zone_id + + records = [ + { + name = "cms" + type = "A" + alias = { + name = module.cms_load_balancer.dns_name + zone_id = module.cms_load_balancer.zone_id + evaluate_target_health = false + } + } + ] +} + +// This Route53 record will point at the Strapi Media Library CDN +resource "aws_route53_record" "strapi_media_library" { + zone_id = var.hosted_zone_id + name = format("cdn.%s", var.dns_domain_name) + type = "A" + + alias { + name = module.cloudfront_cms.cloudfront_distribution_domain_name + zone_id = module.cloudfront_cms.cloudfront_distribution_hosted_zone_id + evaluate_target_health = false + } +} diff --git a/apps/infrastructure/src/modules/cms/s3_bucket.tf b/apps/infrastructure/src/modules/cms/s3_bucket.tf new file mode 100644 index 0000000000..c39e1366a3 --- /dev/null +++ b/apps/infrastructure/src/modules/cms/s3_bucket.tf @@ -0,0 +1,23 @@ +## Bucket S3 for CMS Strapi Medialibrary +resource "random_integer" "bucket_random_integer" { + min = 1 + max = 9999 +} + +module "s3_bucket_cms" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git?ref=3a1c80b29fdf8fc682d2749456ec36ecbaf4ce14" # v4.1.0 + + bucket = "cms-medialibrary-${random_integer.bucket_random_integer.result}" + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true + + versioning = { + status = true + enabled = true + } + + attach_policy = true + policy = data.aws_iam_policy_document.s3_iam_policy_cms.json +} \ No newline at end of file diff --git a/apps/infrastructure/src/security_group.tf b/apps/infrastructure/src/modules/cms/security_group.tf similarity index 100% rename from apps/infrastructure/src/security_group.tf rename to apps/infrastructure/src/modules/cms/security_group.tf diff --git a/apps/infrastructure/src/ssm_parameter.tf b/apps/infrastructure/src/modules/cms/ssm_parameter.tf similarity index 99% rename from apps/infrastructure/src/ssm_parameter.tf rename to apps/infrastructure/src/modules/cms/ssm_parameter.tf index be97701aed..98db7755e7 100644 --- a/apps/infrastructure/src/ssm_parameter.tf +++ b/apps/infrastructure/src/modules/cms/ssm_parameter.tf @@ -83,22 +83,6 @@ module "secret_cms_transfer_token_salt" { secure_type = true } -module "secret_cms_access_key_id" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-ssm-parameter.git?ref=77d2c139784197febbc8f8e18a33d23eb4736879" # v1.1.0 - - name = "/cms/access_key_id" - value = module.iam_user_cms.iam_access_key_id - secure_type = true -} - -module "secret_cms_access_key_secret" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-ssm-parameter.git?ref=77d2c139784197febbc8f8e18a33d23eb4736879" # v1.1.0 - - name = "/cms/access_key_secret" - value = module.iam_user_cms.iam_access_key_secret - secure_type = true -} - resource "random_password" "cms_github_pat" { length = 16 special = true @@ -141,3 +125,19 @@ module "secret_cms_google_gsuite_hd" { # Ignore changes to value, because the value is updated manually ignore_value_changes = "true" } + +module "secret_cms_access_key_id" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-ssm-parameter.git?ref=77d2c139784197febbc8f8e18a33d23eb4736879" # v1.1.0 + + name = "/cms/access_key_id" + value = module.iam_user_cms.iam_access_key_id + secure_type = true +} + +module "secret_cms_access_key_secret" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-ssm-parameter.git?ref=77d2c139784197febbc8f8e18a33d23eb4736879" # v1.1.0 + + name = "/cms/access_key_secret" + value = module.iam_user_cms.iam_access_key_secret + secure_type = true +} \ No newline at end of file diff --git a/apps/infrastructure/src/task-definitions/cms_app.json.tpl b/apps/infrastructure/src/modules/cms/task-definitions/cms_app.json.tpl similarity index 100% rename from apps/infrastructure/src/task-definitions/cms_app.json.tpl rename to apps/infrastructure/src/modules/cms/task-definitions/cms_app.json.tpl diff --git a/apps/infrastructure/src/modules/cms/variables.tf b/apps/infrastructure/src/modules/cms/variables.tf new file mode 100644 index 0000000000..cb6442fe15 --- /dev/null +++ b/apps/infrastructure/src/modules/cms/variables.tf @@ -0,0 +1,57 @@ +variable "aws_region" { + type = string + description = "AWS region to create resources. Default Milan" + default = "eu-south-1" +} + +variable "environment" { + type = string + description = "Environment" +} + +variable "github_repository" { + type = string + description = "The repository where the IaC workflows will run" +} + +variable "tags" { + type = map(any) + default = { + CreatedBy = "Terraform" + } +} + +variable "dns_domain_name" { + description = "DNS domain for the Developer Portal product" + type = string +} + +## CMS Strapi App Port +variable "cms_app_port" { + description = "The standard app port used by CMS Strapi" + default = 1337 +} + +## CMS Strapi CPU +variable "cms_app_cpu" { + description = "Fargate instance CPU units to provision (1 vCPU = 1024 CPU units)" + default = "1024" ##### 1 vCPU +} + +## CMS Strapi RAM +variable "cms_app_memory" { + description = "Fargate instance memory to provision (in MiB)" + default = "3072" ##### 3 GB RAM +} + +# CMS Strapi DNS +variable "dns_domain_name_cms" { + description = "DNS domain name of the Developer Portal's CMS" + type = map(any) + default = null +} + +variable "hosted_zone_id" { + type = string + description = "The ID of the hosted zone to create the public DNS records in" +} \ No newline at end of file diff --git a/apps/infrastructure/src/vpc.tf b/apps/infrastructure/src/modules/cms/vpc.tf similarity index 100% rename from apps/infrastructure/src/vpc.tf rename to apps/infrastructure/src/modules/cms/vpc.tf diff --git a/apps/infrastructure/src/iam_group.tf b/apps/infrastructure/src/modules/core/iam_group.tf similarity index 100% rename from apps/infrastructure/src/iam_group.tf rename to apps/infrastructure/src/modules/core/iam_group.tf diff --git a/apps/infrastructure/src/iam_user.tf b/apps/infrastructure/src/modules/core/iam_user.tf similarity index 60% rename from apps/infrastructure/src/iam_user.tf rename to apps/infrastructure/src/modules/core/iam_user.tf index e1cb622500..955030ba41 100644 --- a/apps/infrastructure/src/iam_user.tf +++ b/apps/infrastructure/src/modules/core/iam_user.tf @@ -16,14 +16,4 @@ resource "aws_iam_user" "mauro_dandrea" { resource "aws_iam_user_policy_attachment" "change_password" { user = aws_iam_user.mauro_dandrea.name policy_arn = "arn:aws:iam::aws:policy/IAMUserChangePassword" -} - -## IAM User Strapi with Access and Secret Key for CMS Strapi -module "iam_user_cms" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-user?ref=f37809108f86d8fbdf17f735df734bf4abe69315" # v5.34.0 - - name = "strapi" - create_iam_user_login_profile = false - create_iam_access_key = true - policy_arns = [module.iam_policy_cms.arn] -} +} \ No newline at end of file diff --git a/apps/infrastructure/src/modules/core/outputs.tf b/apps/infrastructure/src/modules/core/outputs.tf new file mode 100644 index 0000000000..a218aebabd --- /dev/null +++ b/apps/infrastructure/src/modules/core/outputs.tf @@ -0,0 +1,12 @@ + +output "name_servers_records" { + value = aws_route53_zone.dev_portal.name_servers +} + +output "hosted_zone_id" { + value = aws_route53_zone.dev_portal.zone_id +} + +output "ses_domain_identity_arn" { + value = module.ses_developer_pagopa_it.ses_domain_identity_arn +} \ No newline at end of file diff --git a/apps/infrastructure/src/modules/core/providers.tf b/apps/infrastructure/src/modules/core/providers.tf new file mode 100644 index 0000000000..9fddf689ff --- /dev/null +++ b/apps/infrastructure/src/modules/core/providers.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.33.0" + } + } +} \ No newline at end of file diff --git a/apps/infrastructure/src/modules/core/route53.tf b/apps/infrastructure/src/modules/core/route53.tf new file mode 100644 index 0000000000..625dee680a --- /dev/null +++ b/apps/infrastructure/src/modules/core/route53.tf @@ -0,0 +1,83 @@ +resource "aws_route53_zone" "dev_portal" { + name = var.dns_domain_name +} + +# Delegation +resource "aws_route53_record" "devportal_delegate" { + for_each = var.dns_delegate_records + + allow_overwrite = true + name = each.key + ttl = 3600 + type = "NS" + zone_id = aws_route53_zone.dev_portal.zone_id + + records = each.value +} + +// TODO: Once the Terraform module will be fixed, we can remove these two dkim records +// TXT Record SES will use to validate that a message was not forged or altered in transit +resource "aws_route53_record" "devportal_ses_dkim_txt" { + name = module.ses_developer_pagopa_it.verification_token.name + type = "TXT" + zone_id = aws_route53_zone.dev_portal.zone_id + records = [module.ses_developer_pagopa_it.verification_token.value] + ttl = 3600 +} + +// CNAME Record SES will use to validate that a message was not forged or altered in transit +resource "aws_route53_record" "devportal_ses_dkim_cname" { + count = 3 + + zone_id = aws_route53_zone.dev_portal.zone_id + name = module.ses_developer_pagopa_it.dkim_tokens[count.index].name + type = "CNAME" + ttl = 3600 + records = [module.ses_developer_pagopa_it.dkim_tokens[count.index].value] +} + +resource "aws_route53_record" "devportal_google_site_verification_txt" { + count = var.environment == "prod" ? 1 : 0 + + name = "" + type = "TXT" + zone_id = aws_route53_zone.dev_portal.zone_id + records = ["google-site-verification=Z94dFrXZD0YqP-r5BY5ODb4NsbQBAggTGRZM9fNtOj0"] + ttl = 3600 +} + +# Active Campaign Records +module "active_campaign_dns_records" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-route53.git//modules/records?ref=bc63328714550fd903d2574b263833c9ce1c867e" # v2.11.0" + + zone_id = aws_route53_zone.dev_portal.id + # Create only on production environment + create = var.environment == "prod" + + records = [ + { + name = "acdkim1._domainkey" + type = "CNAME" + records = ["dkim.acdkim1.acems1.com"] + ttl = 3600 + }, + { + name = "acdkim2._domainkey" + type = "CNAME" + records = ["dkim.acdkim2.acems1.com"] + ttl = 3600 + }, + { + name = "em-3628291" + type = "CNAME" + records = ["cmd.emsend1.com"] + ttl = 3600 + }, + { + name = "_dmarc" + type = "TXT" + records = ["v=DMARC1;p=none;"] + ttl = 3600 + } + ] +} \ No newline at end of file diff --git a/apps/infrastructure/src/ses.tf b/apps/infrastructure/src/modules/core/ses.tf similarity index 100% rename from apps/infrastructure/src/ses.tf rename to apps/infrastructure/src/modules/core/ses.tf diff --git a/apps/infrastructure/src/modules/core/variables.tf b/apps/infrastructure/src/modules/core/variables.tf new file mode 100644 index 0000000000..6917a6ccc8 --- /dev/null +++ b/apps/infrastructure/src/modules/core/variables.tf @@ -0,0 +1,28 @@ +variable "aws_region" { + type = string + description = "AWS region to create resources. Default Milan" + default = "eu-south-1" +} + +variable "environment" { + type = string + description = "Environment" +} + +variable "tags" { + type = map(any) + default = { + CreatedBy = "Terraform" + } +} + +variable "dns_domain_name" { + description = "DNS domain for the Developer Portal product" + type = string +} + +variable "dns_delegate_records" { + type = map(any) + description = "DNS delegate records" + default = {} +} diff --git a/apps/infrastructure/src/modules/website/acm.tf b/apps/infrastructure/src/modules/website/acm.tf new file mode 100644 index 0000000000..26f409f5d7 --- /dev/null +++ b/apps/infrastructure/src/modules/website/acm.tf @@ -0,0 +1,24 @@ +resource "aws_acm_certificate" "website" { + domain_name = var.dns_domain_name + validation_method = "DNS" + subject_alternative_names = [format("www.%s", var.dns_domain_name)] + + lifecycle { + create_before_destroy = true + } + + # TLS certificate generated in us-east because it is related to the CDN which is a global resource + provider = aws.us-east-1 +} + +resource "aws_acm_certificate" "auth" { + domain_name = format("auth.%s", var.dns_domain_name) + validation_method = "DNS" + + lifecycle { + create_before_destroy = true + } + + # TLS certificate generated in us-east because it is related to the CDN which is a global resource + provider = aws.us-east-1 +} \ No newline at end of file diff --git a/apps/infrastructure/src/cloudfront.tf b/apps/infrastructure/src/modules/website/cloudfront.tf similarity index 73% rename from apps/infrastructure/src/cloudfront.tf rename to apps/infrastructure/src/modules/website/cloudfront.tf index 066cf42046..f9d68acfd2 100644 --- a/apps/infrastructure/src/cloudfront.tf +++ b/apps/infrastructure/src/modules/website/cloudfront.tf @@ -46,7 +46,7 @@ resource "aws_cloudfront_function" "website_viewer_request_handler" { runtime = "cloudfront-js-1.0" # publish this version only if the env is true publish = var.publish_cloudfront_functions - code = file("${path.module}/../../cloudfront-functions/dist/viewer-request-handler.js") + code = file("${path.root}/../../cloudfront-functions/dist/viewer-request-handler.js") } ## Static website CDN @@ -110,58 +110,4 @@ resource "aws_cloudfront_distribution" "website" { acm_certificate_arn = var.use_custom_certificate ? aws_acm_certificate.website.arn : null ssl_support_method = var.use_custom_certificate ? "sni-only" : null } -} - -## CDN to Media Library for CMS Strapi -module "cloudfront_cms" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-cloudfront.git?ref=ed0f1f983f606304e00ad9f48399bd2fe0b79233" # v3.2.2 - - create_origin_access_identity = true - origin_access_identities = { - s3_cms = "Identity to access S3 bucket" - } - - origin = { - s3_one = { - domain_name = module.s3_bucket_cms.s3_bucket_bucket_regional_domain_name - s3_origin_config = { - origin_access_identity = "s3_cms" - } - } - } - - enabled = true - is_ipv6_enabled = true - comment = "CloudFront distribution for the CMS Media Library" - - viewer_certificate = { - cloudfront_default_certificate = false - acm_certificate_arn = module.strapi_media_library_ssl_certificate.acm_certificate_arn - ssl_support_method = "sni-only" - minimum_protocol_version = "TLSv1.2_2021" - } - - aliases = module.strapi_media_library_ssl_certificate.distinct_domain_names - - default_cache_behavior = { - allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] - cached_methods = ["GET", "HEAD", "OPTIONS"] - target_origin_id = "s3_one" - viewer_protocol_policy = "redirect-to-https" - min_ttl = 0 # min time for objects to live in the distribution cache - default_ttl = 3600 # default time for objects to live in the distribution cache - max_ttl = 86400 # max time for objects to live in the distribution cache - - forwarded_values = { - query_string = false - headers = [] - cookies = { - forward = "none" - } - } - } - - geo_restriction = { - restriction_type = "none" - } -} +} \ No newline at end of file diff --git a/apps/infrastructure/src/cloudwatch_dashboard.tf b/apps/infrastructure/src/modules/website/cloudwatch_dashboard.tf similarity index 100% rename from apps/infrastructure/src/cloudwatch_dashboard.tf rename to apps/infrastructure/src/modules/website/cloudwatch_dashboard.tf diff --git a/apps/infrastructure/src/cloudwatch_metric_alarm.tf b/apps/infrastructure/src/modules/website/cloudwatch_metric_alarm.tf similarity index 100% rename from apps/infrastructure/src/cloudwatch_metric_alarm.tf rename to apps/infrastructure/src/modules/website/cloudwatch_metric_alarm.tf diff --git a/apps/infrastructure/src/cognito_identity.tf b/apps/infrastructure/src/modules/website/cognito_identity.tf similarity index 100% rename from apps/infrastructure/src/cognito_identity.tf rename to apps/infrastructure/src/modules/website/cognito_identity.tf diff --git a/apps/infrastructure/src/cognito_user.tf b/apps/infrastructure/src/modules/website/cognito_user.tf similarity index 98% rename from apps/infrastructure/src/cognito_user.tf rename to apps/infrastructure/src/modules/website/cognito_user.tf index aa949e8bd3..d5d22a20fc 100644 --- a/apps/infrastructure/src/cognito_user.tf +++ b/apps/infrastructure/src/modules/website/cognito_user.tf @@ -45,7 +45,7 @@ resource "aws_cognito_user_pool" "devportal" { email_configuration { email_sending_account = "DEVELOPER" from_email_address = local.from_email_address - source_arn = module.ses_developer_pagopa_it.ses_domain_identity_arn + source_arn = var.ses_domain_identity_arn } verification_message_template { diff --git a/apps/infrastructure/src/dynamodb.tf b/apps/infrastructure/src/modules/website/dynamodb.tf similarity index 100% rename from apps/infrastructure/src/dynamodb.tf rename to apps/infrastructure/src/modules/website/dynamodb.tf diff --git a/apps/infrastructure/src/modules/website/iam_policy.tf b/apps/infrastructure/src/modules/website/iam_policy.tf new file mode 100644 index 0000000000..234703992e --- /dev/null +++ b/apps/infrastructure/src/modules/website/iam_policy.tf @@ -0,0 +1,110 @@ +data "aws_caller_identity" "current" {} + +data "aws_iam_policy_document" "deploy_github" { + statement { + effect = "Allow" + actions = ["sts:AssumeRoleWithWebIdentity"] + principals { + type = "Federated" + identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/token.actions.githubusercontent.com"] + } + + condition { + test = "StringLike" + variable = "token.actions.githubusercontent.com:sub" + values = ["repo:${var.github_repository}:*"] + } + + condition { + test = "ForAllValues:StringEquals" + variable = "token.actions.githubusercontent.com:iss" + values = ["https://token.actions.githubusercontent.com"] + } + + condition { + test = "ForAllValues:StringEquals" + variable = "token.actions.githubusercontent.com:aud" + values = ["sts.amazonaws.com"] + } + } +} + +resource "aws_iam_policy" "deploy_website" { + name = "DeployWebsite" + description = "Policy to allow to deploy the website" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "s3:PutObject", + "s3:GetObject", + "s3:PutObjectAcl", + "s3:DeleteObject" + ] + Effect = "Allow" + Resource = [ + format("%s/*", aws_s3_bucket.website.arn) + ] + }, + { + Action = [ + "s3:ListBucket" + ] + Effect = "Allow" + Resource = [ + aws_s3_bucket.website.arn + ] + }, + { + Action = [ + "cloudfront:CreateInvalidation" + ] + Effect = "Allow" + Resource = [ + aws_cloudfront_distribution.website.arn + ] + } + ] + }) +} + +data "aws_iam_policy_document" "website_iam_policy" { + statement { + actions = ["s3:GetObject", "s3:ListBucket"] + resources = [ + aws_s3_bucket.website.arn, + "${aws_s3_bucket.website.arn}/*" + ] + + principals { + type = "AWS" + identifiers = [aws_cloudfront_origin_access_identity.main.iam_arn] + } + } +} + +data "aws_iam_policy_document" "authenticated_users_policy" { + statement { + effect = "Allow" + actions = ["sts:AssumeRoleWithWebIdentity"] + + principals { + type = "Federated" + identifiers = ["cognito-identity.amazonaws.com"] + } + + condition { + test = "StringEquals" + variable = "cognito-identity.amazonaws.com:aud" + values = [aws_cognito_identity_pool.devportal.id] + } + + condition { + test = "ForAnyValue:StringLike" + variable = "cognito-identity.amazonaws.com:amr" + values = ["authenticated"] + } + } +} diff --git a/apps/infrastructure/src/iam_role.tf b/apps/infrastructure/src/modules/website/iam_role.tf similarity index 54% rename from apps/infrastructure/src/iam_role.tf rename to apps/infrastructure/src/modules/website/iam_role.tf index 7526f564de..a9f2cb6042 100644 --- a/apps/infrastructure/src/iam_role.tf +++ b/apps/infrastructure/src/modules/website/iam_role.tf @@ -12,61 +12,6 @@ resource "aws_iam_role_policy_attachment" "deploy_website" { policy_arn = aws_iam_policy.deploy_website.arn } -############################################################################### -# Define IAM Role to use on strapi deploy # -############################################################################### -resource "aws_iam_role" "deploy_cms" { - name = "GitHubActionDeployCms" - description = "Role to assume to deploy the cms" - assume_role_policy = data.aws_iam_policy_document.deploy_github.json -} - -resource "aws_iam_role_policy_attachment" "deploy_cms" { - role = aws_iam_role.deploy_cms.name - policy_arn = aws_iam_policy.deploy_cms.arn -} - -############################################################################### -# IAM Role used by task execution agent # -############################################################################### -module "iam_role_ecs_task_execution" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-assumable-role?ref=f37809108f86d8fbdf17f735df734bf4abe69315" # v5.34.0 - - create_role = true - role_name = "ecs-task-execution-role" - - custom_role_policy_arns = [ - "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy", - "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", - module.iam_policy_ecs_task_execution.arn, - ] - number_of_custom_role_policy_arns = 3 - trusted_role_services = [ - "ecs-tasks.amazonaws.com" - ] - role_requires_mfa = false -} - -############################################################################### -# IAM Role used by strapi # -############################################################################### -module "iam_role_task_role" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-assumable-role?ref=f37809108f86d8fbdf17f735df734bf4abe69315" # v5.34.0 - - create_role = true - role_name = "ecs-task-role" - - custom_role_policy_arns = [ - "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role", - module.iam_policy_ecs_task_role_s3.arn, - ] - number_of_custom_role_policy_arns = 2 - trusted_role_services = [ - "ecs-tasks.amazonaws.com" - ] - role_requires_mfa = false -} - ############################################################################### # Define IAM Role to use on Cognito users # ############################################################################### diff --git a/apps/infrastructure/src/lambda.tf b/apps/infrastructure/src/modules/website/lambda.tf similarity index 97% rename from apps/infrastructure/src/lambda.tf rename to apps/infrastructure/src/modules/website/lambda.tf index d23f7f85d8..12e249cc8c 100644 --- a/apps/infrastructure/src/lambda.tf +++ b/apps/infrastructure/src/modules/website/lambda.tf @@ -56,7 +56,7 @@ module "cognito_post_confirmation_function" { ses = { effect = "Allow", actions = ["ses:SendEmail", "ses:SendRawEmail"], - resources = [module.ses_developer_pagopa_it.ses_domain_identity_arn] + resources = [var.ses_domain_identity_arn] }, } @@ -113,7 +113,7 @@ module "cognito_create_auth_challenge_function" { ses = { effect = "Allow", actions = ["ses:SendEmail", "ses:SendRawEmail"], - resources = [module.ses_developer_pagopa_it.ses_domain_identity_arn] + resources = [var.ses_domain_identity_arn] }, } diff --git a/apps/infrastructure/src/modules/website/outputs.tf b/apps/infrastructure/src/modules/website/outputs.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/infrastructure/src/modules/website/providers.tf b/apps/infrastructure/src/modules/website/providers.tf new file mode 100644 index 0000000000..680b132740 --- /dev/null +++ b/apps/infrastructure/src/modules/website/providers.tf @@ -0,0 +1,10 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.33.0" + + configuration_aliases = [aws.us-east-1] + } + } +} \ No newline at end of file diff --git a/apps/infrastructure/src/modules/website/route53.tf b/apps/infrastructure/src/modules/website/route53.tf new file mode 100644 index 0000000000..341141f37b --- /dev/null +++ b/apps/infrastructure/src/modules/website/route53.tf @@ -0,0 +1,61 @@ +locals { + domain_validations_options = setunion( + aws_acm_certificate.website.domain_validation_options, + aws_acm_certificate.auth.domain_validation_options + ) +} + +resource "aws_route53_record" "certificate" { + for_each = { + for dvo in local.domain_validations_options : dvo.domain_name => { + name = dvo.resource_record_name + record = dvo.resource_record_value + type = dvo.resource_record_type + } + } + + allow_overwrite = true + name = each.value.name + records = [each.value.record] + ttl = 3600 # 1 hour + type = each.value.type + zone_id = var.hosted_zone_id +} + +// This Route53 record will point at our CloudFront distribution. +resource "aws_route53_record" "www_website" { + zone_id = var.hosted_zone_id + name = format("www.%s", var.dns_domain_name) + type = "A" + + alias { + name = aws_cloudfront_distribution.website.domain_name + zone_id = aws_cloudfront_distribution.website.hosted_zone_id + evaluate_target_health = false + } +} + +resource "aws_route53_record" "website" { + zone_id = var.hosted_zone_id + name = var.dns_domain_name + type = "A" + + alias { + name = aws_route53_record.www_website.name + zone_id = aws_route53_record.www_website.zone_id + evaluate_target_health = false + } +} + +// This Route53 record point to Cognito UI. +resource "aws_route53_record" "devportal_cognito_A" { + name = aws_cognito_user_pool_domain.devportal.domain + type = "A" + zone_id = var.hosted_zone_id + alias { + evaluate_target_health = false + + name = aws_cognito_user_pool_domain.devportal.cloudfront_distribution + zone_id = aws_cognito_user_pool_domain.devportal.cloudfront_distribution_zone_id + } +} diff --git a/apps/infrastructure/src/s3_bucket.tf b/apps/infrastructure/src/modules/website/s3_bucket.tf similarity index 63% rename from apps/infrastructure/src/s3_bucket.tf rename to apps/infrastructure/src/modules/website/s3_bucket.tf index bd244e79b0..bd35f0aa3b 100644 --- a/apps/infrastructure/src/s3_bucket.tf +++ b/apps/infrastructure/src/modules/website/s3_bucket.tf @@ -46,28 +46,4 @@ resource "aws_s3_bucket_lifecycle_configuration" "website" { resource "aws_s3_bucket_policy" "cloudfront" { bucket = aws_s3_bucket.website.id policy = data.aws_iam_policy_document.website_iam_policy.json -} - -## Bucket S3 for CMS Strapi Medialibrary -resource "random_integer" "bucket_random_integer" { - min = 1 - max = 9999 -} - -module "s3_bucket_cms" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git?ref=3a1c80b29fdf8fc682d2749456ec36ecbaf4ce14" # v4.1.0 - - bucket = "cms-medialibrary-${random_integer.bucket_random_integer.result}" - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true - - versioning = { - status = true - enabled = true - } - - attach_policy = true - policy = data.aws_iam_policy_document.s3_iam_policy_cms.json -} +} \ No newline at end of file diff --git a/apps/infrastructure/src/sns_topic.tf b/apps/infrastructure/src/modules/website/sns_topic.tf similarity index 100% rename from apps/infrastructure/src/sns_topic.tf rename to apps/infrastructure/src/modules/website/sns_topic.tf diff --git a/apps/infrastructure/src/modules/website/variables.tf b/apps/infrastructure/src/modules/website/variables.tf new file mode 100644 index 0000000000..af6aaae379 --- /dev/null +++ b/apps/infrastructure/src/modules/website/variables.tf @@ -0,0 +1,72 @@ +variable "aws_region" { + type = string + description = "AWS region to create resources. Default Milan" + default = "eu-south-1" +} + +variable "environment" { + type = string + description = "Environment" +} + +variable "github_repository" { + type = string + description = "The repository where the IaC workflows will run" +} + +variable "tags" { + type = map(any) + default = { + CreatedBy = "Terraform" + } +} + +variable "cdn_custom_headers" { + type = list(object( + { + header = string + override = bool + value = string + } + )) + default = [] +} + +variable "publish_cloudfront_functions" { + type = bool + description = "Defines if cloudfront functions should be published" + default = false +} + +variable "dns_domain_name" { + description = "DNS domain for the Developer Portal product" + type = string +} + +variable "dns_delegate_records" { + type = map(any) + description = "DNS delegate records" + default = {} +} + +variable "use_custom_certificate" { + type = bool + description = "Enable CDN https support with a custom certificate instead using the default one" + default = true +} + +variable "log_retention_days" { + type = number + description = "The number of days logs should be retained. Default is 90 days." + default = 90 +} + +variable "hosted_zone_id" { + type = string + description = "The ID of the hosted zone to create the public DNS records in" +} + +variable "ses_domain_identity_arn" { + type = string + description = "The ARN of the SES domain identity" +} \ No newline at end of file diff --git a/apps/infrastructure/src/moved.tf b/apps/infrastructure/src/moved.tf new file mode 100644 index 0000000000..192c2d8a0b --- /dev/null +++ b/apps/infrastructure/src/moved.tf @@ -0,0 +1,1185 @@ + +moved { + from = aws_acm_certificate.auth + to = module.website.aws_acm_certificate.auth +} + +moved { + from = aws_acm_certificate.website + to = module.website.aws_acm_certificate.website +} + +moved { + from = aws_cloudfront_distribution.website + to = module.website.aws_cloudfront_distribution.website +} + +moved { + from = aws_cloudfront_function.website_viewer_request_handler + to = module.website.aws_cloudfront_function.website_viewer_request_handler +} + +moved { + from = aws_cloudfront_origin_access_identity.main + to = module.website.aws_cloudfront_origin_access_identity.main +} + +moved { + from = aws_cloudfront_response_headers_policy.websites + to = module.website.aws_cloudfront_response_headers_policy.websites +} + +moved { + from = aws_cloudwatch_dashboard.main + to = module.website.aws_cloudwatch_dashboard.main +} + +moved { + from = aws_cognito_identity_pool.devportal + to = module.website.aws_cognito_identity_pool.devportal +} + +moved { + from = aws_cognito_identity_pool_roles_attachment.main + to = module.website.aws_cognito_identity_pool_roles_attachment.main +} + +moved { + from = aws_cognito_user_group.hosts + to = module.website.aws_cognito_user_group.hosts +} + +moved { + from = aws_cognito_user_pool.devportal + to = module.website.aws_cognito_user_pool.devportal +} + +moved { + from = aws_cognito_user_pool_client.devportal_website + to = module.website.aws_cognito_user_pool_client.devportal_website +} + +moved { + from = aws_cognito_user_pool_domain.devportal + to = module.website.aws_cognito_user_pool_domain.devportal +} + +moved { + from = aws_ecs_task_definition.cms_task_def + to = module.cms.aws_ecs_task_definition.cms_task_def +} + +moved { + from = aws_iam_group.developers_read_only + to = module.core.aws_iam_group.developers_read_only +} + +moved { + from = aws_iam_group_membership.dgs + to = module.core.aws_iam_group_membership.dgs +} + +moved { + from = aws_iam_group_policy_attachment.read_only + to = module.core.aws_iam_group_policy_attachment.read_only +} + +moved { + from = aws_iam_policy.deploy_cms + to = module.cms.aws_iam_policy.deploy_cms +} + +moved { + from = aws_iam_policy.deploy_website + to = module.website.aws_iam_policy.deploy_website +} + +moved { + from = aws_iam_role.deploy_cms + to = module.cms.aws_iam_role.deploy_cms +} + +moved { + from = aws_iam_role.deploy_website + to = module.website.aws_iam_role.deploy_website +} + +moved { + from = aws_iam_role.devportal_authenticated_host_user + to = module.website.aws_iam_role.devportal_authenticated_host_user +} + +moved { + from = aws_iam_role.devportal_authenticated_user + to = module.website.aws_iam_role.devportal_authenticated_user +} + +moved { + from = aws_iam_role_policy.devportal_authenticated_host_user + to = module.website.aws_iam_role_policy.devportal_authenticated_host_user +} + +moved { + from = aws_iam_role_policy.devportal_authenticated_user + to = module.website.aws_iam_role_policy.devportal_authenticated_user +} + +moved { + from = aws_iam_role_policy_attachment.deploy_cms + to = module.cms.aws_iam_role_policy_attachment.deploy_cms +} + +moved { + from = aws_iam_role_policy_attachment.deploy_website + to = module.website.aws_iam_role_policy_attachment.deploy_website +} + +moved { + from = aws_iam_user.mauro_dandrea + to = module.core.aws_iam_user.mauro_dandrea +} + +moved { + from = aws_iam_user_policy_attachment.change_password + to = module.core.aws_iam_user_policy_attachment.change_password +} + +moved { + from = aws_route53_record.certificate["auth.dev.developer.pagopa.it"] + to = module.website.aws_route53_record.certificate["auth.dev.developer.pagopa.it"] +} + +moved { + from = aws_route53_record.certificate["dev.developer.pagopa.it"] + to = module.website.aws_route53_record.certificate["dev.developer.pagopa.it"] +} + +moved { + from = aws_route53_record.certificate["www.dev.developer.pagopa.it"] + to = module.website.aws_route53_record.certificate["www.dev.developer.pagopa.it"] +} + +moved { + from = aws_route53_record.certificate["auth.developer.pagopa.it"] + to = module.website.aws_route53_record.certificate["auth.developer.pagopa.it"] +} + +moved { + from = aws_route53_record.certificate["developer.pagopa.it"] + to = module.website.aws_route53_record.certificate["developer.pagopa.it"] +} + +moved { + from = aws_route53_record.certificate["www.developer.pagopa.it"] + to = module.website.aws_route53_record.certificate["www.developer.pagopa.it"] +} + +moved { + from = aws_route53_record.devportal_cognito_A + to = module.website.aws_route53_record.devportal_cognito_A +} + +moved { + from = aws_route53_record.devportal_ses_dkim_cname[0] + to = module.core.aws_route53_record.devportal_ses_dkim_cname[0] +} + +moved { + from = aws_route53_record.devportal_ses_dkim_cname[1] + to = module.core.aws_route53_record.devportal_ses_dkim_cname[1] +} + +moved { + from = aws_route53_record.devportal_ses_dkim_cname[2] + to = module.core.aws_route53_record.devportal_ses_dkim_cname[2] +} + +moved { + from = aws_route53_record.devportal_ses_dkim_txt + to = module.core.aws_route53_record.devportal_ses_dkim_txt +} + +moved { + from = aws_route53_record.strapi_media_library + to = module.cms.aws_route53_record.strapi_media_library +} + +moved { + from = aws_route53_record.website + to = module.website.aws_route53_record.website +} + +moved { + from = aws_route53_record.www_website + to = module.website.aws_route53_record.www_website +} + +moved { + from = aws_route53_zone.dev_portal + to = module.core.aws_route53_zone.dev_portal +} + +moved { + from = aws_s3_bucket.website + to = module.website.aws_s3_bucket.website +} + +moved { + from = aws_s3_bucket_lifecycle_configuration.website + to = module.website.aws_s3_bucket_lifecycle_configuration.website +} + +moved { + from = aws_s3_bucket_policy.cloudfront + to = module.website.aws_s3_bucket_policy.cloudfront +} + +moved { + from = aws_s3_bucket_public_access_block.website + to = module.website.aws_s3_bucket_public_access_block.website +} + +moved { + from = aws_s3_bucket_versioning.website + to = module.website.aws_s3_bucket_versioning.website +} + +moved { + from = aws_security_group.cms_database + to = module.cms.aws_security_group.cms_database +} + +moved { + from = aws_security_group.cms_lb + to = module.cms.aws_security_group.cms_lb +} + +moved { + from = aws_security_group.ecs_tasks + to = module.cms.aws_security_group.ecs_tasks +} + +moved { + from = aws_sns_topic.metric_alarm + to = module.website.aws_sns_topic.metric_alarm +} + +moved { + from = aws_sns_topic_subscription.metric_alarm + to = module.website.aws_sns_topic_subscription.metric_alarm +} + +moved { + from = random_integer.bucket_random_integer + to = module.cms.random_integer.bucket_random_integer +} + +moved { + from = random_integer.website_bucket_random_integer + to = module.website.random_integer.website_bucket_random_integer +} + +moved { + from = random_password.cms_admin_jwt_secret + to = module.cms.random_password.cms_admin_jwt_secret +} + +moved { + from = random_password.cms_api_token_salt + to = module.cms.random_password.cms_api_token_salt +} + +moved { + from = random_password.cms_app_keys + to = module.cms.random_password.cms_app_keys +} + +moved { + from = random_password.cms_database_password + to = module.cms.random_password.cms_database_password +} + +moved { + from = random_password.cms_github_pat + to = module.cms.random_password.cms_github_pat +} + +moved { + from = random_password.cms_jwt_secret + to = module.cms.random_password.cms_jwt_secret +} + +moved { + from = random_password.cms_transfer_token_salt + to = module.cms.random_password.cms_transfer_token_salt +} + +moved { + from = module.cloudfront_5xx_error_rate_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cloudfront_5xx_error_rate_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cloudfront_cms.aws_cloudfront_distribution.this[0] + to = module.cms.module.cloudfront_cms.aws_cloudfront_distribution.this[0] +} + +moved { + from = module.cloudfront_cms.aws_cloudfront_origin_access_identity.this["s3_cms"] + to = module.cms.module.cloudfront_cms.aws_cloudfront_origin_access_identity.this["s3_cms"] +} + +moved { + from = module.cloudfront_function_execution_errors_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cloudfront_function_execution_errors_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cloudfront_function_throttled_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cloudfront_function_throttled_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cloudfront_function_validation_errors_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cloudfront_function_validation_errors_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cloudfront_origin_latency_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cloudfront_origin_latency_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cms_ecs_cluster.aws_cloudwatch_log_group.this[0] + to = module.cms.module.cms_ecs_cluster.aws_cloudwatch_log_group.this[0] +} + +moved { + from = module.cms_ecs_cluster.aws_ecs_cluster.this[0] + to = module.cms.module.cms_ecs_cluster.aws_ecs_cluster.this[0] +} + +moved { + from = module.cms_ecs_service.aws_appautoscaling_policy.this["cpu"] + to = module.cms.module.cms_ecs_service.aws_appautoscaling_policy.this["cpu"] +} + +moved { + from = module.cms_ecs_service.aws_appautoscaling_policy.this["memory"] + to = module.cms.module.cms_ecs_service.aws_appautoscaling_policy.this["memory"] +} + +moved { + from = module.cms_ecs_service.aws_appautoscaling_target.this[0] + to = module.cms.module.cms_ecs_service.aws_appautoscaling_target.this[0] +} + +moved { + from = module.cms_ecs_service.aws_ecs_service.ignore_task_definition[0] + to = module.cms.module.cms_ecs_service.aws_ecs_service.ignore_task_definition[0] +} + +moved { + from = module.cms_load_balancer.aws_lb.this[0] + to = module.cms.module.cms_load_balancer.aws_lb.this[0] +} + +moved { + from = module.cms_load_balancer.aws_lb_listener.this["front_end_http"] + to = module.cms.module.cms_load_balancer.aws_lb_listener.this["front_end_http"] +} + +moved { + from = module.cms_load_balancer.aws_lb_listener.this["front_end_https"] + to = module.cms.module.cms_load_balancer.aws_lb_listener.this["front_end_https"] +} + +moved { + from = module.cms_load_balancer.aws_lb_target_group.this["cms-target-group"] + to = module.cms.module.cms_load_balancer.aws_lb_target_group.this["cms-target-group"] +} + +moved { + from = module.cms_log_group.aws_cloudwatch_log_group.this[0] + to = module.cms.module.cms_log_group.aws_cloudwatch_log_group.this[0] +} + +moved { + from = module.cms_rds.aws_rds_cluster.this[0] + to = module.cms.module.cms_rds.aws_rds_cluster.this[0] +} + +moved { + from = module.cms_rds.aws_rds_cluster_instance.this["one"] + to = module.cms.module.cms_rds.aws_rds_cluster_instance.this["one"] +} + +moved { + from = module.cms_rds.aws_security_group.this[0] + to = module.cms.module.cms_rds.aws_security_group.this[0] +} + +moved { + from = module.cms_ssl_certificate.aws_acm_certificate.this[0] + to = module.cms.module.cms_ssl_certificate.aws_acm_certificate.this[0] +} + +moved { + from = module.cms_ssl_certificate.aws_route53_record.validation[0] + to = module.cms.module.cms_ssl_certificate.aws_route53_record.validation[0] +} + +moved { + from = module.cms_ssl_certificate.aws_route53_record.validation[1] + to = module.cms.module.cms_ssl_certificate.aws_route53_record.validation[1] +} + +moved { + from = module.cognito_create_auth_challenge_function.aws_cloudwatch_log_group.lambda[0] + to = module.website.module.cognito_create_auth_challenge_function.aws_cloudwatch_log_group.lambda[0] +} + +moved { + from = module.cognito_create_auth_challenge_function.aws_iam_policy.additional_inline[0] + to = module.website.module.cognito_create_auth_challenge_function.aws_iam_policy.additional_inline[0] +} + +moved { + from = module.cognito_create_auth_challenge_function.aws_iam_policy.logs[0] + to = module.website.module.cognito_create_auth_challenge_function.aws_iam_policy.logs[0] +} + +moved { + from = module.cognito_create_auth_challenge_function.aws_iam_role.lambda[0] + to = module.website.module.cognito_create_auth_challenge_function.aws_iam_role.lambda[0] +} + +moved { + from = module.cognito_create_auth_challenge_function.aws_iam_role_policy_attachment.additional_inline[0] + to = module.website.module.cognito_create_auth_challenge_function.aws_iam_role_policy_attachment.additional_inline[0] +} + +moved { + from = module.cognito_create_auth_challenge_function.aws_iam_role_policy_attachment.logs[0] + to = module.website.module.cognito_create_auth_challenge_function.aws_iam_role_policy_attachment.logs[0] +} + +moved { + from = module.cognito_create_auth_challenge_function.aws_lambda_function.this[0] + to = module.website.module.cognito_create_auth_challenge_function.aws_lambda_function.this[0] +} + +moved { + from = module.cognito_create_auth_challenge_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] + to = module.website.module.cognito_create_auth_challenge_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] +} + +moved { + from = module.cognito_create_auth_challenge_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_create_auth_challenge_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_create_auth_challenge_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_create_auth_challenge_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_create_auth_challenge_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_create_auth_challenge_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_create_auth_challenge_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_create_auth_challenge_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_custom_message_function.aws_cloudwatch_log_group.lambda[0] + to = module.website.module.cognito_custom_message_function.aws_cloudwatch_log_group.lambda[0] +} + +moved { + from = module.cognito_custom_message_function.aws_iam_policy.logs[0] + to = module.website.module.cognito_custom_message_function.aws_iam_policy.logs[0] +} + +moved { + from = module.cognito_custom_message_function.aws_iam_role.lambda[0] + to = module.website.module.cognito_custom_message_function.aws_iam_role.lambda[0] +} + +moved { + from = module.cognito_custom_message_function.aws_iam_role_policy_attachment.logs[0] + to = module.website.module.cognito_custom_message_function.aws_iam_role_policy_attachment.logs[0] +} + +moved { + from = module.cognito_custom_message_function.aws_lambda_function.this[0] + to = module.website.module.cognito_custom_message_function.aws_lambda_function.this[0] +} + +moved { + from = module.cognito_custom_message_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] + to = module.website.module.cognito_custom_message_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] +} + +moved { + from = module.cognito_custom_message_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_custom_message_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_custom_message_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_custom_message_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_custom_message_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_custom_message_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_custom_message_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_custom_message_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_define_auth_challenge_function.aws_cloudwatch_log_group.lambda[0] + to = module.website.module.cognito_define_auth_challenge_function.aws_cloudwatch_log_group.lambda[0] +} + +moved { + from = module.cognito_define_auth_challenge_function.aws_iam_policy.logs[0] + to = module.website.module.cognito_define_auth_challenge_function.aws_iam_policy.logs[0] +} + +moved { + from = module.cognito_define_auth_challenge_function.aws_iam_role.lambda[0] + to = module.website.module.cognito_define_auth_challenge_function.aws_iam_role.lambda[0] +} + +moved { + from = module.cognito_define_auth_challenge_function.aws_iam_role_policy_attachment.logs[0] + to = module.website.module.cognito_define_auth_challenge_function.aws_iam_role_policy_attachment.logs[0] +} + +moved { + from = module.cognito_define_auth_challenge_function.aws_lambda_function.this[0] + to = module.website.module.cognito_define_auth_challenge_function.aws_lambda_function.this[0] +} + +moved { + from = module.cognito_define_auth_challenge_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] + to = module.website.module.cognito_define_auth_challenge_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] +} + +moved { + from = module.cognito_define_auth_challenge_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_define_auth_challenge_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_define_auth_challenge_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_define_auth_challenge_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_define_auth_challenge_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_define_auth_challenge_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_define_auth_challenge_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_define_auth_challenge_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_post_confirmation_function.aws_cloudwatch_log_group.lambda[0] + to = module.website.module.cognito_post_confirmation_function.aws_cloudwatch_log_group.lambda[0] +} + +moved { + from = module.cognito_post_confirmation_function.aws_iam_policy.additional_inline[0] + to = module.website.module.cognito_post_confirmation_function.aws_iam_policy.additional_inline[0] +} + +moved { + from = module.cognito_post_confirmation_function.aws_iam_policy.logs[0] + to = module.website.module.cognito_post_confirmation_function.aws_iam_policy.logs[0] +} + +moved { + from = module.cognito_post_confirmation_function.aws_iam_role.lambda[0] + to = module.website.module.cognito_post_confirmation_function.aws_iam_role.lambda[0] +} + +moved { + from = module.cognito_post_confirmation_function.aws_iam_role_policy_attachment.additional_inline[0] + to = module.website.module.cognito_post_confirmation_function.aws_iam_role_policy_attachment.additional_inline[0] +} + +moved { + from = module.cognito_post_confirmation_function.aws_iam_role_policy_attachment.logs[0] + to = module.website.module.cognito_post_confirmation_function.aws_iam_role_policy_attachment.logs[0] +} + +moved { + from = module.cognito_post_confirmation_function.aws_lambda_function.this[0] + to = module.website.module.cognito_post_confirmation_function.aws_lambda_function.this[0] +} + +moved { + from = module.cognito_post_confirmation_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] + to = module.website.module.cognito_post_confirmation_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] +} + +moved { + from = module.cognito_post_confirmation_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_post_confirmation_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_post_confirmation_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_post_confirmation_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_post_confirmation_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_post_confirmation_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_post_confirmation_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_post_confirmation_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_user_pool_sign_in_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_user_pool_sign_in_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_user_pool_sign_up_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_user_pool_sign_up_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_user_pool_token_refresh_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_user_pool_token_refresh_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_verify_auth_challenge_function.aws_cloudwatch_log_group.lambda[0] + to = module.website.module.cognito_verify_auth_challenge_function.aws_cloudwatch_log_group.lambda[0] +} + +moved { + from = module.cognito_verify_auth_challenge_function.aws_iam_policy.logs[0] + to = module.website.module.cognito_verify_auth_challenge_function.aws_iam_policy.logs[0] +} + +moved { + from = module.cognito_verify_auth_challenge_function.aws_iam_role.lambda[0] + to = module.website.module.cognito_verify_auth_challenge_function.aws_iam_role.lambda[0] +} + +moved { + from = module.cognito_verify_auth_challenge_function.aws_iam_role_policy_attachment.logs[0] + to = module.website.module.cognito_verify_auth_challenge_function.aws_iam_role_policy_attachment.logs[0] +} + +moved { + from = module.cognito_verify_auth_challenge_function.aws_lambda_function.this[0] + to = module.website.module.cognito_verify_auth_challenge_function.aws_lambda_function.this[0] +} + +moved { + from = module.cognito_verify_auth_challenge_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] + to = module.website.module.cognito_verify_auth_challenge_function.aws_lambda_permission.unqualified_alias_triggers["cognito_devportal"] +} + +moved { + from = module.cognito_verify_auth_challenge_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_verify_auth_challenge_lambda_concurrent_executions_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_verify_auth_challenge_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_verify_auth_challenge_lambda_duration_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_verify_auth_challenge_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_verify_auth_challenge_lambda_errors_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.cognito_verify_auth_challenge_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.cognito_verify_auth_challenge_lambda_throttles_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.dynamodb_read_capacity_utilization_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.dynamodb_read_capacity_utilization_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.dynamodb_read_throttle_events_webinar_questions_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.dynamodb_read_throttle_events_webinar_questions_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.dynamodb_successful_request_latency_put_item_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.dynamodb_successful_request_latency_put_item_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.dynamodb_successful_request_latency_query_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.dynamodb_successful_request_latency_query_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.dynamodb_system_errors_webinar_questions_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.dynamodb_system_errors_webinar_questions_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.dynamodb_user_errors_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.dynamodb_user_errors_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.dynamodb_webinar_questions.aws_dynamodb_table.this[0] + to = module.website.module.dynamodb_webinar_questions.aws_dynamodb_table.this[0] +} + +moved { + from = module.dynamodb_webinar_subscriptions.aws_dynamodb_table.this[0] + to = module.website.module.dynamodb_webinar_subscriptions.aws_dynamodb_table.this[0] +} + +moved { + from = module.dynamodb_write_capacity_utilization_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.dynamodb_write_capacity_utilization_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.dynamodb_write_throttle_events_webinar_questions_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.dynamodb_write_throttle_events_webinar_questions_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.ecr.aws_ecr_lifecycle_policy.this[0] + to = module.cms.module.ecr.aws_ecr_lifecycle_policy.this[0] +} + +moved { + from = module.ecr.aws_ecr_repository.this[0] + to = module.cms.module.ecr.aws_ecr_repository.this[0] +} + +moved { + from = module.ecr.aws_ecr_repository_policy.this[0] + to = module.cms.module.ecr.aws_ecr_repository_policy.this[0] +} + +moved { + from = module.iam_policy_cms.aws_iam_policy.policy[0] + to = module.cms.module.iam_policy_cms.aws_iam_policy.policy[0] +} + +moved { + from = module.iam_policy_ecs_task_execution.aws_iam_policy.policy[0] + to = module.cms.module.iam_policy_ecs_task_execution.aws_iam_policy.policy[0] +} + +moved { + from = module.iam_policy_ecs_task_role_s3.aws_iam_policy.policy[0] + to = module.cms.module.iam_policy_ecs_task_role_s3.aws_iam_policy.policy[0] +} + +moved { + from = module.iam_role_ecs_task_execution.aws_iam_role.this[0] + to = module.cms.module.iam_role_ecs_task_execution.aws_iam_role.this[0] +} + +moved { + from = module.iam_role_ecs_task_execution.aws_iam_role_policy_attachment.custom[0] + to = module.cms.module.iam_role_ecs_task_execution.aws_iam_role_policy_attachment.custom[0] +} + +moved { + from = module.iam_role_ecs_task_execution.aws_iam_role_policy_attachment.custom[1] + to = module.cms.module.iam_role_ecs_task_execution.aws_iam_role_policy_attachment.custom[1] +} + +moved { + from = module.iam_role_ecs_task_execution.aws_iam_role_policy_attachment.custom[2] + to = module.cms.module.iam_role_ecs_task_execution.aws_iam_role_policy_attachment.custom[2] +} + +moved { + from = module.iam_role_task_role.aws_iam_role.this[0] + to = module.cms.module.iam_role_task_role.aws_iam_role.this[0] +} + +moved { + from = module.iam_role_task_role.aws_iam_role_policy_attachment.custom[0] + to = module.cms.module.iam_role_task_role.aws_iam_role_policy_attachment.custom[0] +} + +moved { + from = module.iam_role_task_role.aws_iam_role_policy_attachment.custom[1] + to = module.cms.module.iam_role_task_role.aws_iam_role_policy_attachment.custom[1] +} + +moved { + from = module.iam_user_cms.aws_iam_access_key.this_no_pgp[0] + to = module.cms.module.iam_user_cms.aws_iam_access_key.this_no_pgp[0] +} + +moved { + from = module.iam_user_cms.aws_iam_user.this[0] + to = module.cms.module.iam_user_cms.aws_iam_user.this[0] +} + +moved { + from = module.iam_user_cms.aws_iam_user_policy_attachment.this["0"] + to = module.cms.module.iam_user_cms.aws_iam_user_policy_attachment.this["0"] +} + +moved { + from = module.s3_bucket_cms.aws_s3_bucket.this[0] + to = module.cms.module.s3_bucket_cms.aws_s3_bucket.this[0] +} + +moved { + from = module.s3_bucket_cms.aws_s3_bucket_policy.this[0] + to = module.cms.module.s3_bucket_cms.aws_s3_bucket_policy.this[0] +} + +moved { + from = module.s3_bucket_cms.aws_s3_bucket_public_access_block.this[0] + to = module.cms.module.s3_bucket_cms.aws_s3_bucket_public_access_block.this[0] +} + +moved { + from = module.s3_bucket_cms.aws_s3_bucket_versioning.this[0] + to = module.cms.module.s3_bucket_cms.aws_s3_bucket_versioning.this[0] +} + +moved { + from = module.secret_cms_access_key_id.aws_ssm_parameter.this[0] + to = module.cms.module.secret_cms_access_key_id.aws_ssm_parameter.this[0] +} + +moved { + from = module.secret_cms_access_key_secret.aws_ssm_parameter.this[0] + to = module.cms.module.secret_cms_access_key_secret.aws_ssm_parameter.this[0] +} + +moved { + from = module.secret_cms_admin_jwt_secret.aws_ssm_parameter.this[0] + to = module.cms.module.secret_cms_admin_jwt_secret.aws_ssm_parameter.this[0] +} + +moved { + from = module.secret_cms_api_token_salt.aws_ssm_parameter.this[0] + to = module.cms.module.secret_cms_api_token_salt.aws_ssm_parameter.this[0] +} + +moved { + from = module.secret_cms_app_keys.aws_ssm_parameter.this[0] + to = module.cms.module.secret_cms_app_keys.aws_ssm_parameter.this[0] +} + +moved { + from = module.secret_cms_database_password.aws_ssm_parameter.this[0] + to = module.cms.module.secret_cms_database_password.aws_ssm_parameter.this[0] +} + +moved { + from = module.secret_cms_github_pat.aws_ssm_parameter.ignore_value[0] + to = module.cms.module.secret_cms_github_pat.aws_ssm_parameter.ignore_value[0] +} + +moved { + from = module.secret_cms_google_gsuite_hd.aws_ssm_parameter.ignore_value[0] + to = module.cms.module.secret_cms_google_gsuite_hd.aws_ssm_parameter.ignore_value[0] +} + +moved { + from = module.secret_cms_google_oauth_client_id.aws_ssm_parameter.ignore_value[0] + to = module.cms.module.secret_cms_google_oauth_client_id.aws_ssm_parameter.ignore_value[0] +} + +moved { + from = module.secret_cms_google_oauth_client_secret.aws_ssm_parameter.ignore_value[0] + to = module.cms.module.secret_cms_google_oauth_client_secret.aws_ssm_parameter.ignore_value[0] +} + +moved { + from = module.secret_cms_jwt_secret.aws_ssm_parameter.this[0] + to = module.cms.module.secret_cms_jwt_secret.aws_ssm_parameter.this[0] +} + +moved { + from = module.secret_cms_transfer_token_salt.aws_ssm_parameter.this[0] + to = module.cms.module.secret_cms_transfer_token_salt.aws_ssm_parameter.this[0] +} + +moved { + from = module.ses_bounce_rate_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.ses_bounce_rate_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.ses_daily_sending_quota_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.ses_daily_sending_quota_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.ses_developer_pagopa_it.aws_iam_access_key.ses_user[0] + to = module.core.module.ses_developer_pagopa_it.aws_iam_access_key.ses_user[0] +} + +moved { + from = module.ses_developer_pagopa_it.aws_iam_group.ses_users[0] + to = module.core.module.ses_developer_pagopa_it.aws_iam_group.ses_users[0] +} + +moved { + from = module.ses_developer_pagopa_it.aws_iam_group_membership.ses_group[0] + to = module.core.module.ses_developer_pagopa_it.aws_iam_group_membership.ses_group[0] +} + +moved { + from = module.ses_developer_pagopa_it.aws_iam_group_policy.ses_group_policy[0] + to = module.core.module.ses_developer_pagopa_it.aws_iam_group_policy.ses_group_policy[0] +} + +moved { + from = module.ses_developer_pagopa_it.aws_iam_user.ses_user[0] + to = module.core.module.ses_developer_pagopa_it.aws_iam_user.ses_user[0] +} + +moved { + from = module.ses_developer_pagopa_it.aws_ses_domain_dkim.this[0] + to = module.core.module.ses_developer_pagopa_it.aws_ses_domain_dkim.this[0] +} + +moved { + from = module.ses_developer_pagopa_it.aws_ses_domain_identity.this + to = module.core.module.ses_developer_pagopa_it.aws_ses_domain_identity.this +} + +moved { + from = module.ses_reputation_complaint_rate_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.ses_reputation_complaint_rate_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.ses_sending_rate_limit_alarm.aws_cloudwatch_metric_alarm.this[0] + to = module.website.module.ses_sending_rate_limit_alarm.aws_cloudwatch_metric_alarm.this[0] +} + +moved { + from = module.strapi_media_library_ssl_certificate.aws_acm_certificate.this[0] + to = module.cms.module.strapi_media_library_ssl_certificate.aws_acm_certificate.this[0] +} + +moved { + from = module.strapi_media_library_ssl_certificate.aws_route53_record.validation[0] + to = module.cms.module.strapi_media_library_ssl_certificate.aws_route53_record.validation[0] +} + +moved { + from = module.vpc.aws_db_subnet_group.database[0] + to = module.cms.module.vpc.aws_db_subnet_group.database[0] +} + +moved { + from = module.vpc.aws_default_network_acl.this[0] + to = module.cms.module.vpc.aws_default_network_acl.this[0] +} + +moved { + from = module.vpc.aws_default_route_table.default[0] + to = module.cms.module.vpc.aws_default_route_table.default[0] +} + +moved { + from = module.vpc.aws_default_security_group.this[0] + to = module.cms.module.vpc.aws_default_security_group.this[0] +} + +moved { + from = module.vpc.aws_eip.nat[0] + to = module.cms.module.vpc.aws_eip.nat[0] +} + +moved { + from = module.vpc.aws_internet_gateway.this[0] + to = module.cms.module.vpc.aws_internet_gateway.this[0] +} + +moved { + from = module.vpc.aws_nat_gateway.this[0] + to = module.cms.module.vpc.aws_nat_gateway.this[0] +} + +moved { + from = module.vpc.aws_network_acl.public[0] + to = module.cms.module.vpc.aws_network_acl.public[0] +} + +moved { + from = module.vpc.aws_network_acl_rule.public_inbound[0] + to = module.cms.module.vpc.aws_network_acl_rule.public_inbound[0] +} + +moved { + from = module.vpc.aws_network_acl_rule.public_outbound[0] + to = module.cms.module.vpc.aws_network_acl_rule.public_outbound[0] +} + +moved { + from = module.vpc.aws_route.private_nat_gateway[0] + to = module.cms.module.vpc.aws_route.private_nat_gateway[0] +} + +moved { + from = module.vpc.aws_route.public_internet_gateway[0] + to = module.cms.module.vpc.aws_route.public_internet_gateway[0] +} + +moved { + from = module.vpc.aws_route_table.private[0] + to = module.cms.module.vpc.aws_route_table.private[0] +} + +moved { + from = module.vpc.aws_route_table.public[0] + to = module.cms.module.vpc.aws_route_table.public[0] +} + +moved { + from = module.vpc.aws_route_table_association.database[0] + to = module.cms.module.vpc.aws_route_table_association.database[0] +} + +moved { + from = module.vpc.aws_route_table_association.database[1] + to = module.cms.module.vpc.aws_route_table_association.database[1] +} + +moved { + from = module.vpc.aws_route_table_association.database[2] + to = module.cms.module.vpc.aws_route_table_association.database[2] +} + +moved { + from = module.vpc.aws_route_table_association.private[0] + to = module.cms.module.vpc.aws_route_table_association.private[0] +} + +moved { + from = module.vpc.aws_route_table_association.private[1] + to = module.cms.module.vpc.aws_route_table_association.private[1] +} + +moved { + from = module.vpc.aws_route_table_association.private[2] + to = module.cms.module.vpc.aws_route_table_association.private[2] +} + +moved { + from = module.vpc.aws_route_table_association.public[0] + to = module.cms.module.vpc.aws_route_table_association.public[0] +} + +moved { + from = module.vpc.aws_route_table_association.public[1] + to = module.cms.module.vpc.aws_route_table_association.public[1] +} + +moved { + from = module.vpc.aws_route_table_association.public[2] + to = module.cms.module.vpc.aws_route_table_association.public[2] +} + +moved { + from = module.vpc.aws_subnet.database[0] + to = module.cms.module.vpc.aws_subnet.database[0] +} + +moved { + from = module.vpc.aws_subnet.database[1] + to = module.cms.module.vpc.aws_subnet.database[1] +} + +moved { + from = module.vpc.aws_subnet.database[2] + to = module.cms.module.vpc.aws_subnet.database[2] +} + +moved { + from = module.vpc.aws_subnet.private[0] + to = module.cms.module.vpc.aws_subnet.private[0] +} + +moved { + from = module.vpc.aws_subnet.private[1] + to = module.cms.module.vpc.aws_subnet.private[1] +} + +moved { + from = module.vpc.aws_subnet.private[2] + to = module.cms.module.vpc.aws_subnet.private[2] +} + +moved { + from = module.vpc.aws_subnet.public[0] + to = module.cms.module.vpc.aws_subnet.public[0] +} + +moved { + from = module.vpc.aws_subnet.public[1] + to = module.cms.module.vpc.aws_subnet.public[1] +} + +moved { + from = module.vpc.aws_subnet.public[2] + to = module.cms.module.vpc.aws_subnet.public[2] +} + +moved { + from = module.vpc.aws_vpc.this[0] + to = module.cms.module.vpc.aws_vpc.this[0] +} + +moved { + from = aws_route53_record.certificate + to = module.cms.aws_route53_record.certificate +} + +moved { + from = module.cms_dns_records.aws_route53_record.this + to = module.cms.module.cms_dns_records.aws_route53_record.this +} + +moved { + from = aws_route53_record.devportal_delegate + to = module.core.aws_route53_record.devportal_delegate +} + +moved { + from = aws_route53_record.devportal_google_site_verification_txt + to = module.core.aws_route53_record.devportal_google_site_verification_txt +} + +moved { + from = module.active_campaign_dns_records.aws_route53_record.this + to = module.core.module.active_campaign_dns_records.aws_route53_record.this +} \ No newline at end of file diff --git a/apps/infrastructure/src/outputs.tf b/apps/infrastructure/src/outputs.tf index 74ea42a267..ece683a564 100644 --- a/apps/infrastructure/src/outputs.tf +++ b/apps/infrastructure/src/outputs.tf @@ -7,5 +7,5 @@ output "terraform_lock_dynamodb_table" { } output "name_servers_records" { - value = aws_route53_zone.dev_portal.name_servers -} + value = module.core.name_servers_records +} \ No newline at end of file diff --git a/apps/infrastructure/src/route53.tf b/apps/infrastructure/src/route53.tf deleted file mode 100644 index 4101fab192..0000000000 --- a/apps/infrastructure/src/route53.tf +++ /dev/null @@ -1,179 +0,0 @@ -resource "aws_route53_zone" "dev_portal" { - name = var.dns_domain_name -} - -# Delegation -resource "aws_route53_record" "devportal_delegate" { - for_each = var.dns_delegate_records - - allow_overwrite = true - name = each.key - ttl = 3600 - type = "NS" - zone_id = aws_route53_zone.dev_portal.zone_id - - records = each.value -} - -locals { - domain_validations_options = setunion( - aws_acm_certificate.website.domain_validation_options, - aws_acm_certificate.auth.domain_validation_options, - module.cms_ssl_certificate.acm_certificate_domain_validation_options, - module.strapi_media_library_ssl_certificate.acm_certificate_domain_validation_options - ) -} - -resource "aws_route53_record" "certificate" { - for_each = { - for dvo in local.domain_validations_options : dvo.domain_name => { - name = dvo.resource_record_name - record = dvo.resource_record_value - type = dvo.resource_record_type - } - } - - allow_overwrite = true - name = each.value.name - records = [each.value.record] - ttl = 3600 # 1 hour - type = each.value.type - zone_id = aws_route53_zone.dev_portal.zone_id -} - -// This Route53 record will point at our CloudFront distribution. -resource "aws_route53_record" "www_website" { - zone_id = aws_route53_zone.dev_portal.zone_id - name = format("www.%s", var.dns_domain_name) - type = "A" - - alias { - name = aws_cloudfront_distribution.website.domain_name - zone_id = aws_cloudfront_distribution.website.hosted_zone_id - evaluate_target_health = false - } -} - -resource "aws_route53_record" "website" { - zone_id = aws_route53_zone.dev_portal.zone_id - name = var.dns_domain_name - type = "A" - - alias { - name = aws_route53_record.www_website.name - zone_id = aws_route53_record.www_website.zone_id - evaluate_target_health = false - } -} - -// This Route53 record point to Cognito UI. -resource "aws_route53_record" "devportal_cognito_A" { - name = aws_cognito_user_pool_domain.devportal.domain - type = "A" - zone_id = aws_route53_zone.dev_portal.zone_id - alias { - evaluate_target_health = false - - name = aws_cognito_user_pool_domain.devportal.cloudfront_distribution - zone_id = aws_cognito_user_pool_domain.devportal.cloudfront_distribution_zone_id - } -} - -// TODO: Once the Terraform module will be fixed, we can remove these two dkim records -// TXT Record SES will use to validate that a message was not forged or altered in transit -resource "aws_route53_record" "devportal_ses_dkim_txt" { - name = module.ses_developer_pagopa_it.verification_token.name - type = "TXT" - zone_id = aws_route53_zone.dev_portal.zone_id - records = [module.ses_developer_pagopa_it.verification_token.value] - ttl = 3600 -} - -// CNAME Record SES will use to validate that a message was not forged or altered in transit -resource "aws_route53_record" "devportal_ses_dkim_cname" { - count = 3 - - zone_id = aws_route53_zone.dev_portal.zone_id - name = module.ses_developer_pagopa_it.dkim_tokens[count.index].name - type = "CNAME" - ttl = 3600 - records = [module.ses_developer_pagopa_it.dkim_tokens[count.index].value] -} - -resource "aws_route53_record" "devportal_google_site_verification_txt" { - count = var.environment == "prod" ? 1 : 0 - - name = "" - type = "TXT" - zone_id = aws_route53_zone.dev_portal.zone_id - records = ["google-site-verification=Z94dFrXZD0YqP-r5BY5ODb4NsbQBAggTGRZM9fNtOj0"] - ttl = 3600 -} - -# Add DNS record for CMS Strapi -module "cms_dns_records" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-route53.git//modules/records?ref=bc63328714550fd903d2574b263833c9ce1c867e" # v2.11.0" - - zone_id = aws_route53_zone.dev_portal.id - - records = [ - { - name = "cms" - type = "A" - alias = { - name = module.cms_load_balancer.dns_name - zone_id = module.cms_load_balancer.zone_id - evaluate_target_health = false - } - } - ] -} - -# Active Campaign Records -module "active_campaign_dns_records" { - source = "git::https://github.com/terraform-aws-modules/terraform-aws-route53.git//modules/records?ref=bc63328714550fd903d2574b263833c9ce1c867e" # v2.11.0" - - zone_id = aws_route53_zone.dev_portal.id - # Create only on production environment - create = var.environment == "prod" - - records = [ - { - name = "acdkim1._domainkey" - type = "CNAME" - records = ["dkim.acdkim1.acems1.com"] - ttl = 3600 - }, - { - name = "acdkim2._domainkey" - type = "CNAME" - records = ["dkim.acdkim2.acems1.com"] - ttl = 3600 - }, - { - name = "em-3628291" - type = "CNAME" - records = ["cmd.emsend1.com"] - ttl = 3600 - }, - { - name = "_dmarc" - type = "TXT" - records = ["v=DMARC1;p=none;"] - ttl = 3600 - } - ] -} - -// This Route53 record will point at the Strapi Media Library CDN -resource "aws_route53_record" "strapi_media_library" { - zone_id = aws_route53_zone.dev_portal.zone_id - name = format("cdn.%s", var.dns_domain_name) - type = "A" - - alias { - name = module.cloudfront_cms.cloudfront_distribution_domain_name - zone_id = module.cloudfront_cms.cloudfront_distribution_hosted_zone_id - evaluate_target_health = false - } -}