Эх сурвалжийг харах

Adds Module for NLB+ALB+WAF with Static IP

I think this is a good thing? Look at `base/sensu/elb.tf` for usage
example.

Also updates dns modules to return list of fdqdn's instead of a map of
fqdns to empty lists.

To be tagged v4.1.12
Fred Damstra [afs macbook] 3 жил өмнө
parent
commit
6d69423055

+ 1 - 1
base/customer_portal/waf.tf

@@ -6,7 +6,7 @@ module "waf" {
   additional_blocked_ips = [ ] # NOTE: There is a standard list in the submodule
   admin_ips = concat(var.zscalar_ips, var.admin_ips)
   resource_arn = aws_alb.portal.arn
-  fqdns = keys(module.public_dns_record.forward) # first entry in list will be the WAF name
+  fqdns = module.public_dns_record.forward # first entry in list will be the WAF name
 
   excluded_rules_AWSManagedRulesCommonRuleSet = [
     "SizeRestrictions_BODY",

+ 0 - 79
base/sensu/certificate.tf

@@ -1,79 +0,0 @@
-#----------------------------------------------------------------------------
-# Private DNS Certificate
-#----------------------------------------------------------------------------
-
-
-resource "aws_acm_certificate" "cert" {
-  domain_name       = "sensu.${var.dns_info["private"]["zone"]}"
-  validation_method = "DNS"
-
-  lifecycle {
-    create_before_destroy = true
-  }
-
-  tags = merge(var.standard_tags, var.tags)
-}
-
-resource "aws_acm_certificate_validation" "cert" {
-  certificate_arn         = aws_acm_certificate.cert.arn
-  validation_record_fqdns = [for record in aws_route53_record.cert_validation: record.fqdn]
-}
-
-resource "aws_route53_record" "cert_validation" {
-  provider = aws.mdr-common-services-commercial
-
-  for_each = {
-    for dvo in aws_acm_certificate.cert.domain_validation_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             = 60
-  type            = each.value.type
-  zone_id         = var.dns_info["public"]["zone_id"]
-}
-
-#----------------------------------------------------------------------------
-# Public DNS Certificate
-#----------------------------------------------------------------------------
-
-
-resource "aws_acm_certificate" "cert_public" {
-  domain_name       = "sensu.${var.dns_info["public"]["zone"]}"
-  validation_method = "DNS"
-
-  lifecycle {
-    create_before_destroy = true
-  }
-
-  tags = merge(var.standard_tags, var.tags)
-}
-
-resource "aws_acm_certificate_validation" "cert_public" {
-  certificate_arn         = aws_acm_certificate.cert_public.arn
-  validation_record_fqdns = [for record in aws_route53_record.cert_validation_public: record.fqdn]
-}
-
-resource "aws_route53_record" "cert_validation_public" {
-  provider = aws.mdr-common-services-commercial
-
-  for_each = {
-    for dvo in aws_acm_certificate.cert_public.domain_validation_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             = 60
-  type            = each.value.type
-  zone_id         = var.dns_info["public"]["zone_id"]
-}

+ 41 - 246
base/sensu/elb.tf

@@ -1,228 +1,50 @@
-# lb ports
-locals {
-  alb_listener_ports = {
-       ui    = "8000"
-       api   = "8080"
-       agent = "8081"
-      }
-}
-
-#----------------------------------------------------------------------------
-# INTERNAL LB
-#----------------------------------------------------------------------------
-
-resource "aws_alb" "sensu_internal" {
-  name               = "sensu-alb-internal-${var.environment}"
-  security_groups    = [ aws_security_group.sensu_alb_server_internal.id ]
-  internal           = true 
-  subnets            = var.private_subnets
-  load_balancer_type = "application"
-
-
-  access_logs {
-    bucket  = "xdr-elb-${ var.environment }"
-    enabled = true
-  }
-
-  tags = merge(var.standard_tags, var.tags, { Name = "sensu-alb-internal-${var.environment}" })
-}
-
-resource "aws_alb_target_group" "sensu_internal" {
-  for_each = local.alb_listener_ports
-  name                 = "sensu-alb-targets-${each.key}"
-  port                 = each.value 
-  protocol             = "HTTPS"
-  #deregistration_delay = "${local.lb_deregistration_delay}"
-  vpc_id               = var.vpc_id
-
-  health_check {
-    protocol = "HTTPS"
-    port     = "8080"
-    path     = "/health"
-    matcher  = "200"
-    timeout  = "4"
-    interval = "5"
-  }
-
-  stickiness {
-    type    = "lb_cookie"
-    enabled = false 
-  }
-
-  tags = merge(var.standard_tags, var.tags)
-}
-
-resource "aws_lb_target_group_attachment" "sensu_internal" {
-  for_each = local.alb_listener_ports
-  target_group_arn = aws_alb_target_group.sensu_internal[each.key].arn
-  target_id        = aws_instance.instance.id
-  port             = each.value
-}
-
-# Create a new alb listener
-resource "aws_alb_listener" "sensu_internal" {
-  for_each = local.alb_listener_ports
-  load_balancer_arn = aws_alb.sensu_internal.arn
-  port              = each.value
-  protocol          = "HTTPS"
-  ssl_policy        = "ELBSecurityPolicy-FS-1-2-Res-2019-08" # PFS, TLS1.2, most "restrictive" policy (took awhile to find that)
-  certificate_arn   = aws_acm_certificate.cert.arn
-
-  default_action {
-    target_group_arn = aws_alb_target_group.sensu_internal[each.key].arn
-    type             = "forward"
-  }
-}
-
-#DNS Alias for the LB ( the CNAME was required. an Alias did NOT work due to aws/bug. )
-resource "aws_route53_record" "sensu_internal" {
-  zone_id = var.dns_info["private"]["zone_id"]
-  name    = var.instance_name 
-  type    = "CNAME" 
-  records = [aws_alb.sensu_internal.dns_name]
-  ttl = "60"
-  provider = aws.c2
-}
-
-#----------------------------------------------------------------------------
-# ALB Security Group
-#----------------------------------------------------------------------------
-
-resource "aws_security_group" "sensu_alb_server_internal" {
-  vpc_id      = var.vpc_id
-  name        = "sensu-alb-sg-internal"
-  description = "Sensu Internal LB SG"
+module "elb" {
+  source = "../../submodules/load_balancer/static_nlb_to_alb"
+
+  name = "sensu"
+  target_ids = [ aws_instance.instance.id ]
+  listener_port = 443
+  target_port = 8081
+  target_protocol = "HTTPS"
+  target_security_group = aws_security_group.instance_security_group.id
+  allow_from_any = false
+
+  # WAF variables
+  waf_enabled = true
+  #excluded_rules_AWSManagedRulesCommonRuleSet = [ "SizeRestrictions_BODY" ]
+  #excluded_rules_AWSManagedRulesAmazonIpReputationList = []
+  #excluded_rules_AWSManagedRulesKnownBadInputsRuleSet = []
+  #excluded_rules_AWSManagedRulesSQLiRuleSet = []
+  #excluded_rules_AWSManagedRulesLinuxRuleSet = []
+  #excluded_rules_AWSManagedRulesUnixRuleSet = []
+  #additional_blocked_ips = []
+  #allowed_ips = []
+  #admin_ips = []
+
+  # Optional Variables
+  healthcheck_port = 8080
+  healthcheck_protocol = "HTTPS"
+  healthcheck_path = "/health"
+  healthcheck_matcher = "200"
+  stickiness = false
+  
+  # Inherited Variables 
   tags = merge(var.standard_tags, var.tags)
-}
-
-#----------------------------------------------------------------------------
-# INGRESS
-#----------------------------------------------------------------------------
-
-
-resource "aws_security_group_rule" "sensu_from_vpc" {
-  for_each = local.alb_listener_ports
-  type              = "ingress"
-  from_port         = each.value
-  to_port           = each.value
-  protocol          = "tcp"
-  cidr_blocks       = ["10.0.0.0/8"]
-  description       = "Sensu ${each.key}"
-  security_group_id = aws_security_group.sensu_alb_server_internal.id
-}
-
-#----------------------------------------------------------------------------
-# EGRESS
-#----------------------------------------------------------------------------
-
-resource "aws_security_group_rule" "sensu_from_alb" {
-  for_each = local.alb_listener_ports
-  type              = "egress"
-  from_port         = each.value
-  to_port           = each.value
-  protocol          = "tcp"
-  source_security_group_id = aws_security_group.instance_security_group.id
-  description       = "Sensu ${each.key}"
-  security_group_id = aws_security_group.sensu_alb_server_internal.id
-}
-
-#----------------------------------------------------------------------------
-# EXTERNAL LB
-#----------------------------------------------------------------------------
-
-resource "aws_alb" "sensu_external" {
-  name               = "sensu-alb-external-${var.environment}"
-  security_groups    = [ aws_security_group.sensu_alb_server_external.id ]
-  internal           = false 
-  subnets            = var.public_subnets
-  load_balancer_type = "application"
-
-
-  access_logs {
-    bucket  = "xdr-elb-${ var.environment }"
-    enabled = true
-  }
-
-  tags = merge(var.standard_tags, var.tags, { Name = "sensu-alb-external-${var.environment}" })
-}
-
-# Create a new target group
-resource "aws_alb_target_group" "sensu_external" {
-  name                 = "sensu-alb-targets-agent-external"
-  port                 = 8081
-  protocol             = "HTTPS"
-  #deregistration_delay = "${local.lb_deregistration_delay}"
-  vpc_id               = var.vpc_id
-
-  health_check {
-    protocol = "HTTPS"
-    port     = "8080"
-    path     = "/health"
-    matcher  = "200"
-    timeout  = "4"
-    interval = "5"
-  }
-
-  stickiness {
-    type    = "lb_cookie"
-    enabled = false 
-  }
-
-  tags = merge(var.standard_tags, var.tags)
-}
-
-resource "aws_lb_target_group_attachment" "sensu_external" {
-  target_group_arn = aws_alb_target_group.sensu_external.arn
-  target_id        = aws_instance.instance.id
-  port             = 8081
-}
-
-# Create a new alb listener
-resource "aws_alb_listener" "sensu_https_external" {
-  load_balancer_arn = aws_alb.sensu_external.arn
-  port              = "443"
-  protocol          = "HTTPS"
-  ssl_policy        = "ELBSecurityPolicy-FS-1-2-Res-2019-08" # PFS, TLS1.2, most "restrictive" policy (took awhile to find that)
-  certificate_arn   = aws_acm_certificate.cert_public.arn
-
-  default_action {
-    target_group_arn = aws_alb_target_group.sensu_external.arn
-    type             = "forward"
-  }
-}
-
-# #########################
-# # DNS Entry
-module "public_dns_record" {
-  source = "../../submodules/dns/public_ALIAS_record"
-
-  name = var.instance_name
-  target_dns_name = aws_alb.sensu_external.dns_name
-  target_zone_id  = aws_alb.sensu_external.zone_id
   dns_info = var.dns_info
+  public_subnets = var.public_subnets
+  environment = var.environment
+  aws_partition = var.aws_partition
+  aws_region = var.aws_region
+  aws_account_id = var.aws_account_id
+  vpc_id = var.vpc_id
 
   providers = {
     aws.mdr-common-services-commercial = aws.mdr-common-services-commercial
+    aws.c2 = aws.c2
   }
 }
 
-#----------------------------------------------------------------------------
-# ALB Security Group
-#----------------------------------------------------------------------------
-
-resource "aws_security_group" "sensu_alb_server_external" {
-  vpc_id      = var.vpc_id
-  name        = "sensu-alb-sg-external"
-  description = "Sensu LB SG"
-  tags = merge(var.standard_tags, var.tags)
-}
-
-#----------------------------------------------------------------------------
-# INGRESS
-#----------------------------------------------------------------------------
-
 resource "aws_security_group_rule" "sensu-external-ips" {
-
   # This deserves some explanation.  Terraform "for_each" expects to be
   # getting as input a map of values to iterate over as part of the foreach.
   # The keys of the map are used to name each of these objects created.  Looking
@@ -240,36 +62,9 @@ resource "aws_security_group_rule" "sensu-external-ips" {
 
   description = "Sensu - ${each.value.description}"
   type = "ingress"
-  from_port = "443"
-  to_port = "443"
+  from_port = 443
+  to_port = 443
   protocol = "tcp"
   cidr_blocks = each.value.cidr_blocks
-  security_group_id = aws_security_group.sensu_alb_server_external.id
+  security_group_id = module.elb.security_group_id
 }
-
-
-
-#----------------------------------------------------------------------------
-# EGRESS
-#----------------------------------------------------------------------------
-
-resource "aws_security_group_rule" "alb_to_sensu_server" {
-  type              = "egress"
-  from_port         = 8081
-  to_port           = 8081
-  protocol          = "tcp"
-  source_security_group_id = aws_security_group.instance_security_group.id
-  description       = "Allows the ALB to talk to the Sensu servers"
-  security_group_id = aws_security_group.sensu_alb_server_external.id
-}
-
-resource "aws_security_group_rule" "alb_to_sensu_health" {
-  type              = "egress"
-  from_port         = 8080
-  to_port           = 8080
-  protocol          = "tcp"
-  source_security_group_id = aws_security_group.instance_security_group.id
-  description       = "Allows the ALB to talk to the Sensu Health check"
-  security_group_id = aws_security_group.sensu_alb_server_external.id
-}
-

+ 2 - 2
base/sensu/main.tf

@@ -231,7 +231,7 @@ resource "aws_security_group_rule" "sensu_agent_external" {
   from_port         = 8081
   to_port           = 8081
   protocol          = "tcp"
-  source_security_group_id = aws_security_group.sensu_alb_server_external.id
+  source_security_group_id = module.elb.security_group_id
   description       = "External Sensu Agents"
   security_group_id = aws_security_group.instance_security_group.id
 }
@@ -241,7 +241,7 @@ resource "aws_security_group_rule" "sensu_api_external" {
   from_port         = 8080
   to_port           = 8080
   protocol          = "tcp"
-  source_security_group_id = aws_security_group.sensu_alb_server_external.id
+  source_security_group_id = module.elb.security_group_id
   description       = "External Sensu API"
   security_group_id = aws_security_group.instance_security_group.id
 }

+ 9 - 1
base/sensu/outputs.tf

@@ -8,4 +8,12 @@ output instance_private_ip {
 
 output internal_alb_address {
   value = aws_alb.sensu_internal.dns_name
-}
+}
+
+output static_ips {
+  value = module.elb.static_ips
+}
+
+output fqdn {
+  value = module.elb.forward
+}

+ 37 - 0
base/sensu/private_certificate.tf

@@ -0,0 +1,37 @@
+#----------------------------------------------------------------------------
+# Private DNS Certificate
+#----------------------------------------------------------------------------
+resource "aws_acm_certificate" "cert" {
+  domain_name       = "sensu.${var.dns_info["private"]["zone"]}"
+  validation_method = "DNS"
+
+  lifecycle {
+    create_before_destroy = true
+  }
+
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_acm_certificate_validation" "cert" {
+  certificate_arn         = aws_acm_certificate.cert.arn
+  validation_record_fqdns = [for record in aws_route53_record.cert_validation: record.fqdn]
+}
+
+resource "aws_route53_record" "cert_validation" {
+  provider = aws.mdr-common-services-commercial
+
+  for_each = {
+    for dvo in aws_acm_certificate.cert.domain_validation_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             = 60
+  type            = each.value.type
+  zone_id         = var.dns_info["public"]["zone_id"]
+}

+ 127 - 0
base/sensu/private_elb.tf

@@ -0,0 +1,127 @@
+# lb ports
+locals {
+  alb_listener_ports = {
+       ui    = "8000"
+       api   = "8080"
+       agent = "8081"
+      }
+}
+
+#----------------------------------------------------------------------------
+# INTERNAL LB
+#----------------------------------------------------------------------------
+
+resource "aws_alb" "sensu_internal" {
+  name               = "sensu-alb-internal-${var.environment}"
+  security_groups    = [ aws_security_group.sensu_alb_server_internal.id ]
+  internal           = true
+  subnets            = var.private_subnets
+  load_balancer_type = "application"
+
+
+  access_logs {
+    bucket  = "xdr-elb-${ var.environment }"
+    enabled = true
+  }
+
+  tags = merge(var.standard_tags, var.tags, { Name = "sensu-alb-internal-${var.environment}" })
+}
+
+resource "aws_alb_target_group" "sensu_internal" {
+  for_each = local.alb_listener_ports
+  name                 = "sensu-alb-targets-${each.key}"
+  port                 = each.value
+  protocol             = "HTTPS"
+  #deregistration_delay = "${local.lb_deregistration_delay}"
+  vpc_id               = var.vpc_id
+
+  health_check {
+    protocol = "HTTPS"
+    port     = "8080"
+    path     = "/health"
+    matcher  = "200"
+    timeout  = "4"
+    interval = "5"
+  }
+
+  stickiness {
+    type    = "lb_cookie"
+    enabled = false
+  }
+
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_lb_target_group_attachment" "sensu_internal" {
+  for_each = local.alb_listener_ports
+  target_group_arn = aws_alb_target_group.sensu_internal[each.key].arn
+  target_id        = aws_instance.instance.id
+  port             = each.value
+}
+
+# Create a new alb listener
+resource "aws_alb_listener" "sensu_internal" {
+  for_each = local.alb_listener_ports
+  load_balancer_arn = aws_alb.sensu_internal.arn
+  port              = each.value
+  protocol          = "HTTPS"
+  ssl_policy        = "ELBSecurityPolicy-FS-1-2-Res-2019-08" # PFS, TLS1.2, most "restrictive" policy (took awhile to find that)
+  certificate_arn   = aws_acm_certificate.cert.arn
+
+  default_action {
+    target_group_arn = aws_alb_target_group.sensu_internal[each.key].arn
+    type             = "forward"
+  }
+}
+
+#DNS Alias for the LB ( the CNAME was required. an Alias did NOT work due to aws/bug. )
+resource "aws_route53_record" "sensu_internal" {
+  zone_id = var.dns_info["private"]["zone_id"]
+  name    = var.instance_name
+  type    = "CNAME"
+  records = [aws_alb.sensu_internal.dns_name]
+  ttl = "60"
+  provider = aws.c2
+}
+
+#----------------------------------------------------------------------------
+# ALB Security Group
+#----------------------------------------------------------------------------
+
+resource "aws_security_group" "sensu_alb_server_internal" {
+  vpc_id      = var.vpc_id
+  name        = "sensu-alb-sg-internal"
+  description = "Sensu Internal LB SG"
+  tags = merge(var.standard_tags, var.tags)
+}
+
+#----------------------------------------------------------------------------
+# INGRESS
+#----------------------------------------------------------------------------
+
+
+resource "aws_security_group_rule" "sensu_from_vpc" {
+  for_each = local.alb_listener_ports
+  type              = "ingress"
+  from_port         = each.value
+  to_port           = each.value
+  protocol          = "tcp"
+  cidr_blocks       = ["10.0.0.0/8"]
+  description       = "Sensu ${each.key}"
+  security_group_id = aws_security_group.sensu_alb_server_internal.id
+}
+
+#----------------------------------------------------------------------------
+# EGRESS
+#----------------------------------------------------------------------------
+
+resource "aws_security_group_rule" "sensu_from_alb" {
+  for_each = local.alb_listener_ports
+  type              = "egress"
+  from_port         = each.value
+  to_port           = each.value
+  protocol          = "tcp"
+  source_security_group_id = aws_security_group.instance_security_group.id
+  description       = "Sensu ${each.key}"
+  security_group_id = aws_security_group.sensu_alb_server_internal.id
+}

+ 1 - 1
base/splunk_servers/customer_searchhead/waf.tf

@@ -7,7 +7,7 @@ module "waf" {
   additional_blocked_ips = [ ] # NOTE: There is a standard list in the submodule
   resource_arn = aws_lb.searchhead-alb.arn
   fqdns = concat( # first entry in list will be the WAF name
-    keys(module.public_dns_record_cust-elb.forward),
+    module.public_dns_record_cust-elb.forward,
     # example, to add additional valid hostnames
     #    keys(module.public_dns_record_cust-auth-elb.forward),
   )

+ 1 - 2
submodules/dns/private_A_record/outputs.tf

@@ -1,6 +1,5 @@
 output "forward" { 
-  # Parenthesis required to resolve ambiguity
-  value = { for entry in aws_route53_record.dns: entry.fqdn => entry.records }
+  value = [ for entry in aws_route53_record.dns: entry.fqdn ]
 }
 
 output "reverse" {

+ 1 - 2
submodules/dns/private_CNAME_record/outputs.tf

@@ -1,4 +1,3 @@
 output "forward" { 
-  # Parenthesis required to resolve ambiguity
-  value = { for entry in aws_route53_record.dns: entry.fqdn => entry.records }
+  value = [ for entry in aws_route53_record.dns: entry.fqdn ]
 }

+ 1 - 1
submodules/dns/public_A_record/outputs.tf

@@ -1,4 +1,4 @@
 output "forward" { 
   # Parenthesis required to resolve ambiguity
-  value = { for entry in aws_route53_record.dns: entry.fqdn => entry.records }
+  value = [ for entry in aws_route53_record.dns: entry.fqdn ]
 }

+ 1 - 2
submodules/load_balancer/public_alb/outputs.tf

@@ -3,6 +3,5 @@ output "alb_arn" {
 }
 
 output "fqdns" {
-  # Fully Qualified Domain Names
-  value = keys(module.public_dns_record.forward)
+  value = module.public_dns_record.forward
 }

+ 37 - 0
submodules/load_balancer/static_nlb_to_alb/certificate.tf

@@ -0,0 +1,37 @@
+#----------------------------------------------------------------------------
+# Public DNS Certificate
+#----------------------------------------------------------------------------
+resource "aws_acm_certificate" "cert_public" {
+  domain_name       = "${var.name}.${var.dns_info["public"]["zone"]}"
+  validation_method = "DNS"
+
+  lifecycle {
+    create_before_destroy = true
+  }
+
+  tags = var.tags
+}
+
+resource "aws_acm_certificate_validation" "cert_public" {
+  certificate_arn         = aws_acm_certificate.cert_public.arn
+  validation_record_fqdns = [for record in aws_route53_record.cert_validation_public: record.fqdn]
+}
+
+resource "aws_route53_record" "cert_validation_public" {
+  provider = aws.mdr-common-services-commercial
+
+  for_each = {
+    for dvo in aws_acm_certificate.cert_public.domain_validation_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             = 60
+  type            = each.value.type
+  zone_id         = var.dns_info["public"]["zone_id"]
+}

+ 14 - 0
submodules/load_balancer/static_nlb_to_alb/dns.tf

@@ -0,0 +1,14 @@
+# #########################
+# # DNS Entry
+module "public_dns_record" {
+  source = "../../../submodules/dns/public_ALIAS_record"
+
+  name = var.name
+  target_dns_name = aws_lb.static.dns_name
+  target_zone_id  = aws_lb.static.zone_id
+  dns_info = var.dns_info
+
+  providers = {
+    aws.mdr-common-services-commercial = aws.mdr-common-services-commercial
+  }
+}

+ 64 - 0
submodules/load_balancer/static_nlb_to_alb/elb.tf

@@ -0,0 +1,64 @@
+#----------------------------------------------------------------------------
+# EXTERNAL LB
+#----------------------------------------------------------------------------
+resource "aws_lb" "external" {
+  name_prefix        = substr("${var.name}-ext-lb", 0, 6)
+  security_groups    = [ aws_security_group.lb_server_external.id ]
+  internal           = false 
+  subnets            = var.public_subnets
+  load_balancer_type = "application"
+
+  access_logs {
+    bucket  = "xdr-elb-${ var.environment }"
+    enabled = true
+  }
+
+  tags = merge(var.tags, { Name = "${var.name}-lb-external-${var.environment}" })
+}
+
+# Create a new target group
+resource "aws_lb_target_group" "external" {
+  name_prefix        = substr("${var.name}-ext-lb", 0, 6)
+  port                 = var.target_port
+  protocol             = var.target_protocol
+  #deregistration_delay = "${local.lb_deregistration_delay}"
+  vpc_id               = var.vpc_id
+
+  health_check {
+    protocol = local.healthcheck_protocol
+    port     = local.healthcheck_port
+    path     = var.healthcheck_path
+    matcher  = var.healthcheck_matcher
+    timeout  = "4"
+    interval = "5"
+  }
+
+  stickiness {
+    type    = "lb_cookie"
+    enabled = var.stickiness
+  }
+
+  tags = merge(var.tags, { Name = "${var.name}-lb-external-${var.environment}" })
+}
+
+resource "aws_lb_target_group_attachment" "external" {
+  for_each         = var.target_ids
+
+  target_group_arn = aws_lb_target_group.external.arn
+  target_id        = each.value
+  port             = var.target_port
+}
+
+# Create a new alb listener
+resource "aws_lb_listener" "https_external" {
+  load_balancer_arn = aws_lb.external.arn
+  port              = var.listener_port
+  protocol          = "HTTPS"
+  ssl_policy        = "ELBSecurityPolicy-FS-1-2-Res-2019-08" # PFS, TLS1.2, most "restrictive" policy (took awhile to find that)
+  certificate_arn   = aws_acm_certificate.cert_public.arn
+
+  default_action {
+    target_group_arn = aws_lb_target_group.external.arn
+    type             = "forward"
+  }
+}

+ 61 - 0
submodules/load_balancer/static_nlb_to_alb/nlb.tf

@@ -0,0 +1,61 @@
+#########################
+# EIP
+resource "aws_eip" "static" {
+  count = 2
+  vpc = true
+
+  tags = merge(var.tags, { Name = "${var.name}-nlb-external-${var.environment}" })
+}
+
+#########################
+# ELB
+resource "aws_lb" "static" {
+  name_prefix        = substr("${var.name}-static", 0, 6)
+  load_balancer_type = "network"
+  internal           = false
+
+  subnet_mapping {
+    subnet_id     = var.public_subnets[0]
+    allocation_id = aws_eip.static[0].id
+  }
+
+  subnet_mapping {
+    subnet_id     = var.public_subnets[1]
+    allocation_id = aws_eip.static[1].id
+  }
+
+  access_logs {
+    bucket  = "xdr-elb-${ var.environment }"
+    enabled = true
+  }
+
+  tags = merge(var.tags, { Name = "${var.name}-nlb-external-${var.environment}" })
+}
+
+resource "aws_lb_listener" "static" {
+  load_balancer_arn = aws_lb.static.arn
+  port              = var.listener_port
+  protocol          = "TCP"
+  default_action {
+    type = "forward"
+    target_group_arn = aws_lb_target_group.static.arn
+  }
+
+  tags = merge(var.tags, { Name = "${var.name}-nlb-external-${var.environment}" })
+}
+
+resource "aws_lb_target_group" "static" {
+  name_prefix  = substr("${var.name}-static", 0, 6)
+  port         = var.listener_port
+  protocol     = "TCP"
+  target_type  = "alb"
+  vpc_id       = var.vpc_id
+
+  tags = merge(var.tags, { Name = "${var.name}-nlb-external-${var.environment}" })
+}
+
+resource "aws_lb_target_group_attachment" "static" {
+  target_group_arn = aws_lb_target_group.static.arn
+  target_id        = aws_lb.external.id
+  port             = var.listener_port
+}

+ 19 - 0
submodules/load_balancer/static_nlb_to_alb/outputs.tf

@@ -0,0 +1,19 @@
+output "security_group_id" {
+  value = aws_security_group.lb_server_external.id
+}
+
+output "alb_id" {
+  value = aws_lb.external.id
+}
+
+output "nlb_id" {
+  value = aws_lb.static.id
+}
+
+output "static_ips" {
+  value = aws_eip.static[*].public_ip
+}
+
+output "forward" {
+  value = module.public_dns_record.forward
+}

+ 9 - 0
submodules/load_balancer/static_nlb_to_alb/provider-submodule.tf

@@ -0,0 +1,9 @@
+terraform {
+  required_providers {
+    aws = {
+      source = "hashicorp/aws"
+      #version = "= 4.4.0"
+      configuration_aliases = [ aws.mdr-common-services-commercial, aws.c2 ]
+    }
+  }
+}

+ 49 - 0
submodules/load_balancer/static_nlb_to_alb/security-groups.tf

@@ -0,0 +1,49 @@
+#----------------------------------------------------------------------------
+# ALB Security Group
+#----------------------------------------------------------------------------
+resource "aws_security_group" "lb_server_external" {
+  vpc_id      = var.vpc_id
+  name_prefix = "${var.name}-alb-sg-external"
+  description = "${var.name} LB SG"
+  tags = var.tags
+}
+
+#----------------------------------------------------------------------------
+# INGRESS
+#----------------------------------------------------------------------------
+resource "aws_security_group_rule" "allow_from_any" {
+  count = var.allow_from_any ? 1 : 0
+
+  description = "${var.name} - Allow from Any"
+  type = "ingress"
+  from_port = var.listener_port
+  to_port = var.listener_port
+  protocol = "tcp"
+  cidr_blocks = [ "0.0.0.0/0" ]
+  security_group_id = aws_security_group.lb_server_external.id
+}
+
+#----------------------------------------------------------------------------
+# EGRESS
+#----------------------------------------------------------------------------
+resource "aws_security_group_rule" "alb_to_servers" {
+  type              = "egress"
+  from_port         = var.target_port
+  to_port           = var.target_port
+  protocol          = "tcp"
+  source_security_group_id = var.target_security_group
+  description       = "${var.name} - Allows the ALB to talk to the servers"
+  security_group_id = aws_security_group.lb_server_external.id
+}
+
+resource "aws_security_group_rule" "alb_to_health" {
+  count = var.target_port != var.healthcheck_port ? 1 : 0
+
+  type              = "egress"
+  from_port         = var.healthcheck_port
+  to_port           = var.healthcheck_port
+  protocol          = "tcp"
+  source_security_group_id = var.target_security_group
+  description       = "${var.name} - Allows the ALB to talk to the Health check"
+  security_group_id = aws_security_group.lb_server_external.id
+}

+ 137 - 0
submodules/load_balancer/static_nlb_to_alb/vars.tf

@@ -0,0 +1,137 @@
+variable "name" { 
+  description = "The shortname for DNS and resources."
+  type = string
+}
+
+variable "target_ids" {
+  description = "List of targets to assign to the ALB"
+  type = set(string)
+}
+
+variable "allow_from_any" {
+  description = "Open the ALB to 0.0.0.0/0? If not, you must create your own rules."
+  type = bool
+  default = true
+}
+
+variable "listener_port" {
+  description = "Public Facing Port"
+  type = number
+}
+
+variable "target_port" {
+  description = "Port on Instance"
+  type = number
+}
+
+variable "target_protocol" {
+  description = "Protocol on Instance"
+  type = string
+}
+
+variable "target_security_group" {
+  description = "A target security group to allow egress from the ALB"
+  type = string
+}
+
+# Health Check Variables have sane defaults
+variable "healthcheck_port" {
+  description = "Health Check Port on Instance"
+  type = number
+  default = null
+}
+
+variable "healthcheck_protocol" {
+  description = "Health Check Protocol on Instance"
+  type = string
+  default = null
+}
+
+variable "healthcheck_path" {
+  description = "Health Check Path on Instance"
+  type = string
+  default = "/"
+}
+
+variable "healthcheck_matcher" {
+  description = "Health Check Match Conditions"
+  type = string
+  default = "200,302"
+}
+
+variable "stickiness" {
+  description = "Session Stickiness enabled?"
+  type = bool
+  default = false
+}
+
+locals {
+  healthcheck_port = var.healthcheck_port == null ? var.target_port : var.healthcheck_port
+  healthcheck_protocol = var.healthcheck_protocol == null ? var.target_protocol : var.healthcheck_protocol
+}
+
+# WAF passthrough variables
+variable "waf_enabled" {
+  type = bool
+  description = "Enable the standard WAF?"
+}
+
+variable "excluded_rules_AWSManagedRulesCommonRuleSet" {
+  type = list(string)
+  default = [
+    "SizeRestrictions_BODY"  # Breaks too many things
+  ]
+}
+
+variable "excluded_rules_AWSManagedRulesAmazonIpReputationList" {
+  type = list(string)
+  default = [ ]
+}
+
+variable "excluded_rules_AWSManagedRulesKnownBadInputsRuleSet" {
+  type = list(string)
+  default = [ ]
+}
+
+variable "excluded_rules_AWSManagedRulesSQLiRuleSet" {
+  type = list(string)
+  default = [ ]
+}
+
+variable "excluded_rules_AWSManagedRulesLinuxRuleSet" {
+  type = list(string)
+  default = [ ]
+}
+
+variable "excluded_rules_AWSManagedRulesUnixRuleSet" {
+  type = list(string)
+  default = [ ]
+}
+
+variable "additional_blocked_ips" {
+  description = "IP addresses that are blocked, in addition to the defaults."
+  type = list(string)
+  default = [ ]
+}
+
+variable "allowed_ips" {
+  description = "IP Addresses that are always allowed"
+  type = list(string)
+  default = [ ]
+}
+
+variable "admin_ips" {
+  description = "IP Addressed that are allowed to the admin interface"
+  type = list(string)
+  default = [ ]
+}
+
+# Inherited variables
+variable "dns_info" { type = map }
+variable "tags" { type = map }
+variable "public_subnets" { type = list }
+variable "environment" { type = string }
+variable "vpc_id" { type = string }
+variable "aws_partition" { type = string }
+variable "aws_region" { type = string }
+variable "aws_account_id" { type = string }

+ 27 - 0
submodules/load_balancer/static_nlb_to_alb/waf.tf

@@ -0,0 +1,27 @@
+module "waf" {
+  count = var.waf_enabled ? 1 : 0
+
+  source = "../../../submodules/wafv2"
+
+  # Custom to resource
+  allowed_ips = var.allowed_ips
+  additional_blocked_ips = var.additional_blocked_ips
+  admin_ips = var.admin_ips #concat(var.zscalar_ips, var.admin_ips)
+
+  resource_arn = aws_lb.external.arn
+  fqdns = module.public_dns_record.forward # first entry in list will be the WAF name
+
+  # Passthrough
+  excluded_rules_AWSManagedRulesCommonRuleSet = var.excluded_rules_AWSManagedRulesCommonRuleSet 
+  excluded_rules_AWSManagedRulesAmazonIpReputationList = var.excluded_rules_AWSManagedRulesAmazonIpReputationList
+  excluded_rules_AWSManagedRulesKnownBadInputsRuleSet = var.excluded_rules_AWSManagedRulesKnownBadInputsRuleSet
+  excluded_rules_AWSManagedRulesSQLiRuleSet = var.excluded_rules_AWSManagedRulesSQLiRuleSet
+  excluded_rules_AWSManagedRulesLinuxRuleSet = var.excluded_rules_AWSManagedRulesLinuxRuleSet
+  excluded_rules_AWSManagedRulesUnixRuleSet = var.excluded_rules_AWSManagedRulesUnixRuleSet
+
+  # These are passed through and should be the same for module
+  aws_partition = var.aws_partition
+  aws_region = var.aws_region
+  aws_account_id = var.aws_account_id
+  tags = merge(var.tags, { Name = "${var.name}-lb-external-${var.environment}" })
+}