Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

Hashicorp Terraform dynamic block for_each loop with example

I use Terraform IAC (Infrastructure as a code) a lot to design Azure resources, While deploying Azure Resource NSG (Network Security Group), I was defining multiple roles inside NSG, Roles were mentioned inside the main.tf code script file. I wanted roles values to be moved to variables inside variable.tf file, so it can be manage better and I can reduce the code inside main.tf file for better readability. 

Related Articles:
Terraform Using one module variable in another module
Writing and Using Terraform modules
Terraform for_each loop on map example

Below is the my normal code to create NSG and multiple rules, check the security_rule mentioned inside the terraform resource azurerm_network_security_group. Multiple rules are configured directly inside the main.tf terraform code file. My task is to move multiple security_rule blocks to variable.tf file.

#main.tf - Before adding dynamic block
provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "demo" {
  name     = var.rg_name
  location = var.location
}

resource "azurerm_network_security_group" "vcloud-lab" {
  name                = var.nsg_name
  location            = azurerm_resource_group.demo.location
  resource_group_name = azurerm_resource_group.demo.name

  security_rule {
    name                       = "Rule01"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "80"
    destination_port_range     = "*"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  security_rule {
    name                       = "Rule02"
    priority                   = 110
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "443"
    destination_port_range     = "*"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  tags = {
    environment = "dev"
    owner = "vcloud-lab.com"
  }
}

#variable.tf - Before adding dynamic block
variable "rg_name" {
  type = string
  default = "RG_vCloud-lab"
}

variable "location" {
  type = string
  default = "West Us"
}

variable "nsg_name" {
  type = string
  default = "NSG_vCloud-lab"
}

This is Terraform codes on Visual Studio Code.

VS code visual studio code hashicorp terraform main.tf variable.tf azurerm provider resoruce features azurerm_network_security_group azurerm_resource_group tags security rules foreach dynamic block.png

Before working and moving security_rule to variables I tested the existing unedited code with terraform init and terraform plan. It is working fine and will adding 2 resources.

Microsoft Azure hashicorp terraform terraform plan init azurerm_network_security_group resource group automation devops iac infrastrure as a code.png

After adding Dynamic Block to main.tf:

From main.tf I moved security_rule to the sec_rules named variable in variable.tf file. The type of sec_rules is list(object({})). Inside main.tf to use multiple rules I am using dynamic block with name security_rule (as same as resource attribute), Under it I have mentioned for_each loop taking sec_rules map/set information stored and mentioned in the variable default value. This values are fetched in the loop fashion with key pair value map (dictionary).

As you can see below in the screenshots with markings.

Hashicorp terraform Microsoft Azure dynamic security rule for_each content value map object list variable tags azurerm_network_security_Group iac infrastructure as a code devops.png

#main.tf - After adding dynamic block
provider "azurerm" {
    features {}
}

resource "azurerm_resource_group" "demo" {
    name     = var.rg_name
    location = var.location
}

resource "azurerm_network_security_group" "vcloud-lab" {
    name                = var.nsg_name
    location            = azurerm_resource_group.demo.location
    resource_group_name = azurerm_resource_group.demo.name

    dynamic "security_rule" {
        for_each = var.sec_rules
        content {
            name                       = security_rule.value["name"]
            priority                   = security_rule.value["priority"]
            direction                  = security_rule.value["direction"]
            access                     = security_rule.value["access"]
            protocol                   = security_rule.value["protocol"]
            source_port_range          = security_rule.value["source_port_range"]
            destination_port_range     = security_rule.value["destination_port_range"]
            source_address_prefix      = "*"
            destination_address_prefix = "*"
        }
    }

    tags = {
        environment = "dev"
        owner = "vcloud-lab.com"
    }
}

#variable.tf - After adding dynamic block
variable "rg_name" {
  type = string
  default = "RG_vloud-lab"
}

variable "location" {
  type = string
  default = "West Us"
}

variable "nsg_name" {
  type = string
  default = "NSG_vCloud-lab"
}

variable "sec_rules" {
    description = "NSG security rules"
    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
    }))
    default = [{
        name                       = "Rule01"
        priority                   = 100
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "80"
        destination_port_range     = "*"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
    },
    {
        name                       = "Rule02"
        priority                   = 110
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "443"
        destination_port_range     = "*"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
    }]
}

Using terraform apply -auto-approve I can verify information is getting created successfully.

Microsoft Azure Powershell Terraform HashiCorp provider azurerm azurerm_resource_group network_security_group nsg subscription .png

Download terraform code files here or it is also available on github.com.

Microsoft Azure Portal NSG network security group resource group rg hashicorp terraform inbound security rules outbound security rules devops infrastructure as a code iac coding scripting.png

Below is the complete snap shot of the terrform report.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
PS D:\Projects\Terraform\Dynamic_Block> terraform init


Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/azurerm from the dependency lock file
- Using previously-installed hashicorp/azurerm v2.74.0

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 

PS D:\Projects\Terraform\Dynamic_Block> terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with   
the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_network_security_group.vcloud-lab will be created
  + resource "azurerm_network_security_group" "vcloud-lab" {
      + id                  = (known after apply)
      + location            = "westus"
      + name                = "NSG_vCloud-lab"
      + resource_group_name = "RG_vCloud-lab"
      + security_rule       = [
          + {
              + access                                     = "Allow"
              + description                                = ""
              + destination_address_prefix                 = "*"
              + destination_address_prefixes               = []
              + destination_application_security_group_ids = []
              + destination_port_range                     = "*"
              + destination_port_ranges                    = []
              + direction                                  = "Inbound"
              + name                                       = "Rule01"
              + priority                                   = 100
              + protocol                                   = "Tcp"
              + source_address_prefix                      = "*"
              + source_address_prefixes                    = []
              + source_application_security_group_ids      = []
              + source_port_range                          = "80"
              + source_port_ranges                         = []
            },
          + {
              + access                                     = "Allow"
              + description                                = ""
              + destination_address_prefix                 = "*"
              + destination_address_prefixes               = []
              + destination_application_security_group_ids = []
              + destination_port_range                     = "*"
              + destination_port_ranges                    = []
              + direction                                  = "Inbound"
              + name                                       = "Rule02"
              + priority                                   = 110
              + protocol                                   = "Tcp"
              + source_address_prefix                      = "*"
              + source_address_prefixes                    = []
              + source_application_security_group_ids      = []
              + source_port_range                          = "443"
              + source_port_ranges                         = []
            },
        ]
      + tags                = {
          + "environment" = "dev"
          + "owner"       = "vcloud-lab.com"
        }
    }

  # azurerm_resource_group.demo will be created
  + resource "azurerm_resource_group" "demo" {
      + id       = (known after apply)
      + location = "westus"
      + name     = "RG_vCloud-lab"
    }

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

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if
you run "terraform apply" now.

PS D:\Projects\Terraform\Dynamic_Block> terraform apply -auto-approve


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_network_security_group.vcloud-lab will be created
  + resource "azurerm_network_security_group" "vcloud-lab" {
      + id                  = (known after apply)
      + location            = "westus"
      + name                = "NSG_vCloud-lab"
      + resource_group_name = "RG_vCloud-lab"
      + security_rule       = [
          + {
              + access                                     = "Allow"  
              + description                                = ""       
              + destination_address_prefix                 = "*"      
              + destination_address_prefixes               = []       
              + destination_application_security_group_ids = []       
              + destination_port_range                     = "*"      
              + destination_port_ranges                    = []       
              + direction                                  = "Inbound"
              + name                                       = "Rule01" 
              + priority                                   = 100      
              + protocol                                   = "Tcp"    
              + source_address_prefix                      = "*"      
              + source_address_prefixes                    = []       
              + source_application_security_group_ids      = []       
              + source_port_range                          = "80"     
              + source_port_ranges                         = []       
            },
          + {
              + access                                     = "Allow"
              + description                                = ""
              + destination_address_prefix                 = "*"
              + destination_address_prefixes               = []
              + destination_application_security_group_ids = []
              + destination_port_range                     = "*"
              + destination_port_ranges                    = []
              + direction                                  = "Inbound"
              + name                                       = "Rule02"
              + priority                                   = 110
              + protocol                                   = "Tcp"
              + source_address_prefix                      = "*"
              + source_address_prefixes                    = []
              + source_application_security_group_ids      = []
              + source_port_range                          = "443"
              + source_port_ranges                         = []
            },
        ]
      + tags                = {
          + "environment" = "dev"
          + "owner"       = "vcloud-lab.com"
        }
    }

  # azurerm_resource_group.demo will be created
  + resource "azurerm_resource_group" "demo" {
      + id       = (known after apply)
      + location = "westus"
      + name     = "RG_vCloud-lab"
    }

Plan: 2 to add, 0 to change, 0 to destroy.
azurerm_resource_group.demo: Creating...
azurerm_resource_group.demo: Creation complete after 5s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/RG_vCloud-lab]
azurerm_network_security_group.vcloud-lab: Creating...
azurerm_network_security_group.vcloud-lab: Still creating... [10s elapsed]
azurerm_network_security_group.vcloud-lab: Creation complete after 20s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/RG_vCloud-lab/providers/Microsoft.Network/networkSecurityGroups/NSG_vCloud-lab]

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

Useful Articles
Create an Azure App registrations in Azure Active Directory using PowerShell & AzureCLI
Get started and configure with certificate-based authentication in Azure
Create a Virtual machine on Microsoft Azure
PowerShell List All Azure Resverations
Powershell get the list of Azure Reservations Virtual Machines instances
Get the list Azure Reservation Catalog with PowerShell and AzureCLI
Azure automation account DSC for On-Premise Virtual Machine on boarding
Azure Powershell : Operation returned an invalid status code 'BadRequest'
Get Azure virtual machine backup reports using Powershell

Go Back



Comment

Blog Search

Page Views

12273407

Follow me on Blogarama