A Dynamic block is similar to for expression but creates nested blocks instead of a complex typed value. It iterates over a given complex value and generates a nested block for each element of that complex value. Unlike the count block, which will iterate over the resource, the dynamic will reside inside the resource block.
Dynamic blocks are supported inside the following blocks,
- Resource
- Data
- Provider
- Provisioner
Dynamic blocks can be used for resources like Setting, Security Group, etc.
Let us consider the example of creating a security group with multiple ingress rules for ports (80, 443, 3306, and 22). In an ideal scenario, we will end up copy-pasting the ingress rule for each port in the security group resource block.
Security Group (Without Dynamic Block)
// Security Group without Dynamic Block
resource "aws_security_group" "lamp_securitygroup_basic" {
name = "LAMP Security Group Basic"
description = "LAMP Server Security Group Basic ${terraform.workspace}" // call the workspace
vpc_id = data.aws_vpc.get_vpc_id.id
tags = local.common_tags
// in-bound rules
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
// outbound rules
egress {
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}The above code will work perfectly fine, but as your security group rules go on increasing, you will need to copy-paste the ingress block for each rule, which will make the code hard to maintain and update.
To overcome this issue, Terraform provides us with a dynamic block. We can write the same code using dynamic block,
Security Group (Dynamic Block)
// Data block for VPC ID
data "aws_vpc" "get_vpc_id" {
default = true
}// variable declaration
variable "port" {
description = "Enter the ports to be configured in SG Ingress rule"
default = [80, 22, 443, 3306]
}// Create Security Group uisng Dynamic Block
resource "aws_security_group" "lamp_sg" {
name = "LAMP Security Group"
description = "LAMP Server Security Group ${terraform.workspace}" // call the workspace
vpc_id = data.aws_vpc.get_vpc_id.id
tags = local.common_tags
dynamic "ingress" {
for_each = var.port
content {
description = "Security rule for inbound ${ingress.value}"
from_port = ingress.value // The block should use block name to fetch the value and key
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}
// outbound rules
egress {
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}In our example, we are producing a nested block of ingress rules,
- The label of our dynamic block is “ingress”, you can change the label, as you per the requirement, like if you want to generate “setting” nested blocks we can name the dynamic block as “setting”.
- For_each – Argument will provide the complex argument to iterate over.
- Content Block – defines the body of each generated block. In our example it will be the ingress block, iterating over multiple ports.
In multi-level nested block, we can have multi-level nested dynamic blocks, ie the nested dynamic bock within the dynamic block.