'Add values to deep nested map in Terraform

I'm using the AWS EKS module 18.20.5 and I'm trying to add values to a deeply nested map. The map is

variable "eks_managed_node_groups" {
  description = "Map of managed node group definitions to create"
  type        = any
  default     = {
    management_cluster_on_demand = {
      desired_capacity = 3
      max_capacity     = 10
      min_capacity     = 3

      instance_types = ["c5.2xlarge"]
      capacity_type  = "ON_DEMAND"
      k8s_labels = {
        Environment  = "testing"
        GithubRepo   = "infrastructure-modules-kubernetes-cluster"
        GithubSource = "terraform-aws-modules"
      }
      additional_tags = {
        cluster = "management_cluster_new"
      }

      block_device_mappings = {
        xvda = {
          device_name = "/dev/xvda"
          ebs = {
            volume_size           = 50
            volume_type           = "gp2"
            delete_on_termination = true
          }
        }
      }
    }
  }
}

What I am aiming to do is add some extra values into the ebs section, specifically

encrypted = true
kms_key_id = module.kms.arn

This would force any volumes added to a node group, to have their EBS volume encrypted with a KMS key.

I've tried using locals to add the values, but the issue is when I get to the xbda section, it tries to loop through the strings and fails

locals {
  managed_nodes = flatten([
    for group in var.eks_managed_node_groups: [
      for vol in group.block_device_mappings: [
        for settings in vol: [
          for values in settings: values
        ]
      ]
    ]
  ])
}

Which when running Terraform plan, results in the following error

│ Error: Iteration over non-iterable value
│ 
│   on main.tf line 9, in locals:
│    8:         for settings in vol: [
│    9:           for values in settings: values
│   10:         ]
│ 
│ A value of type string cannot be used as the collection in a 'for' expression.

Is this even possible to accomplish? Thanks.



Solution 1:[1]

I think the following should do the job:

locals {
    eks_managed_node_groups = {
        for group_name, group in var.eks_managed_node_groups: 
          group_name => merge(group, {block_device_mappings = {
                for device_name, device in group.block_device_mappings: 
                    device_name => merge(device, 
                             {ebs=merge(device.ebs, {
                                    encrypted = true
                                    kms_key_id = "module.kms.arn"
                                })})
                }})

            }
}

resulting in:

{
  "management_cluster_on_demand" = {
    "additional_tags" = {
      "cluster" = "management_cluster_new"
    }
    "block_device_mappings" = {
      "xvda" = {
        "device_name" = "/dev/xvda"
        "ebs" = {
          "delete_on_termination" = true
          "encrypted" = true
          "kms_key_id" = "module.kms.arn"
          "volume_size" = 50
          "volume_type" = "gp2"
        }
      }
    }
    "capacity_type" = "ON_DEMAND"
    "desired_capacity" = 3
    "instance_types" = [
      "c5.2xlarge",
    ]
    "k8s_labels" = {
      "Environment" = "testing"
      "GithubRepo" = "infrastructure-modules-kubernetes-cluster"
      "GithubSource" = "terraform-aws-modules"
    }
    "max_capacity" = 10
    "min_capacity" = 3
  }
}

I don't have your module.kms.arn, so I just use it as string "module.kms.arn". So you have to change it back to module.kms.arn.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Marcin