How to: Terraform Dynamic Blocks
Further automating your automation.
**Please skip to the “Configuration” section if you’re looking for a quick answer**
Another blog about Terraform? Sorry in advance. At work, I’ve been working on some pretty complex Terraform and I’m learning new things about the language as I go, so why not put some of the learning on display? This post is about creating dynamic blocks in Terraform to further automate your automation.
The Problem
Infrastructure as code (IaC) is a Godsend, but it can turn into just as much of a pain as perusing through the UI of whatever cloud when you have to create multiple of the same resources over and over again with slight differences like naming or region. For that, Terraform has dynamic blocks. These blocks allow you to iterate over a key-value store of variables to “dynamically” create multiple resources without having to define them all in your configuration file. Saving you time, lines of code, and analysis paralysis.
Kind of Problem
The second problem is documentation/demonstration. Try and find an example of dynamic blocks on YouTube, Google, StackOverflow, etc. and I bet it will show you something with Network Security Groups rules. So what about all the other people who don’t need to create security group rules dynamically? Hopefully, I can help with this issue. Let’s make this quick…
Configuration
This is going to be pretty high-level to spare making this post multiple thousands of words, but here goes nothing. This example is also going to be in Azure.
Let’s say we want to create multiple resource groups, inside through resource groups we have storage accounts. These storage accounts have multiple attributes like blocking public access, large file shares being enabled, and more (you’ll see). Now imagine you have to create 40 resource groups and storage accounts with these attributes. This would take a lifetime in the UI. Though doing this via Terraform would be faster, if these resources have to be defined in the configuration individually it would take half a lifetime. So, here is an example block before making it dynamic:
resource "azurerm_resource_group" "resource_group_name" {
name = “resource-group-test”
location = "eastus"
tags = {
"Extra Tag" = "Tag Value"
}
}
resource "azurerm_storage_account" "storage_account" {
name = "test-storage”
resource_group_name = azurerm_resource_group.resource_group_name.name
location = azurerm_resource_group.resource_group_name.location
account_tier = "Standard"
account_replication_type = "LRS"
public_network_access_enabled = true
large_file_share_enabled = true
share_properties {
retention_policy {
days = "14"
}
}
network_rules {
default_action = "Deny"
bypass = ["AzureServices"]
ip_rules = ["X.X.X.X"]
}
tags = {
"Extra Tag" = "9876"
}
}
This works, but as I said, imagine doing this another 40 times just to account for different names of the resource groups and storage accounts.
So we’ll start by creating a variables.tf and placing the variables here to pull from.
variable "test_variables" {
type = map(object({
location = string
ExtraTag = string
}))
default = {
str = {
location = "eastus"
ExtraTag = "1234"
}
rsg = {
location = "westus"
ExtraTag = "5678"
}
pre = {
location = "westeurope"
ExtraTag = "9876"
}
}
}This map is going to be used to automate the naming, location, and tags of the resources. Now it’s time to build the dynamic block. Terraform uses a for_each = var.test_variables to iterate over the map above. Keys are accessed using each.key, and values are accessed using each.value.NAME so for this example it would be each.value.location to access “eastus”.
esource "azurerm_resource_group" "resource_group_name" {
for_each = var.test_variables
name = “${each.key}-test”
location = each.value.location
tags = {
"Extra Tag" = each.value.ExtraTag
}
}
resource "azurerm_storage_account" "storage_account" {
for_each = var.test_variables
name = "${each.key}-test-storage”
resource_group_name = azurerm_resource_group.resource_group_name[each.key].name
location = each.value.location
account_tier = "Standard"
account_replication_type = "LRS"
public_network_access_enabled = true
large_file_share_enabled = true
share_properties {
retention_policy {
days = "14"
}
}
tags = {
"Extra Tag" = each.value.ExtraTag
}
}With this configuration, three resource groups will be created with a storage account inside of each. All with a similar naming convention and the proper attachment after being attached via azurerm_resource_group.resource_group_name[each.key].name.
You could also access other attributes of the dynamic resources like “id” with similar naming:
azurerm_resource_group.resource_group_name[each.key].id
Go ahead and make your necessary changes, then run terraform plan.
Keep in mind that changes made to the dynamic block will make changes across all resources that are provisioned via that block.
Career/Life Lesson
Sorry for another Terraform blog post. Since we’re on the topic, I quickly want to discuss free time and how it is spent. Before being in my current role, I would write Terraform all day. This was in hopes/preparation for being in a role like the one I’m in today. Now that I’m in this role, I have the opportunity to master this skill in my day job, and onboard new skills to make me better in my career and prep me for the next one in my free time. Working on the same skill at work and home would be redundant, and I don’t necessarily see the benefit (but I’m open to alternative opinions). I’ve always thought like this, but it was good to hear it from someone else during my limited YouTube time yesterday: The Tech Job You Want.
What’s Next?
Projects, projects, and more projects. Lots of ideas in store and too many smart people around me, so stay tuned!



