Building DevSecOps solutions using AWS, Terraform and Kubernetes

How To Iterate Over Nested Maps In Terraform

  • 22nd May 2024

Introduction

We will explore iterating over a nested map in terraform by looking at the simple example of attaching policies to roles.

Setup Nested Map

First up, we need to create a dummy variable that will contain our nested map:

variable "role_map" {
  default = {
    "role_1" = {
      "name" : "Role 1"
      "policies" : ["policy_arn_1", "policy_arn_2", "policy_arn_3"],
    },
    "role_2" = {
      "name" : "Role 2"
      "policies" : ["policy_arn_2", "policy_arn_4", "policy_arn_6"],
    }
  }
}

As you can see each role contains many policies which creates trouble while looping through the map.

Flatten Nested Map

In order to convert this into a format we can iterate over. we need to flatten this map:

locals {
  role_policies = flatten([
    for role_key, role in var.role_map : [
      for p, policy in role.policies : {
        role_key  = role_key
        role_name = role.name
        policy_arn  = policy
      }
    ]
  ])
}

Test Flattened Map

We can confirm this worked as expected by using the terraform console command.

Within the console, run local.role_policies. You should now see the following output:

[
  {
    "policy_arn" = "policy_arn_1"
    "role_key" = "role_1"
    "role_name" = "Role 1"
  },
  {
    "policy_arn" = "policy_arn_2"
    "role_key" = "role_1"
    "role_name" = "Role 1"
  },
  {
    "policy_arn" = "policy_arn_3"
    "role_key" = "role_1"
    "role_name" = "Role 1"
  },
  {
    "policy_arn" = "policy_arn_2"
    "role_key" = "role_2"
    "role_name" = "Role 2"
  },
  {
    "policy_arn" = "policy_arn_4"
    "role_key" = "role_2"
    "role_name" = "Role 2"
  },
  {
    "policy_arn" = "policy_arn_6"
    "role_key" = "role_2"
    "role_name" = "Role 2"
  },
]

This is now in the ideal format. Every policy is now flattened out, but still references the original role it should be attached to.

Iterate Over Flattened Map

We can now loop through our flattened local.role_policies:

resource "example_terraform_resource_attach_policy" "example" {
  for_each = { for p, policy in local.role_policies : p => policy }

  policy_arn = each.value.policy_arn
  role_key = each.value.role_key
}

This will create all 6 policies with the correct policy_arn, and assign them the correct role_key.

Summary

And that’s it! We get to keep the benefits of working with a nested map while still being able to iterate over them.

Rhuaridh

Please get in touch through my socials if you would like to ask any questions - I am always happy to speak tech!