From b0394be3b4408a30ce33be73b79293664594c8c9 Mon Sep 17 00:00:00 2001 From: George Taylor Date: Fri, 8 Mar 2024 14:26:12 +0000 Subject: [PATCH] Nit 1150 delius core pwm vs hmpps auth usecase (#5256) * configure pwm * setup ses * image + config * Update pwm.tf * add dkim records * Update pwm.tf * Update pwm.tf * Update pwm.tf * Update pwm.tf * Update pwm.tf * task def * Update pwm.tf * sg * Update PwmConfiguration.xml.tpl * create smtp creds user * justice relay * Update pwm.tf * Update pwm.tf * Update load_balancing.tf * Update pwm.tf * Update pwm.tf * Update pwm.tf * Update PwmConfiguration.xml.tpl * security groups * url schema * Update pwm.tf * Update pwm.tf * Update pwm.tf * fix * ingress * Update locals.tf * Update pwm.tf * Update locals_test.tf * Update pwm.tf * Update pwm.tf * Update pwm.tf --- .../delius-core/locals_development.tf | 2 +- .../environments/delius-core/locals_test.tf | 2 +- .../modules/components/ldap/outputs.tf | 4 + .../delius_environment/alb_ancillary.tf | 11 +- .../modules/delius_environment/locals.tf | 15 ++ .../password_reset_service.tf | 74 ------- .../modules/delius_environment/pwm.tf | 181 ++++++++++++++++++ .../templates/PwmConfiguration.xml.tpl | 30 ++- .../helpers/delius_microservice/ecs.tf | 6 +- .../delius_microservice/load_balancing.tf | 2 +- .../modules/helpers/delius_microservice/sg.tf | 30 +++ .../helpers/delius_microservice/variables.tf | 40 ++++ 12 files changed, 306 insertions(+), 91 deletions(-) delete mode 100644 terraform/environments/delius-core/modules/delius_environment/password_reset_service.tf create mode 100644 terraform/environments/delius-core/modules/delius_environment/pwm.tf diff --git a/terraform/environments/delius-core/locals_development.tf b/terraform/environments/delius-core/locals_development.tf index 105ddb2ebd1..fb06134fd69 100644 --- a/terraform/environments/delius-core/locals_development.tf +++ b/terraform/environments/delius-core/locals_development.tf @@ -122,7 +122,7 @@ locals { } pwm = { - image_tag = "5.7.6" + image_tag = "8179630699-1" container_port = 8080 } diff --git a/terraform/environments/delius-core/locals_test.tf b/terraform/environments/delius-core/locals_test.tf index 6130084be2a..49405d15f25 100644 --- a/terraform/environments/delius-core/locals_test.tf +++ b/terraform/environments/delius-core/locals_test.tf @@ -130,7 +130,7 @@ locals { } pwm = { - image_tag = "5.7.6" + image_tag = "8179630699-1" container_port = 8080 } diff --git a/terraform/environments/delius-core/modules/components/ldap/outputs.tf b/terraform/environments/delius-core/modules/components/ldap/outputs.tf index ffd34a25468..e9cc7b70686 100644 --- a/terraform/environments/delius-core/modules/components/ldap/outputs.tf +++ b/terraform/environments/delius-core/modules/components/ldap/outputs.tf @@ -8,4 +8,8 @@ output "delius_core_ldap_principal_arn" { output "delius_core_ldap_bind_password_arn" { value = aws_ssm_parameter.delius_core_ldap_bind_password.arn +} + +output "security_group_id" { + value = aws_security_group.ldap.id } \ No newline at end of file diff --git a/terraform/environments/delius-core/modules/delius_environment/alb_ancillary.tf b/terraform/environments/delius-core/modules/delius_environment/alb_ancillary.tf index c07e914b34c..66deec7d241 100644 --- a/terraform/environments/delius-core/modules/delius_environment/alb_ancillary.tf +++ b/terraform/environments/delius-core/modules/delius_environment/alb_ancillary.tf @@ -9,7 +9,7 @@ resource "aws_security_group" "ancillary_alb_security_group" { } resource "aws_vpc_security_group_ingress_rule" "ancillary_alb_ingress_https_global_protect_allowlist" { - for_each = toset(local.globalprotect_ips) + for_each = toset(local.all_ingress_ips) security_group_id = aws_security_group.ancillary_alb_security_group.id description = "Access into alb over https" from_port = "443" @@ -19,7 +19,7 @@ resource "aws_vpc_security_group_ingress_rule" "ancillary_alb_ingress_https_glob } resource "aws_vpc_security_group_ingress_rule" "ancillary_alb_ingress_http_global_protect_allowlist" { - for_each = toset(local.globalprotect_ips) + for_each = toset(local.all_ingress_ips) security_group_id = aws_security_group.ancillary_alb_security_group.id description = "Access into alb over http (will redirect)" from_port = "80" @@ -28,6 +28,13 @@ resource "aws_vpc_security_group_ingress_rule" "ancillary_alb_ingress_http_globa cidr_ipv4 = each.key # Global Protect VPN } +resource "aws_vpc_security_group_egress_rule" "ancillary_alb_egress_private" { + security_group_id = aws_security_group.ancillary_alb_security_group.id + description = "Access into alb over http (will redirect)" + ip_protocol = "-1" + cidr_ipv4 = var.account_config.shared_vpc_cidr +} + # tfsec:ignore:aws-elb-alb-not-public resource "aws_lb" "delius_core_ancillary" { # checkov:skip=CKV_AWS_91 diff --git a/terraform/environments/delius-core/modules/delius_environment/locals.tf b/terraform/environments/delius-core/modules/delius_environment/locals.tf index ba5b5785e29..c02f03d49e5 100644 --- a/terraform/environments/delius-core/modules/delius_environment/locals.tf +++ b/terraform/environments/delius-core/modules/delius_environment/locals.tf @@ -22,4 +22,19 @@ locals { certificate_arn = aws_acm_certificate.external.arn globalprotect_ips = module.ip_addresses.moj_cidr.moj_aws_digital_macos_globalprotect_alpha + unilink_ips = [ + "194.75.210.216/29", # Unilink AOVPN + "83.98.63.176/29", # Unilink AOVPN + "78.33.10.50/31", # Unilink AOVPN + "78.33.10.52/30", # Unilink AOVPN + "78.33.10.56/30", # Unilink AOVPN + "78.33.10.60/32", # Unilink AOVPN + "78.33.32.99/32", # Unilink AOVPN + "78.33.32.100/30", # Unilink AOVPN + "78.33.32.104/30", # Unilink AOVPN + "78.33.32.108/32", # Unilink AOVPN + "217.138.45.109/32", # Unilink AOVPN + "217.138.45.110/32", # Unilink AOVPN + ] + all_ingress_ips = concat(local.globalprotect_ips, local.unilink_ips) } diff --git a/terraform/environments/delius-core/modules/delius_environment/password_reset_service.tf b/terraform/environments/delius-core/modules/delius_environment/password_reset_service.tf deleted file mode 100644 index e667be2c1f8..00000000000 --- a/terraform/environments/delius-core/modules/delius_environment/password_reset_service.tf +++ /dev/null @@ -1,74 +0,0 @@ -module "password_reset_service" { - source = "../helpers/delius_microservice" - - name = "password-reset" - certificate_arn = local.certificate_arn - alb_security_group_id = aws_security_group.delius_frontend_alb_security_group.id - env_name = var.env_name - container_port_config = [ - { - containerPort = var.delius_microservice_configs.pwm.container_port - protocol = "tcp" - } - ] - - ecs_cluster_arn = module.ecs.ecs_cluster_arn - container_secrets = [ - { - name = "SECURITY_KEY" - valueFrom = "REPLACE" - # "/${var.environment_name}/${var.project_name}/pwm/pwm/security_key" - }, - { - name = "CONFIG_PASSWORD" - valueFrom = aws_ssm_parameter.delius_core_pwm_config_password.arn - #value = "/${var.environment_name}/${var.project_name}/pwm/pwm/config_password" - }, - { - name = "LDAP_PASSWORD" - valueFrom = module.ldap.delius_core_ldap_bind_password_arn - #value = "/${var.environment_name}/${var.project_name}/apacheds/apacheds/ldap_admin_password" - } - ] - db_ingress_security_groups = [] - - cluster_security_group_id = aws_security_group.cluster.id - - bastion_sg_id = module.bastion_linux.bastion_security_group - - tags = var.tags - microservice_lb = aws_lb.delius_core_ancillary - microservice_lb_https_listener_arn = aws_lb_listener.ancillary_https.arn - - #TODO - check the path based routing based on shared ALB or dedicated - alb_listener_rule_host_header = "pwm.${var.env_name}.${var.account_config.dns_suffix}" - platform_vars = var.platform_vars - container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-password-management-ecr-repo:${var.delius_microservice_configs.pwm.image_tag}" - account_config = var.account_config - #TODO check the health end-point - health_check_path = "/pwm/actuator/health" - account_info = var.account_info - - container_environment_vars = [ - { - name = "CONFIG_XML_BASE64" - value = base64encode(templatefile("${path.module}/templates/PwmConfiguration.xml.tpl", { - region = var.account_info["region"] - ldap_url = "ldap://${module.ldap.nlb_dns_name}:${var.ldap_config.port}" - ldap_user = module.ldap.delius_core_ldap_principal_arn - user_base = "REPLACE" - # site_url = "https://${aws_route53_record.public_dns.fqdn}" - site_url = "REPLACE" - # email_smtp_address = "smtp.${data.terraform_remote_state.vpc.outputs.private_zone_name}" - email_smtp_address = "REPLACE" - # email_from_address = "no-reply@${data.terraform_remote_state.vpc.outputs.public_zone_name}" - email_from_address = "REPLACE" - })) - } - ] - - providers = { - aws = aws - aws.core-vpc = aws.core-vpc - } -} diff --git a/terraform/environments/delius-core/modules/delius_environment/pwm.tf b/terraform/environments/delius-core/modules/delius_environment/pwm.tf new file mode 100644 index 00000000000..4f2c483d5b4 --- /dev/null +++ b/terraform/environments/delius-core/modules/delius_environment/pwm.tf @@ -0,0 +1,181 @@ +module "pwm" { + source = "../helpers/delius_microservice" + + name = "pwd-manager" + certificate_arn = local.certificate_arn + alb_security_group_id = aws_security_group.ancillary_alb_security_group.id + env_name = var.env_name + container_port_config = [ + { + containerPort = var.delius_microservice_configs.pwm.container_port + protocol = "tcp" + } + ] + + ecs_cluster_arn = module.ecs.ecs_cluster_arn + container_secrets = [ + { + name = "CONFIG_PASSWORD" + valueFrom = aws_ssm_parameter.delius_core_pwm_config_password.arn + }, + { + name = "LDAP_PASSWORD" + valueFrom = aws_ssm_parameter.ldap_admin_password.arn + } + ] + + db_ingress_security_groups = [] + + cluster_security_group_id = aws_security_group.cluster.id + + bastion_sg_id = module.bastion_linux.bastion_security_group + + ecs_service_ingress_security_group_ids = [] + ecs_service_egress_security_group_ids = [{ + ip_protocol = "tcp" + port = 389 + cidr_ipv4 = var.account_config.shared_vpc_cidr + }, + { + ip_protocol = "tcp" + port = 25 + cidr_ipv4 = "10.180.104.0/22" # https://github.com/ministryofjustice/staff-infrastructure-network-services/blob/main/README.md#smtp-relay-service + + }] + + tags = var.tags + microservice_lb = aws_lb.delius_core_ancillary + microservice_lb_https_listener_arn = aws_lb_listener.ancillary_https.arn + + + alb_listener_rule_host_header = "pwm.${var.env_name}.${var.account_config.dns_suffix}" + + platform_vars = var.platform_vars + + container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-password-management:${var.delius_microservice_configs.pwm.image_tag}" + account_config = var.account_config + health_check_path = "/" + health_check_interval = "15" + account_info = var.account_info + + target_group_protocol_version = "HTTP1" + health_check_grace_period_seconds = 10 + + container_cpu = 1024 + container_memory = 2048 + deployment_maximum_percent = 200 + deployment_minimum_healthy_percent = 100 + + container_environment_vars = [ + { + name = "CONFIG_XML_BASE64" + value = base64encode(templatefile("${path.module}/templates/PwmConfiguration.xml.tpl", { + ldap_host_url = "ldap://${module.ldap.nlb_dns_name}:${var.ldap_config.port}" + ldap_user = module.ldap.delius_core_ldap_principal_arn + pwm_url = "https://pwm.${var.env_name}.${var.account_config.dns_suffix}" + # email_smtp_address = "smtp.${data.terraform_remote_state.vpc.outputs.private_zone_name}" + email_smtp_address = "production-smtp-relay-70e032e2738d0a27.elb.eu-west-2.amazonaws.com" + # email_from_address = "no-reply@${data.terraform_remote_state.vpc.outputs.public_zone_name}" + email_from_address = "noreply-ndelius-pwm-${var.env_name}@digital.justice.gov.uk" + })) + }, + { + name = "SECURITY_KEY" + value = "${uuid()}" + } + ] + + ignore_changes_task_definition = false + force_new_deployment = true + + providers = { + aws = aws + aws.core-vpc = aws.core-vpc + } +} + + + + +############# +# SES +#############" + +resource "aws_ses_domain_identity" "pwm" { + domain = "pwm.${var.env_name}.${var.account_config.dns_suffix}" +} + +resource "aws_ses_domain_identity_verification" "pwm" { + domain = "pwm.${var.env_name}.${var.account_config.dns_suffix}" +} + +resource "aws_route53_record" "pwm_ses_verification_record" { + provider = aws.core-vpc + zone_id = var.account_config.route53_external_zone.zone_id + name = "_amazonses.${aws_ses_domain_identity.pwm.id}" + type = "TXT" + ttl = "600" + records = [aws_ses_domain_identity.pwm.verification_token] +} + +resource "aws_ses_domain_identity_verification" "pwm_ses_verification" { + domain = aws_ses_domain_identity.pwm.id + depends_on = [aws_route53_record.pwm_ses_verification_record] +} + + +resource "aws_ses_domain_dkim" "pwm" { + domain = aws_ses_domain_identity.pwm.domain +} + +resource "aws_route53_record" "pwm_amazonses_dkim_record" { + provider = aws.core-vpc + count = 3 + zone_id = var.account_config.route53_external_zone.zone_id + name = "${aws_ses_domain_dkim.pwm.dkim_tokens[count.index]}._domainkey" + type = "CNAME" + ttl = "600" + records = ["${aws_ses_domain_dkim.pwm.dkim_tokens[count.index]}.dkim.amazonses.com"] +} + +###################### +# SES SMTP User +###################### + +# resource "aws_iam_user" "pwm_ses_smtp_user" { +# name = "pwm-smtp-user" +# } +# +# resource "aws_iam_access_key" "pwm_ses_smtp_user" { +# user = aws_iam_user.pwm_ses_smtp_user.name +# } +# +# resource "aws_iam_user_policy" "pwm_ses_smtp_user" { +# name = "pwm-ses-smtp-user-policy" +# user = aws_iam_user.pwm_ses_smtp_user.name +# +# policy = jsonencode({ +# Version = "2012-10-17", +# Statement = [ +# { +# Effect = "Allow", +# Action = [ +# "ses:SendRawEmail", +# "ses:SendEmail" +# ], +# Resource = "*" +# } +# ] +# }) +# } + +# resource "aws_ssm_parameter" "pwm_ses_smtp_user" { +# name = "/pwm/ses_smtp" +# type = "SecureString" +# value = jsonencode({ +# user = aws_iam_user.pwm_ses_smtp_user.name, +# key = aws_iam_access_key.pwm_ses_smtp_user.id, +# secret = aws_iam_access_key.pwm_ses_smtp_user.secret +# ses_smtp_password = aws_iam_access_key.pwm_ses_smtp_user.ses_smtp_password_v4 +# }) +# } \ No newline at end of file diff --git a/terraform/environments/delius-core/modules/delius_environment/templates/PwmConfiguration.xml.tpl b/terraform/environments/delius-core/modules/delius_environment/templates/PwmConfiguration.xml.tpl index d423e955ab8..6f0c3254a0d 100644 --- a/terraform/environments/delius-core/modules/delius_environment/templates/PwmConfiguration.xml.tpl +++ b/terraform/environments/delius-core/modules/delius_environment/templates/PwmConfiguration.xml.tpl @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@ true - $${PWM_CONFIG_PASSWORD_HASH} + $${CONFIG_PASSWORD_HASH} false 1 @@ -18,9 +18,13 @@ $${SECURITY_KEY} + + + security.http.permittedUrlPathCharacters=^[a-zA-Z0-9-_=\\s]*$ + - + @@ -32,11 +36,11 @@ - + - + @@ -44,7 +48,7 @@ - + @@ -52,11 +56,11 @@ - + - {"ldapBase":"${user_base}","ldapQuery":"(pwmAdmin=TRUE)","type":"ldapQuery"} + {"ldapBase":"ou=Users,dc=moj,dc=com","ldapQuery":"(pwmAdmin=TRUE)","type":"ldapQuery"} @@ -68,7 +72,7 @@ - + @@ -163,5 +167,13 @@ + + + + + + + + diff --git a/terraform/environments/delius-core/modules/helpers/delius_microservice/ecs.tf b/terraform/environments/delius-core/modules/helpers/delius_microservice/ecs.tf index 728d1db5916..a08ae3eec8d 100644 --- a/terraform/environments/delius-core/modules/helpers/delius_microservice/ecs.tf +++ b/terraform/environments/delius-core/modules/helpers/delius_microservice/ecs.tf @@ -70,7 +70,7 @@ module "ecs_service" { exec_enabled = true - ignore_changes_task_definition = true # task definition managed by Delius App team - redeploy_on_apply = false - force_new_deployment = false + ignore_changes_task_definition = var.ignore_changes_task_definition # task definition managed by Delius App team + redeploy_on_apply = var.redeploy_on_apply + force_new_deployment = var.force_new_deployment } diff --git a/terraform/environments/delius-core/modules/helpers/delius_microservice/load_balancing.tf b/terraform/environments/delius-core/modules/helpers/delius_microservice/load_balancing.tf index bf3a511d1a6..6a746b191c1 100644 --- a/terraform/environments/delius-core/modules/helpers/delius_microservice/load_balancing.tf +++ b/terraform/environments/delius-core/modules/helpers/delius_microservice/load_balancing.tf @@ -149,7 +149,7 @@ resource "aws_route53_record" "services_nlb_r53_record" { provider = aws.core-vpc zone_id = var.account_config.route53_inner_zone_info.zone_id name = "${var.name}.service.${var.env_name}.${var.account_config.dns_suffix}" - type = "CNAME" + type = "A" alias { evaluate_target_health = false name = aws_lb.delius_microservices.dns_name diff --git a/terraform/environments/delius-core/modules/helpers/delius_microservice/sg.tf b/terraform/environments/delius-core/modules/helpers/delius_microservice/sg.tf index 8278e47d592..f4377e63a3e 100644 --- a/terraform/environments/delius-core/modules/helpers/delius_microservice/sg.tf +++ b/terraform/environments/delius-core/modules/helpers/delius_microservice/sg.tf @@ -56,4 +56,34 @@ resource "aws_security_group_rule" "bastion_to_ecs_service_tcp" { to_port = each.value protocol = "tcp" source_security_group_id = var.bastion_sg_id +} + +resource "aws_vpc_security_group_ingress_rule" "nlb_to_ecs_service" { + security_group_id = aws_security_group.ecs_service.id + description = "network load balancer to ecs service" + from_port = var.container_port_config[0].containerPort + to_port = var.container_port_config[0].containerPort + ip_protocol = "tcp" + referenced_security_group_id = aws_security_group.delius_microservices_service_nlb.id +} + +resource "aws_vpc_security_group_ingress_rule" "custom_rules" { + for_each = { for index, rule in var.ecs_service_ingress_security_group_ids : index => rule } + security_group_id = aws_security_group.ecs_service.id + description = "custom rule" + from_port = each.value.port + to_port = each.value.port + ip_protocol = each.value.ip_protocol + cidr_ipv4 = each.value.cidr_ipv4 +} + +resource "aws_vpc_security_group_egress_rule" "custom_rules" { + for_each = { for index, rule in var.ecs_service_egress_security_group_ids : index => rule } + security_group_id = aws_security_group.ecs_service.id + description = "custom rule" + from_port = each.value.port + to_port = each.value.port + ip_protocol = each.value.ip_protocol + cidr_ipv4 = each.value.cidr_ipv4 + referenced_security_group_id = each.value.referenced_security_group_id } \ No newline at end of file diff --git a/terraform/environments/delius-core/modules/helpers/delius_microservice/variables.tf b/terraform/environments/delius-core/modules/helpers/delius_microservice/variables.tf index aedeb198c40..c22b94e3050 100644 --- a/terraform/environments/delius-core/modules/helpers/delius_microservice/variables.tf +++ b/terraform/environments/delius-core/modules/helpers/delius_microservice/variables.tf @@ -442,4 +442,44 @@ variable "deployment_maximum_percent" { type = number description = "The upper limit of the number of tasks (as a percentage of `desired_count`) that can be running in a service during a deployment" default = 100 +} + +variable "ignore_changes_task_definition" { + description = "Ignore changes to the task definition" + type = bool + default = true +} + +variable "redeploy_on_apply" { + description = "Redeploy the ecs service on apply" + type = bool + default = false +} + +variable "force_new_deployment" { + description = "Force a new deployment" + type = bool + default = false +} + +variable "ecs_service_ingress_security_group_ids" { + description = "Security group ids to allow ingress to the ECS service" + type = list(object({ + referenced_security_group_id = optional(string, null) + cidr_ipv4 = optional(string, null) + port = number + ip_protocol = string + })) + default = [] +} + +variable "ecs_service_egress_security_group_ids" { + description = "Security group ids to allow egress from the ECS service" + type = list(object({ + referenced_security_group_id = optional(string, null) + cidr_ipv4 = optional(string, null) + port = optional(number, null) + ip_protocol = string + })) + default = [] } \ No newline at end of file