Simplifying Dynamic blocks in Terraform

Simplifying Dynamic blocks in Terraform

When I started out with Terraform, dynamic blocks were a tough nut for me to crack, atleast for a while. For some reason, reading the official documentation repeatedly didn't help my case. In this article, I have tried my best to explain the dynamic blocks in Terraform in simple language with examples that will make it easier to understand for anyone starting out with Terraform.

Traditional Terraform code often involves specifying resource blocks with fixed, static configurations. For example, creating multiple security group rules or IAM policies for different instances can lead to repetitive and lengthy code. Dynamic Blocks help in addressing this challenge as they offer a more clean approach to managing such scenarios.

Dynamic Blocks enable Terraform to create multiple instances of a particular configuration block within a single resource or data block which is dynamically generated based on variables or a collection of elements. This means that instead of repeating the same configuration multiple times, we can loop through a list or map to generate the required blocks automatically.

Syntax :

The syntax for Dynamic Blocks consists of the keyword dynamic, followed by one or more nested for_each or for expressions, and inside it, we define the block type along with its arguments.

Assuming you have already set up your AWS provider configuration, let's start by defining the variables and the listener configuration map in a Terraform file called variables.tf :

variable "elb_name" {
  description = "Name of the Elastic Load Balancer"
  type        = string
}

variable "listener_rules" {
  description = "Map of listener rules for the Elastic Load Balancer"
  type        = map(object({
    protocol           = string
    load_balancer_port = number
    instance_protocol  = string
    instance_port      = number
  }))
}

In this example, listener_rules is a map that can hold multiple listener configurations. Each configuration contains the following attributes:

  • protocol: The protocol for the incoming traffic (e.g., HTTP, HTTPS, TCP).

  • load_balancer_port: The port on the Elastic Load Balancer that listens for incoming traffic.

  • instance_protocol: The protocol to use when forwarding traffic from the load balancer to the backend instances (e.g., HTTP, HTTPS, TCP).

  • instance_port: The port on the backend instances that the load balancer forwards traffic to.

Now, let's create the main Terraform configuration file (e.g., main.tf) to provision the ELB using Dynamic Blocks:

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

resource "aws_elb" "example" {
  name      = var.elb_name
  subnets   = ["subnet-12345678", "subnet-87654321"]  # Replace with your subnet IDs
  listener {
    instance_port     = 80
    instance_protocol = "HTTP"
    lb_port           = 80
    lb_protocol       = "HTTP"
  }

  dynamic "listener" {
    for_each = var.listener_rules

    content {
      instance_port     = listener.value.instance_port
      instance_protocol = listener.value.instance_protocol
      lb_port           = listener.value.load_balancer_port
      lb_protocol       = listener.value.protocol
    }
  }
}

In this configuration, we create an Elastic Load Balancer resource (aws_elb) with a default listener configured on port 80 for HTTP traffic. Other than that, we use the Dynamic Block to create additional listeners based on the configurations provided in the listener_rules map.

For example, you can define the listener_rules in a separate .tfvars file (e.g., variables.tfvars):

listener_rules = {
  "https_listener" = {
    protocol           = "HTTPS"
    load_balancer_port = 443
    instance_protocol  = "HTTP"
    instance_port      = 80
  }
  "custom_tcp_listener" = {
    protocol           = "TCP"
    load_balancer_port = 8080
    instance_protocol  = "TCP"
    instance_port      = 8080
  }
}

With this configuration, the Terraform code will dynamically create two additional listeners in the Elastic Load Balancer, as defined in the listener_rules map. If you need to add more listeners, simply include them in the map with their respective configurations.

By leveraging Dynamic Blocks, you can easily manage and scale your infrastructure configurations with minimal code repetition, making your Terraform codebase more clean, maintainable, and readable.


If you liked what you read, do consider sharing the article with a friend and connect with me on Twitter - @afraz_momin. Also, subscribe to my newsletter and stay up-to-date with my latest blog posts.