Creating an Application Load Balancer (ALB) Listener with Multiple Host Header Conditions Using Terraform


Application Load Balancers (ALBs) play a crucial role in distributing traffic across multiple backend services. They provide the flexibility to route requests based on a variety of conditions, such as path-based or host-based routing. In this article, we’ll walk through how to create an ALB listener with multiple host_header conditions using Terraform.

Prerequisites

Before you begin, ensure that you have the following:

  • AWS Account: You’ll need an AWS account with the appropriate permissions to create and manage ALB, EC2, and other related resources.
  • Terraform Installed: Make sure you have Terraform installed on your local machine. You can download it from the official website.
  • Basic Knowledge of Terraform: Familiarity with Terraform basics, such as providers, resources, and variables, is assumed.

Step 1: Set Up Your Terraform Configuration

Start by creating a new directory for your Terraform configuration files. Inside this directory, create a file named main.tf. This file will contain the Terraform code to create the ALB, listener, and associated conditions.

provider "aws" {
  region = "us-west-2" # Replace with your preferred region
}

resource "aws_vpc" "main_vpc" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "main_subnet" {
  vpc_id            = aws_vpc.main_vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-west-2a" # Replace with your preferred AZ
}

resource "aws_security_group" "alb_sg" {
  name   = "alb_sg"
  vpc_id = aws_vpc.main_vpc.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_lb" "my_alb" {
  name               = "my-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb_sg.id]
  subnets            = [aws_subnet.main_subnet.id]

  enable_deletion_protection = false
}

resource "aws_lb_target_group" "target_group_1" {
  name     = "target-group-1"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main_vpc.id
}

resource "aws_lb_target_group" "target_group_2" {
  name     = "target-group-2"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main_vpc.id
}

resource "aws_lb_listener" "alb_listener" {
  load_balancer_arn = aws_lb.my_alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "fixed-response"
    fixed_response {
      content_type = "text/plain"
      message_body = "404: No matching host header"
      status_code  = "404"
    }
  }
}

resource "aws_lb_listener_rule" "host_header_rule_1" {
  listener_arn = aws_lb_listener.alb_listener.arn
  priority     = 1

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.target_group_1.arn
  }

  condition {
    host_header {
      values = ["example1.com"]
    }
  }
}

resource "aws_lb_listener_rule" "host_header_rule_2" {
  listener_arn = aws_lb_listener.alb_listener.arn
  priority     = 2

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.target_group_2.arn
  }

  condition {
    host_header {
      values = ["example2.com"]
    }
  }
}

Step 2: Define the ALB and Listener

In the main.tf file, we start by defining the ALB and its associated listener. The listener listens for incoming HTTP requests on port 80 and directs the traffic based on the conditions we set.

resource "aws_lb_listener" "alb_listener" {
  load_balancer_arn = aws_lb.my_alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "fixed-response"
    fixed_response {
      content_type = "text/plain"
      message_body = "404: No matching host header"
      status_code  = "404"
    }
  }
}

Step 3: Add Host Header Conditions

Next, we create listener rules that define the host header conditions. These rules will forward traffic to specific target groups based on the Host header in the HTTP request.

resource "aws_lb_listener_rule" "host_header_rule_1" {
  listener_arn = aws_lb_listener.alb_listener.arn
  priority     = 1

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.target_group_1.arn
  }

  condition {
    host_header {
      values = ["example1.com"]
    }
  }
}

resource "aws_lb_listener_rule" "host_header_rule_2" {
  listener_arn = aws_lb_listener.alb_listener.arn
  priority     = 2

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.target_group_2.arn
  }

  condition {
    host_header {
      values = ["example2.com"]
    }
  }
}

In this example, requests with a Host header of example1.com are routed to target_group_1, while requests with a Host header of example2.com are routed to target_group_2.

Step 4: Deploy the Infrastructure

Once you have defined your Terraform configuration, you can deploy the infrastructure by running the following commands:

  1. Initialize Terraform: This command initializes the working directory containing the Terraform configuration files.
   terraform init
  1. Review the Execution Plan: This command creates an execution plan, which lets you see what Terraform will do when you run terraform apply.
   terraform plan
  1. Apply the Configuration: This command applies the changes required to reach the desired state of the configuration.
   terraform apply

After running terraform apply, Terraform will create the ALB, listener, and listener rules with the specified host header conditions.

Adding SSL to your Application Load Balancer (ALB) in AWS using Terraform involves creating an HTTPS listener, configuring an SSL certificate, and setting up the necessary security group rules. This guide will walk you through the process of adding SSL to the ALB configuration that we created earlier.

Step 1: Obtain an SSL Certificate

Before you can set up SSL on your ALB, you need to have an SSL certificate. You can obtain an SSL certificate using AWS Certificate Manager (ACM). This guide assumes you already have a certificate in ACM, but if not, you can request one via the AWS Management Console or using Terraform.

Here’s an example of how to request a certificate in Terraform:

resource "aws_acm_certificate" "cert" {
  domain_name       = "example.com"
  validation_method = "DNS"

  subject_alternative_names = [
    "www.example.com",
  ]

  tags = {
    Name = "example-cert"
  }
}

After requesting the certificate, you need to validate it. Once validated, it will be ready for use.

Step 2: Modify the ALB Security Group

To allow HTTPS traffic, you need to update the security group associated with your ALB to allow incoming traffic on port 443.

resource "aws_security_group_rule" "allow_https" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.alb_sg.id
}

Step 3: Add the HTTPS Listener

Now, you can add an HTTPS listener to your ALB. This listener will handle incoming HTTPS requests on port 443 and will forward them to the appropriate target groups based on the same conditions we set up earlier.

resource "aws_lb_listener" "https_listener" {
  load_balancer_arn = aws_lb.my_alb.arn
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = aws_acm_certificate.cert.arn

  default_action {
    type = "fixed-response"
    fixed_response {
      content_type = "text/plain"
      message_body = "404: No matching host header"
      status_code  = "404"
    }
  }
}

Step 4: Add Host Header Rules for HTTPS

Just as we did with the HTTP listener, we need to create rules for the HTTPS listener to route traffic based on the Host header.

resource "aws_lb_listener_rule" "https_host_header_rule_1" {
  listener_arn = aws_lb_listener.https_listener.arn
  priority     = 1

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.target_group_1.arn
  }

  condition {
    host_header {
      values = ["example1.com"]
    }
  }
}

resource "aws_lb_listener_rule" "https_host_header_rule_2" {
  listener_arn = aws_lb_listener.https_listener.arn
  priority     = 2

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.target_group_2.arn
  }

  condition {
    host_header {
      values = ["example2.com"]
    }
  }
}

Step 5: Update Terraform and Apply Changes

After adding the HTTPS listener and security group rules, you need to update your Terraform configuration and apply the changes.

  1. Initialize Terraform: If you haven’t done so already.
   terraform init
  1. Review the Execution Plan: This command creates an execution plan to review the changes.
   terraform plan
  1. Apply the Configuration: Apply the configuration to create the HTTPS listener and associated resources.
   terraform apply

Conclusion

We walked through creating an ALB listener with multiple host header conditions using Terraform. This setup allows you to route traffic to different target groups based on the Host header of incoming requests, providing a flexible way to manage multiple applications or services behind a single ALB.

By following these steps, you have successfully added SSL to your AWS ALB using Terraform. The HTTPS listener is now configured to handle secure traffic on port 443, routing it to the appropriate target groups based on the Host header.

This setup not only ensures that your application traffic is encrypted but also maintains the flexibility of routing based on different host headers. This is crucial for securing web applications and complying with modern web security standards.