Terraform Security:

Last Updated on August 7, 2025 by Arnav Sharma

Let’s assume you want to configure resources where attributes require similar structures. A list-to-map conversion with objects makes this more manageable.

Example

Consider this scenario: you have a list of property names. You want to create a map where each property name is a key, and the value is an object defining that property’s type.

Steps

Define Your List:

variable "property_list" {
  type = list(string)
  default = ["name", "description", "type"]
}

Create an Empty Map:

locals {
    property_map = {}
}

Use a for loop:

locals {
  property_map = {
    for prop in var.property_list : prop => {
      "type" = "string"  # Assign a default type
    }
  }
}

Explanation

  • We start with a variable property_list containing the names of your properties.
  • An empty map, property_map, is created within a locals block.
  • The for loop iterates over each prop (property name) in the property_list.
  • Inside the loop, it constructs an object with the current prop as the key. The object has a single attribute, “type”, set to “string” (you can customize this).
  • This object is then added to the property_map.

Output

The resulting property_map would look like this:

{
  "name"        = { "type" = "string" }
  "description" = { "type" = "string" }
  "type"        = { "type" = "string" }
}

Usage

You could then use this property_map to dynamically create resource configurations, feeding these objects into attributes.

Key Points

  • locals are used to define values that can be referenced elsewhere in your Terraform configuration.
  • for loops are essential for transforming data structures in Terraform.
  • Customize the object’s structure within the for loop to suit your specific use case (add more attributes, change types, etc.).

Example of Azure VM:

Let’s say you need to create several Azure VMs with similar configurations, but you want to vary the VM names and possibly some other attributes.

provider "azurerm" {
  # ... Your Azure provider configuration ...
}

# Variables for VM configuration
variable "vm_names" {
  type = list(string)
  default = ["webserver-01", "webserver-02", "dbserver"]
}

variable "base_vm_config" {
  type = map(object({
    size          = string
    resource_group_name = string
    location          = string
    image_urn         = string
    admin_username    = string
    admin_password    = string
  }))
  default = {
    size          = "Standard_B2s"
    resource_group_name = "my-resource-group" 
    location          = "eastus" 
    image_urn         = "Canonical:UbuntuServer:18.04-LTS:latest"
    admin_username    = "adminuser"
    admin_password    = "your_secure_password" 
  }
}

# Customize individual VM configurations
locals {
  vm_configs = {
    for vm_index, vm_name in var.vm_names : vm_name => merge(var.base_vm_config, {
      name = vm_name,
      size = (vm_index == 2 ? "Standard_D2s_v3" : var.base_vm_config.size), 
      tags = {
        "role" = (vm_name == "dbserver" ? "database" : "web")
      }
    })
  }
}

# Iterate and create VMs using the map
resource "azurerm_virtual_machine" "vm" {
  for_each = local.vm_configs

  # Access VM settings with each.key (VM name) and each.value 
  name                = each.key 
  size                = each.value.size
  resource_group_name = each.value.resource_group_name
  location            = each.value.location

  # ... (other VM configurations using each.value: network_interface_ids, storage_image_reference, etc.)

  os_profile {
    computer_name  = each.key
    admin_username = var.base_vm_config.admin_username
    admin_password = var.base_vm_config.admin_password
  }

  os_profile_linux_config {
    disable_password_authentication = false
  } 
}

Explanation:

  1. provider “azurerm”: Configures the Azure Resource Manager provider. You’ll need to have this set up with your Azure credentials.
  2. variable “vm_names”: Defines a list of your desired Azure VM names.
  3. variable “base_vm_config”: A map storing the core configuration that will be shared across most of your VMs.
  4. locals “vm_configs”:
    • for loop: Iterates over both the name and index (vm_index) of each VM.
    • merge: Combines the base_vm_config with customizations:
      • name: Sets the VM name.
      • size: Conditionally assigns a different size for the third VM.
      • tags: Assigns role-based tags for identification.
  5. resource “azurerm_virtual_machine” “vm”:
    • for_each: Iterates over the vm_configs map.
    • each.key: Provides the VM name (e.g., “webserver-01”).
    • each.value: Provides the entire configuration object for that specific VM.
    • Example usage: Access each.value.sizeeach.value.tags, etc.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.