Browse Source

Merge pull request #83 from mdr-engineering/feature/ftd_MSOCI-1447_OpenVPN_to_GCTest_ELB

Puts an NLB in front of the openvpn server(s)
Frederick Damstra 4 years ago
parent
commit
81d42f8329

+ 31 - 0
base/openvpn/certificate.tf

@@ -0,0 +1,31 @@
+#Certificate 
+resource "aws_acm_certificate" "cert" {
+  domain_name       = "openvpn.${var.dns_info["public"]["zone"]}"
+  validation_method = "DNS"
+
+  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"]
+}

+ 161 - 0
base/openvpn/elb.tf

@@ -0,0 +1,161 @@
+resource "aws_lb" "openvpn-nlb" {
+  name               = "openvpn-nlb"
+  internal           = false
+  load_balancer_type = "network"
+  # Not supported for NLB
+  #security_groups    = [aws_security_group.openvpn-nlb-sg.id]
+  # Note, changing subnets results in recreation of the resource
+  subnets            = var.public_subnets
+  enable_cross_zone_load_balancing = true
+
+  # TODO
+  #access_logs {
+  #  bucket  = aws_s3_bucket.lb_logs.bucket
+  #  prefix  = "test-lb"
+  #  enabled = true
+  #}
+
+  tags = merge(var.standard_tags, var.tags)
+}
+
+#########################
+# Listeners
+resource "aws_lb_listener" "openvpn-nlb-listener-https" {
+  load_balancer_arn = aws_lb.openvpn-nlb.arn
+  port              = "443"
+  protocol          = "TLS"
+  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 {
+    type             = "forward"
+    target_group_arn = aws_lb_target_group.openvpn-nlb-target-https.arn
+  }
+}
+
+# Only alb's can redirect
+#resource "aws_lb_listener" "openvpn-nlb-listener-http" {
+#  load_balancer_arn = aws_lb.openvpn-nlb.arn
+#  port              = "80"
+#  protocol          = "HTTP"
+#
+#  default_action {
+#    type             = "redirect"
+#
+#    redirect {
+#      port        = "443"
+#      protocol    = "HTTPS"
+#      status_code = "HTTP_301"
+#    }
+#  }
+#}
+
+resource "aws_lb_listener" "openvpn-nlb-listener-openvpn" {
+  load_balancer_arn = aws_lb.openvpn-nlb.arn
+  port              = "1194"
+  protocol          = "UDP"
+
+  default_action {
+    type             = "forward"
+    target_group_arn = aws_lb_target_group.openvpn-nlb-target-openvpn.arn
+  }
+}
+
+
+#########################
+# Targets
+resource "aws_lb_target_group" "openvpn-nlb-target-https" {
+  name     = "openvpn-nlb-target-https"
+  port     = 443
+  protocol = "TLS"
+  target_type = "instance"
+  vpc_id   = var.vpc_id
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_lb_target_group_attachment" "openvpn-nlb-target-https-instance" {
+  target_group_arn = aws_lb_target_group.openvpn-nlb-target-https.arn
+  target_id        = aws_instance.instance.id
+  port             = 443
+}
+
+resource "aws_lb_target_group" "openvpn-nlb-target-openvpn" {
+  name     = "openvpn-nlb-target-openvpn"
+  port     = 1194
+  protocol = "UDP"
+  target_type = "instance"
+  vpc_id   = var.vpc_id
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_lb_target_group_attachment" "openvpn-nlb-target-openvpn-instance" {
+  target_group_arn = aws_lb_target_group.openvpn-nlb-target-openvpn.arn
+  target_id        = aws_instance.instance.id
+  port             = 1194
+}
+
+
+#########################
+# Security Group for NLB
+# 
+# From tf: 
+# Error: error creating network Load Balancer: InvalidConfigurationRequest: Security groups are not supported for load balancers with type 'network'
+#resource "aws_security_group" "openvpn-nlb-sg" {
+#  name = "openvpn_nlb_sg"
+#  description = "Security Group for the OpenVPN NLB"
+#  vpc_id = var.vpc_id
+#  tags = merge(var.standard_tags, var.tags)
+#}
+#
+#resource "aws_security_group_rule" "openvpn-nlb-in" {
+#  type              = "ingress"
+#  from_port         = 1194
+#  to_port           = 1194
+#  protocol          = "udp"
+#  cidr_blocks       = [ "0.0.0.0/0" ]
+#  security_group_id = aws_security_group.openvpn-nlb-sg.id
+#}
+#
+#resource "aws_security_group_rule" "openvpn-nlb-https-in" {
+#  type              = "ingress"
+#  from_port         = 443
+#  to_port           = 443
+#  protocol          = "tcp"
+#  cidr_blocks       = [ "0.0.0.0/0" ]
+#  security_group_id = aws_security_group.openvpn-nlb-sg.id
+#}
+#
+#resource "aws_security_group_rule" "openvpn-nlb-out" {
+#  type              = "egress"
+#  from_port         = 1194
+#  to_port           = 1194
+#  protocol          = "udp"
+#  # Maybe should limit to the local vpc, but I don't readily have that cidr available
+#  cidr_blocks       = [ "10.0.0.0/8" ]
+#  security_group_id = aws_security_group.openvpn-nlb-sg.id
+#}
+#
+#resource "aws_security_group_rule" "openvpn-nlb-https-out" {
+#  type              = "egress"
+#  from_port         = 443
+#  to_port           = 443
+#  protocol          = "tcp"
+#  # Maybe should limit to the local vpc, but I don't readily have that cidr available
+#  cidr_blocks       = [ "10.0.0.0/8" ]
+#  security_group_id = aws_security_group.openvpn-nlb-sg.id
+#}
+
+#########################
+# DNS Entry
+module "public_dns_record" {
+  source = "../../submodules/dns/public_ALIAS_record"
+
+  name = var.instance_name
+  target_dns_name = aws_lb.openvpn-nlb.dns_name
+  target_zone_id  = aws_lb.openvpn-nlb.zone_id
+  dns_info = var.dns_info
+
+  providers = {
+    aws.mdr-common-services-commercial = aws.mdr-common-services-commercial
+  }
+}

+ 3 - 23
base/openvpn/main.tf

@@ -22,16 +22,6 @@ resource "aws_network_interface" "instance" {
   tags = merge(var.standard_tags, var.tags, { Name = var.instance_name })
 }
 
-resource "aws_eip" "instance" {
-  vpc = true
-  tags = merge(var.standard_tags, var.tags, { Name = var.instance_name })
-}
-
-resource "aws_eip_association" "instance" {
-  network_interface_id = aws_network_interface.instance.id
-  allocation_id = aws_eip.instance.id
-}
-
 resource "aws_instance" "instance" {
   #availability_zone = var.azs[count.index % 2]
   tenancy = "default"
@@ -151,18 +141,6 @@ module "private_dns_record" {
   }
 }
 
-module "public_dns_record" {
-  source = "../../submodules/dns/public_A_record"
-
-  name = var.instance_name
-  ip_addresses = [ aws_eip.instance.public_ip ]
-  dns_info = var.dns_info
-
-  providers = {
-    aws.mdr-common-services-commercial = aws.mdr-common-services-commercial
-  }
-}
-
 data "template_file" "cloud-init" {
   # Should these be in a common directory? I suspect they'd be reusable
   template = "${file("${path.module}/cloud-init/cloud-init.tpl")}"
@@ -200,7 +178,7 @@ data "template_cloudinit_config" "cloud-init" {
 
 resource "aws_security_group" "openvpn_security_group" {
   name = "openvpn_security_group"
-  description = "Security Group for Bastion Server(s)"
+  description = "Security Group for OpenVPN Instance(s)"
   vpc_id = var.vpc_id
   tags = merge(var.standard_tags, var.tags)
 }
@@ -210,6 +188,7 @@ resource "aws_security_group_rule" "openvpn-in" {
   from_port         = 1194
   to_port           = 1194
   protocol          = "udp"
+  # NOTE: For NLBs, the source IP is the public IP, so the security group must allow public access.
   cidr_blocks       = [ "0.0.0.0/0" ]
   security_group_id = aws_security_group.openvpn_security_group.id
 }
@@ -219,6 +198,7 @@ resource "aws_security_group_rule" "openvpn-https-in" {
   from_port         = 443
   to_port           = 443
   protocol          = "tcp"
+  # NOTE: For NLBs, the source IP is the public IP, so the security group must allow public access.
   cidr_blocks       = [ "0.0.0.0/0" ]
   security_group_id = aws_security_group.openvpn_security_group.id
 }

+ 2 - 2
base/openvpn/outputs.tf

@@ -2,8 +2,8 @@ output instance_arn {
   value = aws_instance.instance.arn
 }
 
-output instance_public_ip {
-  value = aws_eip.instance.public_ip
+output public-name {
+  value = aws_lb.openvpn-nlb.dns_name
 }
 
 output instance_private_ip {

+ 4 - 0
base/openvpn/vars.tf

@@ -11,6 +11,10 @@ variable "subnets" {
   type = list(string)
 }
 
+variable "public_subnets" {
+  type = list(string)
+}
+
 variable "vpc_id" {
   type = string
 }

+ 15 - 0
submodules/dns/public_ALIAS_record/main.tf

@@ -0,0 +1,15 @@
+resource "aws_route53_record" "dns" {
+  count = var.enabled ? 1 : 0
+
+  name = var.name
+  type = "A"
+  zone_id = var.dns_info["public"]["zone_id"]
+
+  alias {
+    name                   = var.target_dns_name
+    zone_id                = var.target_zone_id
+    evaluate_target_health = false #don't care, return an answer regardless
+  }
+
+  provider = aws.mdr-common-services-commercial
+}

+ 4 - 0
submodules/dns/public_ALIAS_record/outputs.tf

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

+ 3 - 0
submodules/dns/public_ALIAS_record/provider.tf

@@ -0,0 +1,3 @@
+provider "aws" {
+  alias = "mdr-common-services-commercial"
+}

+ 10 - 0
submodules/dns/public_ALIAS_record/vars.tf

@@ -0,0 +1,10 @@
+variable "enabled" {
+  description = "Set to false to do nothing"
+  type = bool
+  default = true
+}
+
+variable "name" { type = string }
+variable "target_dns_name" { type = string }
+variable "target_zone_id" { type = string }
+variable "dns_info" { type = map }