diff --git a/.github/workflows/_lint-terraform.yml b/.github/workflows/_lint-terraform.yml index 9be75524b3..2395ddf792 100644 --- a/.github/workflows/_lint-terraform.yml +++ b/.github/workflows/_lint-terraform.yml @@ -24,7 +24,7 @@ jobs: - uses: hashicorp/setup-terraform@e192cfcbae6c6ed207c277ed7624131996c9bf13 # pin@v2.0.0 with: - terraform_version: 1.2.4 + terraform_version: 1.5.6 - name: configure AWS credentials for terraform uses: aws-actions/configure-aws-credentials@375a690dc0af3921541e5f427167f333d7e85f67 # pin@v1.7.0 diff --git a/.github/workflows/_run-terraform.yml b/.github/workflows/_run-terraform.yml index e793a818f2..bce314cb7f 100644 --- a/.github/workflows/_run-terraform.yml +++ b/.github/workflows/_run-terraform.yml @@ -66,7 +66,7 @@ jobs: - uses: hashicorp/setup-terraform@e192cfcbae6c6ed207c277ed7624131996c9bf13 # pin@v2.0.0 with: - terraform_version: 1.2.4 + terraform_version: 1.5.6 - name: configure AWS credentials for getting pagerduty token uses: aws-actions/configure-aws-credentials@375a690dc0af3921541e5f427167f333d7e85f67 # pin@v1.7.0 diff --git a/.github/workflows/pull-request-path.yml b/.github/workflows/pull-request-path.yml index 93dfc2a4af..46679379fe 100644 --- a/.github/workflows/pull-request-path.yml +++ b/.github/workflows/pull-request-path.yml @@ -130,6 +130,7 @@ jobs: uses: ./.github/workflows/_run-terraform.yml needs: - terraform_lint + - workflow_variables with: workspace: development terraform_path: account @@ -161,6 +162,27 @@ jobs: needs.docker_build_scan_push.result == 'success' && needs.workflow_variables.result == 'success' + terraform_preproduction_plan_environment: + name: terraform apply environment + uses: ./.github/workflows/_run-terraform.yml + needs: + - docker_build_scan_push + - terraform_lint + - workflow_variables + with: + workspace: preproduction + terraform_path: environment + container_version: main-${{ needs.workflow_variables.outputs.short_sha }} + apply: false + specific_path: all + add_ttl: false + secrets: inherit + if: | + always() && + needs.terraform_lint.result == 'success' && + needs.docker_build_scan_push.result == 'success' && + needs.workflow_variables.result == 'success' + seed_dynamodb: name: seed dynamodb uses: ./.github/workflows/_seed-database.yml @@ -228,7 +250,7 @@ jobs: always() && needs.code_coverage.result == 'success' && needs.terraform_apply_environment.result == 'success' - + # Required end of workflow job end_of_workflow: name: end of workflow diff --git a/.github/workflows/scheduled-workspace-cleanup.yml b/.github/workflows/scheduled-workspace-cleanup.yml index 2eabf31877..98aefacfdf 100644 --- a/.github/workflows/scheduled-workspace-cleanup.yml +++ b/.github/workflows/scheduled-workspace-cleanup.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@f095bcc56b7c2baf48f3ac70d6d6782f4f553222 # pin@v3 - uses: hashicorp/setup-terraform@e192cfcbae6c6ed207c277ed7624131996c9bf13 # pin@v2 with: - terraform_version: 1.2.4 + terraform_version: 1.5.6 terraform_wrapper: false - uses: webfactory/ssh-agent@d4b9b8ff72958532804b70bbe600ad43b36d5f2e # pin@v0.5.4 diff --git a/terraform/account/.tfswitchrc b/terraform/account/.tfswitchrc index e8ea05db81..eac1e0ada6 100644 --- a/terraform/account/.tfswitchrc +++ b/terraform/account/.tfswitchrc @@ -1 +1 @@ -1.2.4 +1.5.6 diff --git a/terraform/environment/.tfswitchrc b/terraform/environment/.tfswitchrc index e8ea05db81..eac1e0ada6 100644 --- a/terraform/environment/.tfswitchrc +++ b/terraform/environment/.tfswitchrc @@ -1 +1 @@ -1.2.4 +1.5.6 diff --git a/terraform/environment/autoscaling.tf b/terraform/environment/autoscaling.tf index 74883aad37..3afb5d6b6e 100644 --- a/terraform/environment/autoscaling.tf +++ b/terraform/environment/autoscaling.tf @@ -1,8 +1,8 @@ module "view_ecs_autoscaling" { source = "./modules/ecs_autoscaling" environment = local.environment_name - aws_ecs_cluster_name = aws_ecs_cluster.use-an-lpa.name - aws_ecs_service_name = aws_ecs_service.viewer.name + aws_ecs_cluster_name = module.eu_west_1.ecs_cluster.name + aws_ecs_service_name = module.eu_west_1.ecs_services.viewer.name ecs_autoscaling_service_role_arn = data.aws_iam_role.ecs_autoscaling_service_role.arn ecs_task_autoscaling_minimum = local.environment.autoscaling.view.minimum ecs_task_autoscaling_maximum = local.environment.autoscaling.view.maximum @@ -11,8 +11,8 @@ module "view_ecs_autoscaling" { module "use_ecs_autoscaling" { source = "./modules/ecs_autoscaling" environment = local.environment_name - aws_ecs_cluster_name = aws_ecs_cluster.use-an-lpa.name - aws_ecs_service_name = aws_ecs_service.actor.name + aws_ecs_cluster_name = module.eu_west_1.ecs_cluster.name + aws_ecs_service_name = module.eu_west_1.ecs_services.actor.name ecs_autoscaling_service_role_arn = data.aws_iam_role.ecs_autoscaling_service_role.arn ecs_task_autoscaling_minimum = local.environment.autoscaling.use.minimum ecs_task_autoscaling_maximum = local.environment.autoscaling.use.maximum @@ -21,8 +21,8 @@ module "use_ecs_autoscaling" { module "api_ecs_autoscaling" { source = "./modules/ecs_autoscaling" environment = local.environment_name - aws_ecs_cluster_name = aws_ecs_cluster.use-an-lpa.name - aws_ecs_service_name = aws_ecs_service.api.name + aws_ecs_cluster_name = module.eu_west_1.ecs_cluster.name + aws_ecs_service_name = module.eu_west_1.ecs_services.api.name ecs_autoscaling_service_role_arn = data.aws_iam_role.ecs_autoscaling_service_role.arn ecs_task_autoscaling_minimum = local.environment.autoscaling.api.minimum ecs_task_autoscaling_maximum = local.environment.autoscaling.api.maximum @@ -31,8 +31,8 @@ module "api_ecs_autoscaling" { module "pdf_ecs_autoscaling" { source = "./modules/ecs_autoscaling" environment = local.environment_name - aws_ecs_cluster_name = aws_ecs_cluster.use-an-lpa.name - aws_ecs_service_name = aws_ecs_service.pdf.name + aws_ecs_cluster_name = module.eu_west_1.ecs_cluster.name + aws_ecs_service_name = module.eu_west_1.ecs_services.pdf.name ecs_autoscaling_service_role_arn = data.aws_iam_role.ecs_autoscaling_service_role.arn ecs_task_autoscaling_minimum = local.environment.autoscaling.pdf.minimum ecs_task_autoscaling_maximum = local.environment.autoscaling.pdf.maximum diff --git a/terraform/environment/config_file.tf b/terraform/environment/config_file.tf index 60dd440507..2b50f5f738 100644 --- a/terraform/environment/config_file.tf +++ b/terraform/environment/config_file.tf @@ -6,7 +6,7 @@ resource "local_file" "cluster_config" { locals { cluster_config = { actor_users_table = aws_dynamodb_table.actor_users_table.name - cluster_name = aws_ecs_cluster.use-an-lpa.name + cluster_name = module.eu_west_1.ecs_cluster.name account_id = local.environment.account_id actor_lpa_codes_table = aws_dynamodb_table.actor_codes_table.name viewer_codes_table = aws_dynamodb_table.viewer_codes_table.name diff --git a/terraform/environment/outputs.tf b/terraform/environment/outputs.tf new file mode 100644 index 0000000000..58d69732b3 --- /dev/null +++ b/terraform/environment/outputs.tf @@ -0,0 +1,3 @@ +output "admin_domain" { + value = module.eu_west_1.admin_domain +} \ No newline at end of file diff --git a/terraform/environment/refactor.tf b/terraform/environment/refactor.tf new file mode 100644 index 0000000000..2337056964 --- /dev/null +++ b/terraform/environment/refactor.tf @@ -0,0 +1,179 @@ +moved { + from = aws_ecs_cluster.use-an-lpa + to = module.eu_west_1.aws_ecs_cluster.use_an_lpa +} + +moved { + from = aws_ecs_service.actor + to = module.eu_west_1.aws_ecs_service.actor +} + +moved { + from = aws_ecs_service.admin + to = module.eu_west_1.aws_ecs_service.admin +} + +moved { + from = aws_ecs_service.api + to = module.eu_west_1.aws_ecs_service.api +} + +moved { + from = aws_ecs_service.pdf + to = module.eu_west_1.aws_ecs_service.pdf +} + +moved { + from = aws_ecs_service.viewer + to = module.eu_west_1.aws_ecs_service.viewer +} + +moved { + from = aws_ecs_task_definition.actor + to = module.eu_west_1.aws_ecs_task_definition.actor +} + +moved { + from = aws_ecs_task_definition.admin + to = module.eu_west_1.aws_ecs_task_definition.admin +} + +moved { + from = aws_ecs_task_definition.api + to = module.eu_west_1.aws_ecs_task_definition.api +} + +moved { + from = aws_ecs_task_definition.pdf + to = module.eu_west_1.aws_ecs_task_definition.pdf +} + +moved { + from = aws_ecs_task_definition.viewer + to = module.eu_west_1.aws_ecs_task_definition.viewer +} + +moved { + from = aws_iam_role_policy.actor_permissions_role + to = module.eu_west_1.aws_iam_role_policy.actor_permissions_role +} + +moved { + from = aws_iam_role_policy.admin_permissions_role + to = module.eu_west_1.aws_iam_role_policy.admin_permissions_role +} + +moved { + from = aws_iam_role_policy.api_permissions_role + to = module.eu_west_1.aws_iam_role_policy.api_permissions_role +} + +moved { + from = aws_iam_role_policy.execution_role + to = module.eu_west_1.aws_iam_role_policy.execution_role +} + +moved { + from = aws_iam_role_policy.viewer_permissions_role + to = module.eu_west_1.aws_iam_role_policy.viewer_permissions_role +} + +moved { + from = aws_security_group.actor_ecs_service + to = module.eu_west_1.aws_security_group.actor_ecs_service +} + +moved { + from = aws_security_group.admin_ecs_service + to = module.eu_west_1.aws_security_group.admin_ecs_service +} + +moved { + from = aws_security_group.api_ecs_service + to = module.eu_west_1.aws_security_group.api_ecs_service +} + +moved { + from = aws_security_group.pdf_ecs_service + to = module.eu_west_1.aws_security_group.pdf_ecs_service +} + +moved { + from = aws_security_group.viewer_ecs_service + to = module.eu_west_1.aws_security_group.viewer_ecs_service +} + +moved { + from = aws_security_group_rule.actor_ecs_service_egress + to = module.eu_west_1.aws_security_group_rule.actor_ecs_service_egress +} + +moved { + from = aws_security_group_rule.actor_ecs_service_elasticache_ingress + to = module.eu_west_1.aws_security_group_rule.actor_ecs_service_elasticache_ingress +} + +moved { + from = aws_security_group_rule.actor_ecs_service_ingress + to = module.eu_west_1.aws_security_group_rule.actor_ecs_service_ingress +} + +moved { + from = aws_security_group_rule.admin_ecs_service_egress + to = module.eu_west_1.aws_security_group_rule.admin_ecs_service_egress +} + +moved { + from = aws_security_group_rule.admin_ecs_service_ingress + to = module.eu_west_1.aws_security_group_rule.admin_ecs_service_ingress +} + +moved { + from = aws_security_group_rule.api_ecs_service_actor_ingress + to = module.eu_west_1.aws_security_group_rule.api_ecs_service_actor_ingress +} + +moved { + from = aws_security_group_rule.api_ecs_service_egress + to = module.eu_west_1.aws_security_group_rule.api_ecs_service_egress +} + +moved { + from = aws_security_group_rule.api_ecs_service_viewer_ingress + to = module.eu_west_1.aws_security_group_rule.api_ecs_service_viewer_ingress +} + +moved { + from = aws_security_group_rule.pdf_ecs_service_egress + to = module.eu_west_1.aws_security_group_rule.pdf_ecs_service_egress +} + +moved { + from = aws_security_group_rule.pdf_ecs_service_viewer_ingress + to = module.eu_west_1.aws_security_group_rule.pdf_ecs_service_viewer_ingress +} + +moved { + from = aws_security_group_rule.viewer_ecs_service_egress + to = module.eu_west_1.aws_security_group_rule.viewer_ecs_service_egress +} + +moved { + from = aws_security_group_rule.viewer_ecs_service_elasticache_ingress + to = module.eu_west_1.aws_security_group_rule.viewer_ecs_service_elasticache_ingress +} + +moved { + from = aws_security_group_rule.viewer_ecs_service_ingress + to = module.eu_west_1.aws_security_group_rule.viewer_ecs_service_ingress +} + +moved { + from = aws_service_discovery_service.api_ecs + to = module.eu_west_1.aws_service_discovery_service.api_ecs +} + +moved { + from = aws_service_discovery_service.pdf_ecs + to = module.eu_west_1.aws_service_discovery_service.pdf_ecs +} diff --git a/terraform/environment/region.tf b/terraform/environment/region.tf new file mode 100644 index 0000000000..598efd5bf9 --- /dev/null +++ b/terraform/environment/region.tf @@ -0,0 +1,83 @@ +module "eu_west_1" { + source = "./region" + + alb_tg_arns = { + "actor" = aws_lb_target_group.actor + "viewer" = aws_lb_target_group.viewer + "admin" = aws_lb_target_group.admin + } + + autoscaling = local.environment.autoscaling + + application_logs_name = aws_cloudwatch_log_group.application_logs.name + + dynamodb_tables = { + "actor_codes_table" = aws_dynamodb_table.actor_codes_table + "stats_table" = aws_dynamodb_table.stats_table + "actor_users_table" = aws_dynamodb_table.actor_users_table + "viewer_codes_table" = aws_dynamodb_table.viewer_codes_table + "viewer_activity_table" = aws_dynamodb_table.viewer_activity_table + "user_lpa_actor_map" = aws_dynamodb_table.user_lpa_actor_map + } + + cognito_user_pool_id = aws_cognito_user_pool_client.use_a_lasting_power_of_attorney_admin.id + + environment_name = local.environment_name + + actor_loadbalancer_security_group_id = aws_security_group.actor_loadbalancer.id + viewer_loadbalancer_security_group_id = aws_security_group.viewer_loadbalancer.id + admin_loadbalancer_security_group_id = aws_security_group.admin_loadbalancer.id + + notify_key_secret_name = local.environment.notify_key_secret_name + + lpa_codes_endpoint = local.environment.lpa_codes_endpoint + iap_images_endpoint = local.environment.iap_images_endpoint + lpas_collection_endpoint = local.environment.lpas_collection_endpoint + + logging_level = local.environment.logging_level + + parameter_store_arns = [aws_ssm_parameter.system_message_view_en.arn, aws_ssm_parameter.system_message_view_cy.arn, aws_ssm_parameter.system_message_use_en.arn, aws_ssm_parameter.system_message_use_cy.arn, ] + route_53_fqdns = { + "public_view" = aws_route53_record.public_facing_view_lasting_power_of_attorney.fqdn + "public_use" = aws_route53_record.public_facing_use_lasting_power_of_attorney.fqdn + "admin" = aws_route53_record.admin_use_my_lpa.fqdn + } + + feature_flags = { + "allow_gov_one_login" = local.environment.application_flags.allow_gov_one_login + "instructions_and_preferences" = local.environment.application_flags.instructions_and_preferences + "dont_send_lpas_registered_after_sep_2019_to_cleansing_team" = local.environment.application_flags.dont_send_lpas_registered_after_sep_2019_to_cleansing_team + "allow_meris_lpas" = local.environment.application_flags.allow_meris_lpas + "deploy_opentelemetry_sidecar" = local.environment.deploy_opentelemetry_sidecar + "delete_lpa_feature" = local.environment.application_flags.delete_lpa_feature + } + + container_version = var.container_version + admin_container_version = var.admin_container_version + pdf_container_version = local.environment.pdf_container_version + + sirius_account_id = local.environment.sirius_account_id + + ecs_task_roles = module.iam.ecs_task_roles + ecs_execution_role = module.iam.ecs_execution_role + + admin_cognito_user_pool_domain_name = local.admin_cognito_user_pool_domain_name + + capacity_provider = local.capacity_provider + + aws_service_discovery_service = aws_service_discovery_private_dns_namespace.internal_ecs + + + session_expires_use = local.environment.session_expires_use + session_expiry_warning = local.environment.session_expiry_warning + cookie_expires_use = local.environment.cookie_expires_use + google_analytics_id_use = local.environment.google_analytics_id_use + google_analytics_id_view = local.environment.google_analytics_id_view + cookie_expires_view = local.environment.cookie_expires_view + session_expires_view = local.environment.session_expires_view + + providers = { + aws.region = aws.eu_west_1 + aws.management = aws.management + } +} \ No newline at end of file diff --git a/terraform/environment/actor_ecs.tf b/terraform/environment/region/actor_ecs.tf similarity index 76% rename from terraform/environment/actor_ecs.tf rename to terraform/environment/region/actor_ecs.tf index 36cb49705d..f3d8b16765 100644 --- a/terraform/environment/actor_ecs.tf +++ b/terraform/environment/region/actor_ecs.tf @@ -3,9 +3,9 @@ resource "aws_ecs_service" "actor" { name = "actor-service" - cluster = aws_ecs_cluster.use-an-lpa.id + cluster = aws_ecs_cluster.use_an_lpa.id task_definition = aws_ecs_task_definition.actor.arn - desired_count = local.environment.autoscaling.use.minimum + desired_count = var.autoscaling.use.minimum platform_version = "1.4.0" network_configuration { @@ -15,13 +15,13 @@ resource "aws_ecs_service" "actor" { } load_balancer { - target_group_arn = aws_lb_target_group.actor.arn + target_group_arn = var.alb_tg_arns.actor.arn container_name = "web" container_port = 80 } capacity_provider_strategy { - capacity_provider = local.capacity_provider + capacity_provider = var.capacity_provider weight = 100 } @@ -40,19 +40,21 @@ resource "aws_ecs_service" "actor" { create_before_destroy = true } - depends_on = [aws_lb.actor] + provider = aws.region } //---------------------------------- // The service's Security Groups resource "aws_security_group" "actor_ecs_service" { - name_prefix = "${local.environment_name}-actor-ecs-service" + name_prefix = "${var.environment_name}-actor-ecs-service" description = "Use service security group" vpc_id = data.aws_vpc.default.id lifecycle { create_before_destroy = true } + + provider = aws.region } // 80 in from the ELB @@ -63,10 +65,12 @@ resource "aws_security_group_rule" "actor_ecs_service_ingress" { to_port = 80 protocol = "tcp" security_group_id = aws_security_group.actor_ecs_service.id - source_security_group_id = aws_security_group.actor_loadbalancer.id + source_security_group_id = var.actor_loadbalancer_security_group_id lifecycle { create_before_destroy = true } + + provider = aws.region } // Anything out @@ -81,6 +85,8 @@ resource "aws_security_group_rule" "actor_ecs_service_egress" { lifecycle { create_before_destroy = true } + + provider = aws.region } resource "aws_security_group_rule" "actor_ecs_service_elasticache_ingress" { @@ -94,29 +100,35 @@ resource "aws_security_group_rule" "actor_ecs_service_elasticache_ingress" { lifecycle { create_before_destroy = true } + + provider = aws.region } //-------------------------------------- // Actor ECS Service Task level config resource "aws_ecs_task_definition" "actor" { - family = "${local.environment_name}-actor" + family = "${var.environment_name}-actor" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 512 memory = 1024 - container_definitions = "[${local.actor_web}, ${local.actor_app} ${local.environment.deploy_opentelemetry_sidecar ? ", ${local.actor_aws_otel_collector}" : ""}]" - task_role_arn = module.iam.ecs_task_roles.actor_task_role.arn - execution_role_arn = module.iam.ecs_execution_role.arn + container_definitions = "[${local.actor_web}, ${local.actor_app} ${var.feature_flags.deploy_opentelemetry_sidecar ? ", ${local.actor_aws_otel_collector}" : ""}]" + task_role_arn = var.ecs_task_roles.actor_task_role.arn + execution_role_arn = var.ecs_execution_role.arn + + provider = aws.region } //---------------- // Permissions resource "aws_iam_role_policy" "actor_permissions_role" { - name = "${local.environment_name}-${local.policy_region_prefix}-ActorApplicationPermissions" + name = "${var.environment_name}-${local.policy_region_prefix}-ActorApplicationPermissions" policy = data.aws_iam_policy_document.actor_permissions_role.json - role = module.iam.ecs_task_roles.actor_task_role.id + role = var.ecs_task_roles.actor_task_role.id + + provider = aws.region } /* @@ -148,6 +160,8 @@ data "aws_iam_policy_document" "actor_permissions_role" { resources = [data.aws_kms_alias.sessions_actor.target_key_arn] } + + provider = aws.region } //----------------------------------------------- @@ -172,15 +186,15 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.actor-web.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.actor-web.use-an-lpa" } }, environment = [ { name = "WEB_DOMAIN", - value = "https://${aws_route53_record.public_facing_use_lasting_power_of_attorney.fqdn}" + value = "https://${var.route_53_fqdns.public_use}" }, { name = "APP_HOST", @@ -219,9 +233,9 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.actor-otel.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.actor-otel.use-an-lpa" } }, environment = [] @@ -252,9 +266,9 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.actor-app.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.actor-app.use-an-lpa" } }, secrets = [ @@ -281,23 +295,23 @@ locals { }, { name = "SESSION_EXPIRES", - value = tostring(local.environment.session_expires_use) + value = tostring(var.session_expires_use) }, { name = "SESSION_EXPIRY_WARNING", - value = tostring(local.environment.session_expiry_warning) + value = tostring(var.session_expiry_warning) }, { name = "COOKIE_EXPIRES", - value = tostring(local.environment.cookie_expires_use) + value = tostring(var.cookie_expires_use) }, { name = "GOOGLE_ANALYTICS_ID", - value = local.environment.google_analytics_id_use + value = var.google_analytics_id_use }, { name = "LOGGING_LEVEL", - value = tostring(local.environment.logging_level) + value = tostring(var.logging_level) }, { name = "BRUTE_FORCE_CACHE_URL", @@ -313,23 +327,23 @@ locals { }, { name = "DELETE_LPA_FEATURE", - value = tostring(local.environment.application_flags.delete_lpa_feature) + value = tostring(var.feature_flags.delete_lpa_feature) }, { name = "ALLOW_MERIS_LPAS", - value = tostring(local.environment.application_flags.allow_meris_lpas) + value = tostring(var.feature_flags.allow_meris_lpas) }, { name = "DONT_SEND_LPAS_REGISTERED_AFTER_SEP_2019_TO_CLEANSING_TEAM", - value = tostring(local.environment.application_flags.dont_send_lpas_registered_after_sep_2019_to_cleansing_team) + value = tostring(var.feature_flags.dont_send_lpas_registered_after_sep_2019_to_cleansing_team) }, { name = "INSTRUCTIONS_AND_PREFERENCES", - value = tostring(local.environment.application_flags.instructions_and_preferences) + value = tostring(var.feature_flags.instructions_and_preferences) }, { name = "ALLOW_GOV_ONE_LOGIN", - value = tostring(local.environment.application_flags.allow_gov_one_login) + value = tostring(var.feature_flags.allow_gov_one_login) } ] }) diff --git a/terraform/environment/admin_ecs.tf b/terraform/environment/region/admin_ecs.tf similarity index 67% rename from terraform/environment/admin_ecs.tf rename to terraform/environment/region/admin_ecs.tf index 5ef197d8d0..c5041a1fce 100644 --- a/terraform/environment/admin_ecs.tf +++ b/terraform/environment/region/admin_ecs.tf @@ -3,7 +3,7 @@ resource "aws_ecs_service" "admin" { name = "admin-service" - cluster = aws_ecs_cluster.use-an-lpa.id + cluster = aws_ecs_cluster.use_an_lpa.id task_definition = aws_ecs_task_definition.admin.arn desired_count = 1 platform_version = "1.4.0" @@ -15,13 +15,13 @@ resource "aws_ecs_service" "admin" { } load_balancer { - target_group_arn = aws_lb_target_group.admin.arn + target_group_arn = var.alb_tg_arns.admin.arn container_name = "app" container_port = 80 } capacity_provider_strategy { - capacity_provider = local.capacity_provider + capacity_provider = var.capacity_provider weight = 100 } @@ -40,7 +40,7 @@ resource "aws_ecs_service" "admin" { create_before_destroy = true } - depends_on = [aws_lb.admin] + provider = aws.region } @@ -53,12 +53,14 @@ moved { // The service's Security Groups resource "aws_security_group" "admin_ecs_service" { - name_prefix = "${local.environment_name}-admin-ecs-service" + name_prefix = "${var.environment_name}-admin-ecs-service" description = "Admin service security group" vpc_id = data.aws_vpc.default.id lifecycle { create_before_destroy = true } + + provider = aws.region } moved { @@ -74,10 +76,12 @@ resource "aws_security_group_rule" "admin_ecs_service_ingress" { to_port = 80 protocol = "tcp" security_group_id = aws_security_group.admin_ecs_service.id - source_security_group_id = aws_security_group.admin_loadbalancer.id + source_security_group_id = var.admin_loadbalancer_security_group_id lifecycle { create_before_destroy = true } + + provider = aws.region } moved { @@ -97,6 +101,8 @@ resource "aws_security_group_rule" "admin_ecs_service_egress" { lifecycle { create_before_destroy = true } + + provider = aws.region } moved { @@ -108,14 +114,16 @@ moved { // admin ECS Service Task level config resource "aws_ecs_task_definition" "admin" { - family = "${local.environment_name}-admin" + family = "${var.environment_name}-admin" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 512 memory = 1024 container_definitions = "[${local.admin_app}]" - task_role_arn = module.iam.ecs_task_roles.admin_task_role.arn - execution_role_arn = module.iam.ecs_execution_role.arn + task_role_arn = var.ecs_task_roles.admin_task_role.arn + execution_role_arn = var.ecs_execution_role.arn + + provider = aws.region } moved { @@ -124,9 +132,11 @@ moved { } resource "aws_iam_role_policy" "admin_permissions_role" { - name = "${local.environment_name}-${local.policy_region_prefix}-adminApplicationPermissions" + name = "${var.environment_name}-${local.policy_region_prefix}-adminApplicationPermissions" policy = data.aws_iam_policy_document.admin_permissions_role.json - role = module.iam.ecs_task_roles.admin_task_role.id + role = var.ecs_task_roles.admin_task_role.id + + provider = aws.region } moved { @@ -155,16 +165,16 @@ data "aws_iam_policy_document" "admin_permissions_role" { ] resources = [ - aws_dynamodb_table.actor_users_table.arn, - "${aws_dynamodb_table.actor_users_table.arn}/index/*", - aws_dynamodb_table.viewer_codes_table.arn, - "${aws_dynamodb_table.viewer_codes_table.arn}/index/*", - aws_dynamodb_table.viewer_activity_table.arn, - "${aws_dynamodb_table.viewer_activity_table.arn}/index/*", - aws_dynamodb_table.user_lpa_actor_map.arn, - "${aws_dynamodb_table.user_lpa_actor_map.arn}/index/*", - aws_dynamodb_table.stats_table.arn, - "${aws_dynamodb_table.stats_table.arn}/index/*", + var.dynamodb_tables.actor_users_table.arn, + "${var.dynamodb_tables.actor_users_table.arn}/index/*", + var.dynamodb_tables.viewer_codes_table.arn, + "${var.dynamodb_tables.viewer_codes_table.arn}/index/*", + var.dynamodb_tables.viewer_activity_table.arn, + "${var.dynamodb_tables.viewer_activity_table.arn}/index/*", + var.dynamodb_tables.user_lpa_actor_map.arn, + "${var.dynamodb_tables.user_lpa_actor_map.arn}/index/*", + var.dynamodb_tables.stats_table.arn, + "${var.dynamodb_tables.stats_table.arn}/index/*", ] } @@ -177,7 +187,7 @@ data "aws_iam_policy_document" "admin_permissions_role" { ] resources = [ - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/GET/use-an-lpa/*", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/GET/use-an-lpa/*", ] } @@ -188,9 +198,9 @@ data "aws_iam_policy_document" "admin_permissions_role" { "execute-api:Invoke", ] resources = [ - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/GET/healthcheck", - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/POST/exists", - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/POST/code", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/GET/healthcheck", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/POST/exists", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/POST/code", ] } @@ -201,13 +211,10 @@ data "aws_iam_policy_document" "admin_permissions_role" { "ssm:GetParameter", "ssm:PutParameter", ] - resources = [ - aws_ssm_parameter.system_message_view_en.arn, - aws_ssm_parameter.system_message_view_cy.arn, - aws_ssm_parameter.system_message_use_en.arn, - aws_ssm_parameter.system_message_use_cy.arn, - ] + resources = var.parameter_store_arns } + + provider = aws.region } //----------------------------------------------- @@ -232,15 +239,15 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.admin-app.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.admin-app.use-an-lpa" } }, environment = [ { name = "LOGGING_LEVEL", - value = tostring(local.environment.logging_level) + value = tostring(var.logging_level) }, { name = "ADMIN_PORT", @@ -248,34 +255,26 @@ locals { }, { name = "ADMIN_DYNAMODB_TABLE_PREFIX", - value = tostring(local.environment_name) + value = tostring(var.environment_name) }, { name = "ADMIN_LOGOUT_URL", - value = "${local.admin_cognito_user_pool_domain_name}/logout" + value = "${var.admin_cognito_user_pool_domain_name}/logout" }, { name = "ADMIN_JWT_SIGNING_KEY_URL", - value = "https://public-keys.auth.elb.eu-west-1.amazonaws.com" + value = "https://public-keys.auth.elb.${data.aws_region.current.name}.amazonaws.com" }, { name = "ADMIN_CLIENT_ID", - value = "${aws_cognito_user_pool_client.use_a_lasting_power_of_attorney_admin.id}" + value = var.cognito_user_pool_id }, { name = "LPA_CODES_API_ENDPOINT", - value = local.environment.lpa_codes_endpoint + value = var.lpa_codes_endpoint }, ] } ) -} - -locals { - admin_domain = "https://${aws_route53_record.admin_use_my_lpa.fqdn}" -} - -output "admin_domain" { - value = local.admin_domain -} +} \ No newline at end of file diff --git a/terraform/environment/api_ecs.tf b/terraform/environment/region/api_ecs.tf similarity index 67% rename from terraform/environment/api_ecs.tf rename to terraform/environment/region/api_ecs.tf index c9b3c3ad30..407a2d8cb1 100644 --- a/terraform/environment/api_ecs.tf +++ b/terraform/environment/region/api_ecs.tf @@ -3,9 +3,9 @@ resource "aws_ecs_service" "api" { name = "api-service" - cluster = aws_ecs_cluster.use-an-lpa.id + cluster = aws_ecs_cluster.use_an_lpa.id task_definition = aws_ecs_task_definition.api.arn - desired_count = local.environment.autoscaling.api.minimum + desired_count = var.autoscaling.api.minimum platform_version = "1.4.0" health_check_grace_period_seconds = 0 @@ -20,7 +20,7 @@ resource "aws_ecs_service" "api" { } capacity_provider_strategy { - capacity_provider = local.capacity_provider + capacity_provider = var.capacity_provider weight = 100 } @@ -38,6 +38,8 @@ resource "aws_ecs_service" "api" { lifecycle { create_before_destroy = true } + + provider = aws.region } //----------------------------------------------- @@ -47,7 +49,7 @@ resource "aws_service_discovery_service" "api_ecs" { name = "api" dns_config { - namespace_id = aws_service_discovery_private_dns_namespace.internal_ecs.id + namespace_id = var.aws_service_discovery_service.id dns_records { ttl = 10 @@ -60,18 +62,20 @@ resource "aws_service_discovery_service" "api_ecs" { health_check_custom_config { failure_threshold = 1 } + + provider = aws.region } // locals { - api_service_fqdn = "${aws_service_discovery_service.api_ecs.name}.${aws_service_discovery_private_dns_namespace.internal_ecs.name}" + api_service_fqdn = "${aws_service_discovery_service.api_ecs.name}.${var.aws_service_discovery_service.name}" } //---------------------------------- // The Api service's Security Groups resource "aws_security_group" "api_ecs_service" { - name_prefix = "${local.environment_name}-api-ecs-service" + name_prefix = "${var.environment_name}-api-ecs-service" description = "API service security group" vpc_id = data.aws_vpc.default.id lifecycle { @@ -93,6 +97,8 @@ resource "aws_security_group_rule" "api_ecs_service_viewer_ingress" { lifecycle { create_before_destroy = true } + + provider = aws.region } //---------------------------------- @@ -109,6 +115,8 @@ resource "aws_security_group_rule" "api_ecs_service_actor_ingress" { lifecycle { create_before_destroy = true } + + provider = aws.region } //---------------------------------- @@ -130,23 +138,27 @@ resource "aws_security_group_rule" "api_ecs_service_egress" { // Api ECS Service Task level config resource "aws_ecs_task_definition" "api" { - family = "${local.environment_name}-api" + family = "${var.environment_name}-api" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 512 memory = 1024 - container_definitions = "[${local.api_web}, ${local.api_app} ${local.environment.deploy_opentelemetry_sidecar ? ", ${local.api_aws_otel_collector}" : ""}]" - task_role_arn = module.iam.ecs_task_roles.api_task_role.arn - execution_role_arn = module.iam.ecs_execution_role.arn + container_definitions = "[${local.api_web}, ${local.api_app} ${var.feature_flags.deploy_opentelemetry_sidecar ? ", ${local.api_aws_otel_collector}" : ""}]" + task_role_arn = var.ecs_task_roles.api_task_role.arn + execution_role_arn = var.ecs_execution_role.arn + + provider = aws.region } //---------------- // Permissions resource "aws_iam_role_policy" "api_permissions_role" { - name = "${local.environment_name}-${local.policy_region_prefix}-apiApplicationPermissions" + name = "${var.environment_name}-${local.policy_region_prefix}-apiApplicationPermissions" policy = data.aws_iam_policy_document.api_permissions_role.json - role = module.iam.ecs_task_roles.api_task_role.id + role = var.ecs_task_roles.api_task_role.id + + provider = aws.region } /* @@ -177,18 +189,18 @@ data "aws_iam_policy_document" "api_permissions_role" { ] resources = [ - aws_dynamodb_table.actor_codes_table.arn, - "${aws_dynamodb_table.actor_codes_table.arn}/index/*", - aws_dynamodb_table.actor_users_table.arn, - "${aws_dynamodb_table.actor_users_table.arn}/index/*", - aws_dynamodb_table.viewer_codes_table.arn, - "${aws_dynamodb_table.viewer_codes_table.arn}/index/*", - aws_dynamodb_table.viewer_activity_table.arn, - "${aws_dynamodb_table.viewer_activity_table.arn}/index/*", - aws_dynamodb_table.user_lpa_actor_map.arn, - "${aws_dynamodb_table.user_lpa_actor_map.arn}/index/*", - aws_dynamodb_table.stats_table.arn, - "${aws_dynamodb_table.stats_table.arn}/index/*", + var.dynamodb_tables.actor_codes_table.arn, + "${var.dynamodb_tables.actor_codes_table.arn}/index/*", + var.dynamodb_tables.actor_users_table.arn, + "${var.dynamodb_tables.actor_users_table.arn}/index/*", + var.dynamodb_tables.viewer_codes_table.arn, + "${var.dynamodb_tables.viewer_codes_table.arn}/index/*", + var.dynamodb_tables.viewer_activity_table.arn, + "${var.dynamodb_tables.viewer_activity_table.arn}/index/*", + var.dynamodb_tables.user_lpa_actor_map.arn, + "${var.dynamodb_tables.user_lpa_actor_map.arn}/index/*", + var.dynamodb_tables.stats_table.arn, + "${var.dynamodb_tables.stats_table.arn}/index/*", ] } @@ -201,8 +213,8 @@ data "aws_iam_policy_document" "api_permissions_role" { ] resources = [ - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/GET/use-an-lpa/*", - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/POST/use-an-lpa/lpas/requestCode" + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/GET/use-an-lpa/*", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/POST/use-an-lpa/lpas/requestCode" ] } @@ -213,10 +225,10 @@ data "aws_iam_policy_document" "api_permissions_role" { "execute-api:Invoke", ] resources = [ - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/GET/healthcheck", - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/POST/revoke", - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/POST/validate", - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/POST/exists", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/GET/healthcheck", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/POST/revoke", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/POST/validate", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/POST/exists", ] } @@ -226,12 +238,7 @@ data "aws_iam_policy_document" "api_permissions_role" { actions = [ "ssm:GetParameter", ] - resources = [ - aws_ssm_parameter.system_message_view_en.arn, - aws_ssm_parameter.system_message_view_cy.arn, - aws_ssm_parameter.system_message_use_en.arn, - aws_ssm_parameter.system_message_use_cy.arn, - ] + resources = var.parameter_store_arns } statement { @@ -241,10 +248,12 @@ data "aws_iam_policy_document" "api_permissions_role" { "execute-api:Invoke", ] resources = [ - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/GET/image-request/*", - "arn:aws:execute-api:eu-west-1:${local.environment.sirius_account_id}:*/*/GET/healthcheck", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/GET/image-request/*", + "arn:aws:execute-api:${data.aws_region.current.name}:${var.sirius_account_id}:*/*/GET/healthcheck", ] } + + provider = aws.region } //----------------------------------------------- @@ -269,9 +278,9 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.api-web.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.api-web.use-an-lpa" } }, environment = [ @@ -312,9 +321,9 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.actor-otel.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.actor-otel.use-an-lpa" } }, environment = [] @@ -345,9 +354,9 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.api-app.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.api-app.use-an-lpa" } }, secrets = [ @@ -358,27 +367,27 @@ locals { environment = [ { name = "DYNAMODB_TABLE_ACTOR_CODES", - value = aws_dynamodb_table.actor_codes_table.name + value = var.dynamodb_tables.actor_codes_table.name }, { name = "DYNAMODB_TABLE_ACTOR_USERS", - value = aws_dynamodb_table.actor_users_table.name + value = var.dynamodb_tables.actor_users_table.name }, { name = "DYNAMODB_TABLE_VIEWER_CODES", - value = aws_dynamodb_table.viewer_codes_table.name + value = var.dynamodb_tables.viewer_codes_table.name }, { name = "DYNAMODB_TABLE_VIEWER_ACTIVITY", - value = aws_dynamodb_table.viewer_activity_table.name + value = var.dynamodb_tables.viewer_activity_table.name }, { name = "DYNAMODB_TABLE_USER_LPA_ACTOR_MAP", - value = aws_dynamodb_table.user_lpa_actor_map.name + value = var.dynamodb_tables.user_lpa_actor_map.name }, { name = "DYNAMODB_TABLE_STATS", - value = aws_dynamodb_table.stats_table.name + value = var.dynamodb_tables.stats_table.name }, { name = "CONTAINER_VERSION", @@ -386,35 +395,35 @@ locals { }, { name = "SIRIUS_API_ENDPOINT", - value = local.environment.lpas_collection_endpoint + value = var.lpas_collection_endpoint }, { name = "LPA_CODES_API_ENDPOINT", - value = local.environment.lpa_codes_endpoint + value = var.lpa_codes_endpoint }, { name = "IAP_IMAGES_API_ENDPOINT", - value = local.environment.iap_images_endpoint + value = var.iap_images_endpoint }, { name = "LOGGING_LEVEL", - value = tostring(local.environment.logging_level) + value = tostring(var.logging_level) }, { name = "ALLOW_MERIS_LPAS", - value = tostring(local.environment.application_flags.allow_meris_lpas) + value = tostring(var.feature_flags.allow_meris_lpas) }, { name = "DONT_SEND_LPAS_REGISTERED_AFTER_SEP_2019_TO_CLEANSING_TEAM", - value = tostring(local.environment.application_flags.dont_send_lpas_registered_after_sep_2019_to_cleansing_team) + value = tostring(var.feature_flags.dont_send_lpas_registered_after_sep_2019_to_cleansing_team) }, { name = "INSTRUCTIONS_AND_PREFERENCES", - value = tostring(local.environment.application_flags.instructions_and_preferences) + value = tostring(var.feature_flags.instructions_and_preferences) }, { name = "ALLOW_GOV_ONE_LOGIN", - value = tostring(local.environment.application_flags.allow_gov_one_login) + value = tostring(var.feature_flags.allow_gov_one_login) } ] }) diff --git a/terraform/environment/region/data_sources.tf b/terraform/environment/region/data_sources.tf new file mode 100644 index 0000000000..15bc2cf67a --- /dev/null +++ b/terraform/environment/region/data_sources.tf @@ -0,0 +1,153 @@ +data "aws_subnets" "private" { + filter { + name = "vpc-id" + values = [data.aws_vpc.default.id] + } + + tags = { + Name = "private" + } + + provider = aws.region +} + +data "aws_subnets" "public" { + filter { + name = "vpc-id" + values = [data.aws_vpc.default.id] + } + + tags = { + Name = "public" + } + + provider = aws.region +} + + +data "aws_cloudwatch_log_group" "use-an-lpa" { + name = "use-an-lpa" + + provider = aws.region +} + +data "aws_kms_alias" "sessions_viewer" { + name = "alias/sessions-viewer" + + provider = aws.region +} + +data "aws_kms_alias" "sessions_actor" { + name = "alias/sessions-actor" + + provider = aws.region +} + +data "aws_kms_alias" "secrets_manager" { + name = "alias/secrets_manager_encryption" + + provider = aws.region +} + +data "aws_kms_alias" "pagerduty_sns" { + name = "alias/pagerduty-sns" + + provider = aws.region +} + +data "aws_kms_alias" "cloudwatch_encryption" { + name = "alias/cloudwatch_encryption" + + provider = aws.region +} + +//-------------------- +// ECR Repos + +data "aws_ecr_repository" "use_an_lpa_front_web" { + provider = aws.management + name = "use_an_lpa/front_web" +} + +data "aws_ecr_repository" "use_an_lpa_front_app" { + provider = aws.management + name = "use_an_lpa/front_app" +} + +data "aws_ecr_repository" "use_an_lpa_api_app" { + provider = aws.management + name = "use_an_lpa/api_app" +} + +data "aws_ecr_repository" "use_an_lpa_api_web" { + provider = aws.management + name = "use_an_lpa/api_web" +} + +data "aws_ecr_repository" "use_an_lpa_pdf" { + provider = aws.management + name = "pdf_service" +} + +data "aws_ecr_image" "pdf_service" { + repository_name = "pdf_service" + image_tag = var.pdf_container_version + provider = aws.management +} + + +data "aws_ecr_repository" "use_an_lpa_admin_app" { + provider = aws.management + name = "use_an_lpa/admin_app" +} + +data "aws_ecr_repository" "use_an_lpa_upload_statistics" { + provider = aws.management + name = "use_an_lpa/stats_upload_lambda" +} + +data "aws_secretsmanager_secret" "notify_api_key" { + name = var.notify_key_secret_name + + provider = aws.region +} + +data "aws_secretsmanager_secret" "gov-uk-onelogin-identity-private-key" { + name = "gov-uk-onelogin-identity-private-key" + + provider = aws.region +} + +data "aws_secretsmanager_secret" "gov-uk-onelogin-identity-public-key" { + name = "gov-uk-onelogin-identity-public-key" + + provider = aws.region +} + +data "aws_ip_ranges" "route53_healthchecks" { + services = ["route53_healthchecks"] + regions = ["GLOBAL"] + + provider = aws.region +} + +data "aws_security_group" "brute_force_cache_service" { + filter { + name = "group-name" + values = ["brute-force-cache-service*"] + } + + provider = aws.region +} + +data "aws_elasticache_replication_group" "brute_force_cache_replication_group" { + replication_group_id = "brute-force-cache-replication-group" + + provider = aws.region +} + +data "aws_iam_role" "ecs_autoscaling_service_role" { + name = "AWSServiceRoleForApplicationAutoScaling_ECSService" + + provider = aws.region +} \ No newline at end of file diff --git a/terraform/environment/ecs_cluster.tf b/terraform/environment/region/ecs_cluster.tf similarity index 80% rename from terraform/environment/ecs_cluster.tf rename to terraform/environment/region/ecs_cluster.tf index 8fea95a936..111072b9d1 100644 --- a/terraform/environment/ecs_cluster.tf +++ b/terraform/environment/region/ecs_cluster.tf @@ -1,14 +1,19 @@ -resource "aws_ecs_cluster" "use-an-lpa" { - name = "${local.environment_name}-use-an-lpa" +resource "aws_ecs_cluster" "use_an_lpa" { + name = "${var.environment_name}-use-an-lpa" setting { name = "containerInsights" value = "enabled" } + + provider = aws.region } + resource "aws_iam_role_policy" "execution_role" { - name = "${local.environment_name}_execution_role" + name = "${var.environment_name}_execution_role" policy = data.aws_iam_policy_document.execution_role.json - role = module.iam.ecs_execution_role.id + role = var.ecs_execution_role.id + + provider = aws.region } data "aws_iam_policy_document" "execution_role" { @@ -48,4 +53,6 @@ data "aws_iam_policy_document" "execution_role" { "kms:DescribeKey", ] } + + provider = aws.region } diff --git a/terraform/environment/region/locals.tf b/terraform/environment/region/locals.tf new file mode 100644 index 0000000000..ecf2610f5c --- /dev/null +++ b/terraform/environment/region/locals.tf @@ -0,0 +1,3 @@ +locals { + policy_region_prefix = lower(replace(data.aws_region.current.name, "-", "")) +} \ No newline at end of file diff --git a/terraform/environment/region/outputs.tf b/terraform/environment/region/outputs.tf new file mode 100644 index 0000000000..27aac90a33 --- /dev/null +++ b/terraform/environment/region/outputs.tf @@ -0,0 +1,20 @@ +output "ecs_cluster" { + description = "The ECS cluster object" + value = aws_ecs_cluster.use_an_lpa +} + +output "ecs_services" { + description = "Objects containing the ECS services" + value = { + actor = aws_ecs_service.actor + admin = aws_ecs_service.admin + api = aws_ecs_service.api + pdf = aws_ecs_service.pdf + viewer = aws_ecs_service.viewer + } +} + +output "admin_domain" { + description = "The URL for the admin interface" + value = "https://${var.route_53_fqdns.admin}" +} \ No newline at end of file diff --git a/terraform/environment/pdf_ecs.tf b/terraform/environment/region/pdf_ecs.tf similarity index 81% rename from terraform/environment/pdf_ecs.tf rename to terraform/environment/region/pdf_ecs.tf index ab24571f1f..ad0a0a0863 100644 --- a/terraform/environment/pdf_ecs.tf +++ b/terraform/environment/region/pdf_ecs.tf @@ -3,9 +3,9 @@ resource "aws_ecs_service" "pdf" { name = "pdf-service" - cluster = aws_ecs_cluster.use-an-lpa.id + cluster = aws_ecs_cluster.use_an_lpa.id task_definition = aws_ecs_task_definition.pdf.arn - desired_count = local.environment.autoscaling.pdf.minimum + desired_count = var.autoscaling.pdf.minimum platform_version = "1.4.0" network_configuration { @@ -19,7 +19,7 @@ resource "aws_ecs_service" "pdf" { } capacity_provider_strategy { - capacity_provider = local.capacity_provider + capacity_provider = var.capacity_provider weight = 100 } @@ -37,6 +37,8 @@ resource "aws_ecs_service" "pdf" { lifecycle { create_before_destroy = true } + + provider = aws.region } //----------------------------------------------- @@ -46,7 +48,7 @@ resource "aws_service_discovery_service" "pdf_ecs" { name = "pdf" dns_config { - namespace_id = aws_service_discovery_private_dns_namespace.internal_ecs.id + namespace_id = var.aws_service_discovery_service.id dns_records { ttl = 10 @@ -59,23 +61,27 @@ resource "aws_service_discovery_service" "pdf_ecs" { health_check_custom_config { failure_threshold = 1 } + + provider = aws.region } // locals { - pdf_service_fqdn = "${aws_service_discovery_service.pdf_ecs.name}.${aws_service_discovery_private_dns_namespace.internal_ecs.name}" + pdf_service_fqdn = "${aws_service_discovery_service.pdf_ecs.name}.${var.aws_service_discovery_service.name}" } //---------------------------------- // The pdf service's Security Groups resource "aws_security_group" "pdf_ecs_service" { - name_prefix = "${local.environment_name}-pdf-ecs-service" + name_prefix = "${var.environment_name}-pdf-ecs-service" description = "PDF generator service security group" vpc_id = data.aws_vpc.default.id lifecycle { create_before_destroy = true } + + provider = aws.region } //---------------------------------- @@ -107,20 +113,24 @@ resource "aws_security_group_rule" "pdf_ecs_service_egress" { lifecycle { create_before_destroy = true } + + provider = aws.region } //-------------------------------------- // pdf ECS Service Task level config resource "aws_ecs_task_definition" "pdf" { - family = "${local.environment_name}-pdf" + family = "${var.environment_name}-pdf" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 512 memory = 1024 container_definitions = "[${local.pdf_app}]" - task_role_arn = module.iam.ecs_task_roles.pdf_task_role.arn - execution_role_arn = module.iam.ecs_execution_role.arn + task_role_arn = var.ecs_task_roles.pdf_task_role.arn + execution_role_arn = var.ecs_execution_role.arn + + provider = aws.region } //---------------- @@ -145,9 +155,9 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.pdf-app.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.pdf-app.use-an-lpa" } }, environment = [ diff --git a/terraform/environment/region/terraform.tf b/terraform/environment/region/terraform.tf new file mode 100644 index 0000000000..575a64eb16 --- /dev/null +++ b/terraform/environment/region/terraform.tf @@ -0,0 +1,23 @@ +terraform { + required_version = ">= 1.5.6" + + required_providers { + aws = { + source = "hashicorp/aws" + configuration_aliases = [ + aws.region, + aws.management, + ] + } + } +} + +data "aws_vpc" "default" { + default = "true" + + provider = aws.region +} + +data "aws_region" "current" { + provider = aws.region +} \ No newline at end of file diff --git a/terraform/environment/region/variables.tf b/terraform/environment/region/variables.tf new file mode 100644 index 0000000000..d9f63c9726 --- /dev/null +++ b/terraform/environment/region/variables.tf @@ -0,0 +1,189 @@ +# Many of these variables are temporary and will be removed once the relevant region specific resources are moved to the region module. +# E.g. dynamodb_tables will no longer be needed once the DynamoDB tables are moved to the region module. + +variable "actor_loadbalancer_security_group_id" { + description = "The ID of the ALB security group for actor service." + type = string +} + +variable "admin_cognito_user_pool_domain_name" { + description = "The domain name of the Cognito User Pool to use for the admin interface." + type = string +} + +variable "admin_container_version" { + description = "The image tag to use for the admin container." + type = string +} + +variable "admin_loadbalancer_security_group_id" { + description = "The ID of the ALB security group for admin service." + type = string +} + +variable "alb_tg_arns" { + description = "Map of ALB ARNs to be used by the ECS services." + type = map(object({ + arn = string + name = string + })) +} + +variable "application_logs_name" { + description = "The name of the CloudWatch Logs group to send application logs to." + type = string +} + +variable "autoscaling" { + description = "The min and max number of instances to run for each ECS service." + type = map(object({ + minimum = number + maximum = number + })) +} + +variable "aws_service_discovery_service" { + description = "The AWS Service Discovery service to use." + type = object({ + id = string + arn = string + name = string + }) +} + +variable "capacity_provider" { + description = "The capacity provider to use for the ECS services." + type = string +} + +variable "cognito_user_pool_id" { + description = "The Cognito User Pool ID to use for authentication to the admin interface." + type = string +} + +variable "container_version" { + description = "The image tag to use for the containers." + type = string +} + +variable "cookie_expires_use" { + description = "The number of seconds before the cookie expires for the use service." + type = string +} + +variable "cookie_expires_view" { + description = "The number of seconds before the cookie expires for the viewer service." + type = number +} + +variable "dynamodb_tables" { + description = "The DynamoDB tables to use." + type = map(object({ + name = string + arn = string + })) +} + +variable "ecs_execution_role" { + description = "The ECS execution role to use." + type = object({ + name = string + arn = string + id = string + }) +} + +variable "ecs_task_roles" { + description = "The ECS task roles to use." + type = map(object({ + name = string + arn = string + id = string + })) +} + +variable "environment_name" { + description = "The name of the environment" + type = string +} + +variable "feature_flags" { + description = "The feature flags to use." + type = map(string) +} + +variable "google_analytics_id_use" { + description = "The Google Analytics ID to use for the use service." + type = string +} + +variable "google_analytics_id_view" { + description = "The Google Analytics ID to use for the viewer service." + type = string +} + +variable "iap_images_endpoint" { + description = "The endpoint to use for IAP images." + type = string +} + +variable "logging_level" { + description = "The logging level to use for the applications." + type = string +} + +variable "lpa_codes_endpoint" { + description = "The endpoint to use for LPA codes." + type = string +} + +variable "lpas_collection_endpoint" { + description = "The endpoint to use for LPAs collection." + type = string +} + +variable "notify_key_secret_name" { + description = "The name of the secret containing the Notify API key." + type = string +} + +variable "parameter_store_arns" { + description = "The ARNs of the Parameter Store parameters to use." + type = list(string) +} + +variable "pdf_container_version" { + description = "The image tag to use for the PDF container." + type = string +} + +variable "route_53_fqdns" { + description = "The FQDNs to use for the Route 53 records." + + type = map(string) +} + +variable "session_expires_use" { + description = "The number of seconds before the session expires for the use service." + type = string +} + +variable "session_expires_view" { + description = "The number of seconds before the session expires for the viewer service." + type = number +} + +variable "session_expiry_warning" { + description = "The number of seconds before the session expires to show the warning for the viewer service." + type = string +} + +variable "sirius_account_id" { + description = "The AWS ID of the Sirius account." + type = string +} + +variable "viewer_loadbalancer_security_group_id" { + description = "The ID of the ALB security group for viewer service." + type = string +} \ No newline at end of file diff --git a/terraform/environment/viewer_ecs.tf b/terraform/environment/region/viewer_ecs.tf similarity index 78% rename from terraform/environment/viewer_ecs.tf rename to terraform/environment/region/viewer_ecs.tf index 35fe90bce8..dd0dacf984 100644 --- a/terraform/environment/viewer_ecs.tf +++ b/terraform/environment/region/viewer_ecs.tf @@ -3,9 +3,9 @@ resource "aws_ecs_service" "viewer" { name = "viewer-service" - cluster = aws_ecs_cluster.use-an-lpa.id + cluster = aws_ecs_cluster.use_an_lpa.id task_definition = aws_ecs_task_definition.viewer.arn - desired_count = local.environment.autoscaling.view.minimum + desired_count = var.autoscaling.view.minimum platform_version = "1.4.0" network_configuration { @@ -15,13 +15,13 @@ resource "aws_ecs_service" "viewer" { } load_balancer { - target_group_arn = aws_lb_target_group.viewer.arn + target_group_arn = var.alb_tg_arns.viewer.arn container_name = "web" container_port = 80 } capacity_provider_strategy { - capacity_provider = local.capacity_provider + capacity_provider = var.capacity_provider weight = 100 } @@ -40,19 +40,21 @@ resource "aws_ecs_service" "viewer" { create_before_destroy = true } - depends_on = [aws_lb.viewer] + provider = aws.region } //---------------------------------- // The service's Security Groups resource "aws_security_group" "viewer_ecs_service" { - name_prefix = "${local.environment_name}-viewer-ecs-service" + name_prefix = "${var.environment_name}-viewer-ecs-service" description = "Use service security group" vpc_id = data.aws_vpc.default.id lifecycle { create_before_destroy = true } + + provider = aws.region } // 80 in from the ELB @@ -63,10 +65,12 @@ resource "aws_security_group_rule" "viewer_ecs_service_ingress" { to_port = 80 protocol = "tcp" security_group_id = aws_security_group.viewer_ecs_service.id - source_security_group_id = aws_security_group.viewer_loadbalancer.id + source_security_group_id = var.viewer_loadbalancer_security_group_id lifecycle { create_before_destroy = true } + + provider = aws.region } // Anything out @@ -81,6 +85,8 @@ resource "aws_security_group_rule" "viewer_ecs_service_egress" { lifecycle { create_before_destroy = true } + + provider = aws.region } resource "aws_security_group_rule" "viewer_ecs_service_elasticache_ingress" { @@ -94,29 +100,35 @@ resource "aws_security_group_rule" "viewer_ecs_service_elasticache_ingress" { lifecycle { create_before_destroy = true } + + provider = aws.region } //-------------------------------------- // Viewer ECS Service Task level config resource "aws_ecs_task_definition" "viewer" { - family = "${local.environment_name}-viewer" + family = "${var.environment_name}-viewer" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 512 memory = 1024 - container_definitions = "[${local.viewer_web}, ${local.viewer_app} ${local.environment.deploy_opentelemetry_sidecar ? ", ${local.viewer_aws_otel_collector}" : ""}]" - task_role_arn = module.iam.ecs_task_roles.viewer_task_role.arn - execution_role_arn = module.iam.ecs_execution_role.arn + container_definitions = "[${local.viewer_web}, ${local.viewer_app} ${var.feature_flags.deploy_opentelemetry_sidecar ? ", ${local.viewer_aws_otel_collector}" : ""}]" + task_role_arn = var.ecs_task_roles.viewer_task_role.arn + execution_role_arn = var.ecs_execution_role.arn + + provider = aws.region } //---------------- // Permissions resource "aws_iam_role_policy" "viewer_permissions_role" { - name = "${local.environment_name}-${local.policy_region_prefix}-ViewerApplicationPermissions" + name = "${var.environment_name}-${local.policy_region_prefix}-ViewerApplicationPermissions" policy = data.aws_iam_policy_document.viewer_permissions_role.json - role = module.iam.ecs_task_roles.viewer_task_role.id + role = var.ecs_task_roles.viewer_task_role.id + + provider = aws.region } /* @@ -149,6 +161,8 @@ data "aws_iam_policy_document" "viewer_permissions_role" { resources = [data.aws_kms_alias.sessions_viewer.target_key_arn] } + + provider = aws.region } //----------------------------------------------- @@ -173,15 +187,15 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.viewer-web.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.viewer-web.use-an-lpa" } }, environment = [ { name = "WEB_DOMAIN", - value = "https://${aws_route53_record.public_facing_view_lasting_power_of_attorney.fqdn}" + value = "https://${var.route_53_fqdns.public_view}" }, { name = "APP_HOST", @@ -216,9 +230,9 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.viewer-otel.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.viewer-otel.use-an-lpa" } }, environment = [] @@ -249,9 +263,9 @@ locals { logConfiguration = { logDriver = "awslogs", options = { - awslogs-group = aws_cloudwatch_log_group.application_logs.name, - awslogs-region = "eu-west-1", - awslogs-stream-prefix = "${local.environment_name}.viewer-app.use-an-lpa" + awslogs-group = var.application_logs_name, + awslogs-region = data.aws_region.current.name, + awslogs-stream-prefix = "${var.environment_name}.viewer-app.use-an-lpa" } }, environment = local.viewer_app_environment_variables @@ -283,19 +297,19 @@ locals { }, { name = "SESSION_EXPIRES", - value = tostring(local.environment.session_expires_view) + value = tostring(var.session_expires_view) }, { name = "COOKIE_EXPIRES", - value = tostring(local.environment.cookie_expires_view) + value = tostring(var.cookie_expires_view) }, { name = "GOOGLE_ANALYTICS_ID", - value = local.environment.google_analytics_id_view + value = var.google_analytics_id_view }, { name = "LOGGING_LEVEL", - value = tostring(local.environment.logging_level) + value = tostring(var.logging_level) }, { name = "BRUTE_FORCE_CACHE_URL", @@ -311,11 +325,11 @@ locals { }, { name = "INSTRUCTIONS_AND_PREFERENCES", - value = tostring(local.environment.application_flags.instructions_and_preferences) + value = tostring(var.feature_flags.instructions_and_preferences) }, { name = "ALLOW_GOV_ONE_LOGIN", - value = tostring(local.environment.application_flags.allow_gov_one_login) + value = tostring(var.feature_flags.allow_gov_one_login) } ], ) diff --git a/terraform/environment/terraform.tf b/terraform/environment/terraform.tf index a630c21d09..0c27abc015 100644 --- a/terraform/environment/terraform.tf +++ b/terraform/environment/terraform.tf @@ -47,6 +47,18 @@ provider "aws" { } } +provider "aws" { + region = "eu-west-1" + alias = "eu_west_1" + default_tags { + tags = local.default_tags + } + assume_role { + role_arn = "arn:aws:iam::${local.environment.account_id}:role/${var.default_role}" + session_name = "terraform-session" + } +} + provider "aws" { region = "us-east-1" alias = "us-east-1"