Part 4 - Create the application load balancer.

By Ben Outram / 2018-06-15

All of the following configuration blocks should be added to the project.tf file that we created previously.

Create an application load balancer security group:

resource "aws_security_group" "alb" {
  name        = "terraform_alb_security_group"
  description = "Terraform load balancer security group"
  vpc_id      = "${aws_vpc.vpc.id}"

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = "${var.allowed_cidr_blocks}"
  }

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = "${var.allowed_cidr_blocks}"
  }

  # Allow all outbound traffic.
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags {
    Name = "terraform-example-alb-security-group"
  }
}

Create a new application load balancer:

resource "aws_alb" "alb" {
  name            = "terraform-example-alb"
  security_groups = ["${aws_security_group.alb.id}"]
  subnets         = ["${aws_subnet.main.*.id}"]
  tags {
    Name = "terraform-example-alb"
  }
}

Create a new target group for the application load balancer. Traffic will be routed to target web server instances on HTTP port 80. We will also define a health check for targets which will expect a "200 OK" response for the login page of our web application:

resource "aws_alb_target_group" "group" {
  name     = "terraform-example-alb-target"
  port     = 80
  protocol = "HTTP"
  vpc_id   = "${aws_vpc.vpc.id}"
  stickiness {
    type = "lb_cookie"
  }
  # Alter the destination of the health check to be the login page.
  health_check {
    path = "/login"
    port = 80
  }
}

Create two new application load balancer listeners. The first listener is configured to accept HTTP client connections.

resource "aws_alb_listener" "listener_http" {
  load_balancer_arn = "${aws_alb.alb.arn}"
  port              = "80"
  protocol          = "HTTP"

  default_action {
    target_group_arn = "${aws_alb_target_group.group.arn}"
    type             = "forward"
  }
}

The second listener is configured to accept HTTPS client connections and is secured with our SSL certificate from Certificate Manager:

resource "aws_alb_listener" "listener_https" {
  load_balancer_arn = "${aws_alb.alb.arn}"
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = "${var.certificate_arn}"
  default_action {
    target_group_arn = "${aws_alb_target_group.group.arn}"
    type             = "forward"
  }
}

Define a record set in Route 53 for the load balancer. This will point a terraform subdomain of our domain name at the load balancer, e.g. terraform.example.com:

resource "aws_route53_record" "terraform" {
  zone_id = "${data.aws_route53_zone.zone.zone_id}"
  name    = "terraform.${var.route53_hosted_zone_name}"
  type    = "A"
  alias {
    name                   = "${aws_alb.alb.dns_name}"
    zone_id                = "${aws_alb.alb.zone_id}"
    evaluate_target_health = true
  }
}

The record set configuration block depends on a data source for our Route 53 hosted zone to provide the zone ID. Add this data source to file datasource.tf:

data "aws_route53_zone" "zone" {
  name = "${var.route53_hosted_zone_name}"
}

Finally let's define a new variable that we introduced during this section for the list of CIDR blocks that are allowed by the load balancer security group.

Add the following to variables.tf:

variable "allowed_cidr_blocks" {
  type = "list"
}

Assign the variable in our user.tfvars file with a comma separated list of CIDR blocks that we want to allow access. Rather than allowing all IP adresses access, we can authorise combinations of specific IP addresses and IP address ranges.

If you have a single IP address 99.99.99.99 that you want to allow access then define a single CIDR block:

allowed_cidr_blocks = ["99.99.99.99/32"]

To allow access to a range of IP addresses 99.99.99.1 through to 99.99.99.255 you would define this single CIDR block instead:

allowed_cidr_blocks = ["99.99.99.1/24"]

We can now try another plan:

$ terraform plan -var-file="user.tfvars"

Terraform will perform the following actions:

  + aws_alb.alb
  + aws_alb_listener.listener_http
  + aws_alb_listener.listener_https
  + aws_alb_target_group.group
  + aws_route53_record.terraform
  + aws_security_group.alb

Plan: 6 to add, 0 to change, 0 to destroy.

Now review the plan. If everything looks good, apply our changes!

$ terraform apply -var-file="user.tfvars"

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.

You can find all the source code for this part of the lab here in GitHub.

More posts in this series.