Didn't be able to make it work w/ HTTP/2, therefore this configuration expects the container to understand HTTP/1.
<env>/main.tf
module "elb" {
source = "../modules/elb"
vpc_id = local.vpc_id
lb_target_name_prefix = substr("${local.ci}-", 0, 6) #Max 6 chars
lb_subnet_internal_ids = local.subnet_web_ids
lb_internal_name = "${local.env}-${local.ci}-lb-internal"
lb_internal_certificate_arn = module.acm.certificate_arn
lb_internal_ingress_cidr_blocks = local.lb_internal_ingress_cidr_blocks
lb_subnet_external_ids = local.subnet_public_ids
lb_external_name = "${local.env}-${local.ci}-lb-external"
lb_external_certificate_arn = module.acm.certificate_arn
}
modules/elb-albs/variables.tf
variable "vpc_id" {}
variable "lb_target_name_prefix" {} #Max 6 chars
### LB EXTERNAL
variable "lb_subnet_external_ids" {}
variable "lb_external_name" {}
variable "lb_external_certificate_arn" {}
### LB INTERNAL
variable "lb_subnet_internal_ids" {}
variable "lb_internal_name" {}
variable "lb_internal_certificate_arn" {}
variable "lb_internal_ingress_cidr_blocks" {}
modules/elb/albs.tf
locals {
env = data.aws_default_tags.dt.tags.env
ci = data.aws_default_tags.dt.tags.ci
}
data "aws_default_tags" "dt" {
}
################################################################################
# VPC > Security Groups
################################################################################
#SG ELB INTERNAL (no WAF, only ingress from specific cidr blocks)
resource "aws_security_group" "sg_elb_internal" {
lifecycle {
create_before_destroy = true
}
#description = #(Optional, Forces new resource) Security group description. Defaults to Managed by Terraform
#name = # (Optional, Forces new resource) If omitted, Terraform will assign a random, unique name
name_prefix = "${local.env}-${local.ci}-sg-elb-internal-"
revoke_rules_on_delete = true
vpc_id = var.vpc_id
}
# Allows inbound traffic [ELB]
resource "aws_vpc_security_group_ingress_rule" "sg_elb_internal_ingress" {
for_each = toset(var.lb_internal_ingress_cidr_blocks)
cidr_ipv4 = each.key #(Optional) The source IPv4 CIDR range
#cidr_ipv6 #(Optional) The source IPv6 CIDR range
description = "Allows inbound traffic from specific cidr_blocks"
from_port = 443 # Required unless ip_protocol is set to -1 or icmpv6
ip_protocol = "tcp" # Values: "tcp", "-1", etc.
#referenced_security_group_id = #(Optional) The source security group that is referenced in the rule
security_group_id = aws_security_group.sg_elb_internal.id
to_port = 443 # Required unless ip_protocol is set to -1 or icmpv6
}
# Allows all outbound traffic (IPv4) [ELB]
resource "aws_vpc_security_group_egress_rule" "sg_elb_internal_egress_ipv4" {
cidr_ipv4 = "0.0.0.0/0"
#cidr_ipv6 = "::/0"
description = "Allow all outbound traffic (IPv4)"
#from_port # Required unless ip_protocol is set to -1 or icmpv6
ip_protocol = "-1"
security_group_id = aws_security_group.sg_elb_internal.id
#to_port # Required unless ip_protocol is set to -1 or icmpv6
}
# Allows all outbound traffic (IPv6) [ELB]
resource "aws_vpc_security_group_egress_rule" "sg_elb_internal_egress_ipv6" {
#cidr_ipv4 = "0.0.0.0/0"
cidr_ipv6 = "::/0"
description = "Allow all outbound traffic (IPv6)"
#from_port # Required unless ip_protocol is set to -1 or icmpv6
ip_protocol = "-1"
security_group_id = aws_security_group.sg_elb_internal.id
#to_port # Required unless ip_protocol is set to -1 or icmpv6
}
#SG ELB EXTERNAL (already protected by WAF)
resource "aws_security_group" "sg_elb_external" {
lifecycle {
create_before_destroy = true
}
#description = #(Optional, Forces new resource) Defaults to Managed by Terraform
name_prefix = "${local.env}-${local.ci}-sg-elb-external-"
revoke_rules_on_delete = true
tags = {
Name = "${local.env}-${local.ci}-sg-elb-external"
}
vpc_id = var.vpc_id
}
# Inbound from CloudFront [ELB external]
data "aws_ec2_managed_prefix_list" "cloudfront_origin_facing" {
name = "com.amazonaws.global.cloudfront.origin-facing"
}
resource "aws_vpc_security_group_ingress_rule" "sg_elb_external_ingress_cloudfront" {
#cidr_ipv4 = "27.0.0.0/8" #(Optional) The source IPv4 CIDR range
#cidr_ipv6 #(Optional) The source IPv6 CIDR range
description = "CloudFront prefix list"
from_port = 443 # Required unless ip_protocol is set to -1 or icmpv6
ip_protocol = "tcp" # Values: "tcp", "-1", etc.
prefix_list_id = data.aws_ec2_managed_prefix_list.cloudfront_origin_facing.id
#referenced_security_group_id = #(Optional) The source SG referenced in the rule
security_group_id = aws_security_group.sg_elb_external.id
to_port = 443 # Required unless ip_protocol is set to -1 or icmpv6
}
# Inbound all HTTPS [ELB external]
resource "aws_vpc_security_group_ingress_rule" "sg_elb_external_ingress" {
cidr_ipv4 = "0.0.0.0/0" #(Optional) The source IPv4 CIDR range
#cidr_ipv6 #(Optional) The source IPv6 CIDR range
description = "Allows all TCP inbound traffic (already protected by WAF)"
from_port = 443 # Required unless ip_protocol is set to -1 or icmpv6
ip_protocol = "tcp" # Values: "tcp", "-1", etc.
#referenced_security_group_id = #(Optional) The source security group that is referenced in the rule
security_group_id = aws_security_group.sg_elb_external.id
to_port = 443 # Required unless ip_protocol is set to -1 or icmpv6
}
# Allows all outbound traffic (IPv4) [ELB]
resource "aws_vpc_security_group_egress_rule" "sg_elb_external_egress_ipv4" {
cidr_ipv4 = "0.0.0.0/0"
#cidr_ipv6 = "::/0"
description = "Allow all outbound traffic (IPv4)"
#from_port # Required unless ip_protocol is set to -1 or icmpv6
ip_protocol = "-1"
security_group_id = aws_security_group.sg_elb_external.id
#to_port # Required unless ip_protocol is set to -1 or icmpv6
}
# Allows all outbound traffic (IPv6) [ELB]
resource "aws_vpc_security_group_egress_rule" "ssg_elb_external_egress_ipv6" {
#cidr_ipv4 = "0.0.0.0/0"
cidr_ipv6 = "::/0"
description = "Allow all outbound traffic (IPv6)"
#from_port # Required unless ip_protocol is set to -1 or icmpv6
ip_protocol = "-1"
security_group_id = aws_security_group.sg_elb_external.id
#to_port # Required unless ip_protocol is set to -1 or icmpv6
}
################################################################################
# LB TG
################################################################################
resource "aws_lb_target_group" "tg_external" {
lifecycle {
create_before_destroy = true
}
deregistration_delay = 64 #(Optional) Default value is 300 seconds
health_check {
interval = 20 #tariff took 105.596s
path = "/back/r/p/health-lb"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
healthy_threshold = 2
unhealthy_threshold = 6
matcher = "200-299"
}
#name_prefix = var.lb_target_name_prefix #(Optional, Forces new resource) Conflicts with name. Max 6 characters
name = "${local.ci}-${local.env}-tg-external"
port = 8080
protocol_version = "HTTP1" #(Optional, Forces new resource) Only applicable when protocol is HTTP or HTTPS. Values: GRPC, HTTP1, HTTP2. Defaults to HTTP1
protocol = "HTTP"
target_type = "ip"
vpc_id = var.vpc_id
}
resource "aws_lb_target_group" "tg_internal" {
lifecycle {
create_before_destroy = true
}
deregistration_delay = 32 #(Optional) Default value is 300 secondse
health_check {
interval = 30
path = "/back/r/p/health-lb"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
healthy_threshold = 2
unhealthy_threshold = 2
matcher = "200-299"
}
#name_prefix = var.lb_target_name_prefix #(Optional, Forces new resource). Conflicts with name. Max 6 characters
name = "${local.ci}-${local.env}-tg-internal"
port = 8080
protocol_version = "HTTP1" #(Optional, Forces new resource) Only applicable when protocol is HTTP or HTTPS. Values: GRPC, HTTP1, HTTP2. Defaults to HTTP1
protocol = "HTTP"
target_type = "ip"
vpc_id = var.vpc_id
}
################################################################################
# ALB INTERNAL
################################################################################
resource "aws_lb" "lb_internal" {
depends_on = [aws_lb_target_group.tg_internal]
#access_logs = #(Optional) Access Logs block
#connection_logs = #(Optional) Connection Logs block
#client_keep_alive = #(Optional) Client keep alive value in seconds. The default is 3600 seconds
#customer_owned_ipv4_pool = #(Optional) ID of the customer owned ipv4 pool
#desync_mitigation_mode = #(Optional) HTTP desync. Values: monitor, defensive (default), strictest
#dns_record_client_routing_policy = #Only valid for network type load balancers
drop_invalid_header_fields = true #
enable_cross_zone_load_balancing = true #Require that message header names contain only alphanumeric characters and hyphens. ALBs only
#enable_cross_zone_load_balancing = #For application load balancer this feature is always enabled (true)
enable_deletion_protection = false #(Optional) If true, deletion of the load balancer will be disabled via the AWS API
#enable_http2 = #i(Optional) Whether HTTP/2 is enabled in application load balancers. Defaults to true
#enable_tls_version_and_cipher_suite_headers =
#enable_xff_client_port =
#enable_waf_fail_open = #(Optional) Whether to allow a WAF-enabled load balancer to route requests to targets if it is unable to forward the request to AWS WAF. Defaults to false
#enable_zonal_shift
#enforce_security_group_inbound_rules_on_private_link_traffic = #Only valid for Load Balancers of type network
#idle_timeout - (Optional) Time in seconds that the connection is allowed to be idle. Only valid for ALBs. Default: 60
internal = true
#ip_address_type - (Optional)
load_balancer_type = "application"
name = var.lb_internal_name
#name_prefix = #(Optional) Creates a unique name beginning with the specified prefix. Conflicts with name
security_groups = [aws_security_group.sg_elb_internal.id]
#preserve_host_header = # (Optional) Whether the ALB should preserve the Host header in the HTTP request and send it to the target without any change. Defaults to false
#subnet_mapping =
subnets = var.lb_subnet_internal_ids
tags = {
Name = "${local.env}-${local.ci}-lb-internal"
}
xff_header_processing_mode = "preserve" #1st value is the originating IP address (for backend logging purposes)
}
resource "aws_lb_listener" "internal_main" {
depends_on = [aws_lb.lb_internal]
load_balancer_arn = aws_lb.lb_internal.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = var.lb_internal_certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.tg_internal.arn
}
}
################################################################################
# ALB EXTERNAL
################################################################################
resource "aws_lb" "lb_external" {
depends_on = [aws_lb_target_group.tg_external]
#access_logs = #(Optional) Access Logs block
#connection_logs = #(Optional) Connection Logs block
#client_keep_alive = #(Optional) Client keep alive value in seconds. The default is 3600 seconds
#customer_owned_ipv4_pool = #(Optional) ID of the customer owned ipv4 pool
#desync_mitigation_mode = #(Optional) HTTP desync. Values: monitor, defensive (default), strictest
#dns_record_client_routing_policy = #Only valid for network type load balancers
drop_invalid_header_fields = true #
enable_cross_zone_load_balancing = true #Require that message header names contain only alphanumeric characters and hyphens. ALBs only
#enable_cross_zone_load_balancing = #For application load balancer this feature is always enabled (true)
enable_deletion_protection = false #(Optional) If true, deletion of the load balancer will be disabled via the AWS API
#enable_http2 = #i(Optional) Whether HTTP/2 is enabled in application load balancers. Defaults to true
#enable_tls_version_and_cipher_suite_headers =
#enable_xff_client_port =
#enable_waf_fail_open = #(Optional) Whether to allow a WAF-enabled load balancer to route requests to targets if it is unable to forward the request to AWS WAF. Defaults to false
#enable_zonal_shift
#enforce_security_group_inbound_rules_on_private_link_traffic = #Only valid for Load Balancers of type network
#idle_timeout - (Optional) Time in seconds that the connection is allowed to be idle. Only valid for ALBs. Default: 60
internal = false
#ip_address_type - (Optional)
load_balancer_type = "application"
name = var.lb_external_name
#name_prefix = #(Optional) Creates a unique name beginning with the specified prefix. Conflicts with name
security_groups = [aws_security_group.sg_elb_external.id]
#preserve_host_header = # (Optional) Whether the ALB should preserve the Host header in the HTTP request and send it to the target without any change. Defaults to false
#subnet_mapping =
subnets = var.lb_subnet_external_ids
tags = {
Name = "${local.env}-${local.ci}-lb-external"
}
xff_header_processing_mode = "preserve" #1st value is the originating IP address (for backend logging purposes)
}
resource "aws_lb_listener" "external_main" {
depends_on = [aws_lb.lb_external]
load_balancer_arn = aws_lb.lb_external.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = var.lb_external_certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.tg_external.arn
}
}
modules/elb-albs/outputs.tf
### LB EXTERNAL
output "lb_target_group_external_arn" {
value = aws_lb_target_group.tg_external.arn
}
### LB INTERNAL
output "lb_target_group_internal_arn" {
value = aws_lb_target_group.tg_internal.arn
}