Thursday, April 28, 2022

ALB rule based routing with terraform

From 2017 Amazon started supporting Host-based routing on Application Load Balancer. Content-based routing was supported before, so Application Load Balancer now supports both Host- and Path-based rules. You can combine both routing types to create complex rules for your services. If you are looking how to combine both routing types, please look at this stack overflow answer: https://stackoverflow.com/a/46304567.

In this example we are going to show you how you can use a single Application Load Balancer(ALB) for separate ECS’s. Imagine, you have 30 ECS’s running on Fargate. You want 10 of those to be exposed. If you would use ALB for every single ECS, this would be very inefficient and expensive. To combat this, AWS supports routing traffic on ALB to Target Groups (ECS can be one example of a target group) based on rules. In this way, you can have one ALB which will route traffic to the Target Group (in our example this will be ECS). 

Below is one example of how you can do that with comments about specific details.

# First create a target group for each of your services, this is target group to
# Docker ECS service running on AWS Fargate
resource "aws_lb_target_group" "this" {
name = "${local.this_name}-alb-tg"
port = var.app_port
protocol = "HTTP"
vpc_id = var.config.vpc_id
target_type = "ip"
health_check {
healthy_threshold = "3"
interval = "120"
protocol = "HTTP"
matcher = "200-299"
timeout = "119"
path = var.health_check_path
unhealthy_threshold = "2"
}
tags = {
Team = var.config.team
Environment = var.config.env
Application = var.app_name
}
}
# Then, create ALB. This is the internal ALB.
# Hint: *Always use tags. It's much easier to do cost management and resource tracking.
resource "aws_lb" "this" {
name = "${local.wd_app_name}-alb"
internal = true
subnets = var.config.lb_subnets_ids
load_balancer_type = "application"
security_groups = [aws_security_group.lb.id]
idle_timeout = 300
tags = {
Team = var.config.team
Environment = var.config.env
Application = local.wd_app_name
}
}
# This is how you route traffic to a specific target group based on the host header.
# For each of your services, you need to create specific rules for each target group.
# In this example, we have only one target group and one router.
resource "aws_lb_listener_rule" "this" {
listener_arn = "${aws_lb_listener.this.arn}"
action {
type = "forward"
target_group_arn = "${aws_lb_target_group.this.arn}"
}
condition {
host_header {
values = var.aws_lb_listener_rules
}
}
}
# This is the security group for ALB.
# Be aware, this is a very permissive security group for internal ALB.
# Tailor it to your needs.
resource "aws_security_group" "lb" {
name = "${local.this_name}-lb-sg"
description = "Access to the Application Load Balancer (ALB)"
vpc_id = var.config.vpc_id
ingress {
protocol = "tcp"
from_port = 443
to_port = 443
cidr_blocks = ["0.0.0.0/0"] # All IP ranges
}
egress { # All traffic is allowed
protocol = "-1" # -1 is equivalent to "All"
from_port = 0
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${local.this_name}-lb-sg"
Team = var.config.team
Environment = var.config.env
Application = var.app_name
}
}