Terraform, a popular tool for infrastructure as code (IaaC), allows you to define and manage your infrastructure in a consistent, repeatable way. One of Terraform’s powerful features is the ability to use dynamic blocks, which enable you to write more modular, DRY (Don’t Repeat Yourself) code. In this blog, we’ll dive into what dynamic blocks are, why they’re useful, and how to use them effectively with a practical example of creating Azure Network Security Group (NSG) rules.
What Are Dynamic Blocks in Terraform?
In Terraform, a block is a fundamental unit that encapsulates configuration information for resources, data sources, or modules. When dealing with multiple similar configurations, such as creating several rules for a Network Security Group (NSG) in Azure, repeating the same block with slight variations can make your Terraform files cumbersome and difficult to maintain.
This is where dynamic blocks come in. A dynamic block allows you to generate multiple instances of a particular block programmatically, based on a list or a map of inputs. This feature is particularly useful when you need to create multiple similar configurations with varying parameters.
Why Use Dynamic Blocks?
Dynamic blocks help you:
- Reduce Code Duplication: Instead of writing out each block manually, you can create a dynamic block that iterates over a set of values, reducing repetitive code.
- Simplify Maintenance: Updating configurations becomes easier since changes only need to be made in one place rather than multiple.
- Increase Flexibility: Dynamic blocks allow you to handle complex scenarios where the number of resources or configurations is not fixed and may vary based on input.
Using Dynamic Blocks: Azure NSG Rule Creation Example
Let’s walk through a practical example of using dynamic blocks in Terraform to create multiple rules for an Azure Network Security Group (NSG).
Step 1: Define the Variables
First, you need to define the variables that will store the rules you want to apply to the NSG. Create a variables.tf file:
# variables.tf
variable "nsg_name" {
description = "Name of the Network Security Group"
type = string
}
variable "location" {
description = "Azure region where the NSG will be created"
type = string
default = "East US"
}
variable "resource_group_name" {
description = "Name of the resource group"
type = string
}
variable "nsg_rules" {
description = "List of security rules to apply to the NSG"
type = list(object({
name = string
priority = number
direction = string
access = string
protocol = string
source_port_range = string
destination_port_range = string
source_address_prefix = string
destination_address_prefix = string
}))
}
In this example, the nsg_rules variable is a list of objects, each representing a rule with several properties such as name, priority, direction, and so on.
Step 2: Write the Terraform Configuration
Next, create your main Terraform configuration file, main.tf, to define the NSG and use a dynamic block to create the rules.
# main.tf
provider "azurerm" {
features = {}
}
resource "azurerm_network_security_group" "nsg" {
name = var.nsg_name
location = var.location
resource_group_name = var.resource_group_name
}
resource "azurerm_network_security_rule" "nsg_rule" {
count = length(var.nsg_rules)
name = var.nsg_rules[count.index].name
priority = var.nsg_rules[count.index].priority
direction = var.nsg_rules[count.index].direction
access = var.nsg_rules[count.index].access
protocol = var.nsg_rules[count.index].protocol
source_port_range = var.nsg_rules[count.index].source_port_range
destination_port_range = var.nsg_rules[count.index].destination_port_range
source_address_prefix = var.nsg_rules[count.index].source_address_prefix
destination_address_prefix = var.nsg_rules[count.index].destination_address_prefix
network_security_group_name = azurerm_network_security_group.nsg.name
}
In this example, the azurerm_network_security_rule resource is defined using a count meta-argument. The count is set to the length of the nsg_rules list, and each rule’s properties are accessed using count.index. This approach dynamically creates the necessary number of security rules based on the input list.
Step 3: Provide Environment-Specific Values
Now, create a terraform.tfvars file to provide specific values for the variables, including the security rules:
# terraform.tfvars
nsg_name = "my-nsg"
resource_group_name = "my-resource-group"
nsg_rules = [
{
name = "allow-ssh"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "0.0.0.0/0"
destination_address_prefix = "*"
},
{
name = "allow-http"
priority = 200
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "0.0.0.0/0"
destination_address_prefix = "*"
}
]
This file contains two rules: one to allow SSH traffic and another to allow HTTP traffic. You can add more rules or adjust these as needed.
Step 4: Deploy the Configuration
With everything set up, you can now deploy your configuration:
terraform init
terraform apply
Terraform will automatically iterate through the nsg_rules list and create a corresponding NSG rule for each entry.
Benefits of Using Dynamic Blocks
- Scalability: Easily scale the number of NSG rules without modifying the core Terraform configuration. Simply update the list in your
terraform.tfvarsfile. - Clarity: Keeps your Terraform code concise and clear, avoiding repetition and making it easier to understand at a glance.
- Flexibility: Accommodates dynamic, varying infrastructure needs. You can adjust the number and configuration of NSG rules just by modifying the input variables.
Dynamic blocks in Terraform are a powerful feature that can help you manage complex infrastructure configurations with ease. By using dynamic blocks, you can reduce redundancy in your code, simplify maintenance, and make your Terraform configurations more flexible and scalable.
In the example of Azure NSG rules, we saw how dynamic blocks enable you to handle multiple similar rules without repetitive code, making your infrastructure as code practices more efficient. Try incorporating dynamic blocks into your Terraform projects to see these benefits in action!