Search code examples
terraformterraform-provider-aws

Creating resources from locals.tf with variable inputs


I have a long list of ACL rules and am trying to generate an aws_network_acl by iterating over them. The rules are in a locals.tf file in my module to keep main.tf a bit tidier, and look like this

locals.tf

locals {
  webapp = [{
    "protocol"  = "tcp"
    "rule_no"   = 100
    "action"    = "allow"
    "from_port" = 22
    "to_port"   = 22
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 110
      "action"    = "allow"
      "from_port" = 60111
      "to_port"   = 60111
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 120
      "action"    = "allow"
      "from_port" = 3243
      "to_port"   = 3243
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 130
      "action"    = "allow"
      "from_port" = 6379
      "to_port"   = 6379
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 140
      "action"    = "allow"
      "from_port" = 50123
      "to_port"   = 50123
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 150
      "action"    = "allow"
      "from_port" = 50432
      "to_port"   = 50432
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 160
      "action"    = "allow"
      "from_port" = 3306
      "to_port"   = 3306
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 170
      "action"    = "allow"
      "from_port" = 50001
      "to_port"   = 50001
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 180
      "action"    = "allow"
      "from_port" = 50010
      "to_port"   = 50015
    },
    {
      "protocol"  = "tcp"
      "rule_no"   = 190
      "action"    = "allow"
      "from_port" = 50650
      "to_port"   = 50660
    }
  ]
}

(there are more but shortened for brevity.

In my module's main.tf I want to iterate over each, creating an ACL

resource "aws_network_acl" "webapp" {
  vpc_id = data.aws_vpc.posttrade-vpc.id

  for_each = {for idx, query in locals.posttrade: idx => query}
  egress = [
    protocol = each.value.protocol
    rule_no = each.value.rule_no
    action = "allow"
    from_port = each.value.from_port
    to_port = each.value.to_port
  ]
}

But get the error

Missing item separator: Expected a comma to mark the beginning of the next item.

Is it possible to do this from a locals file, or a variables map?


Solution

  • You are missing a dynamic block to create multiples egress. You just need to add the code:

    resource "aws_network_acl" "webapp" {
      vpc_id = data.aws_vpc.posttrade-vpc.id
      dynamic "egress" {
    
        for_each = toset(local.webapp)
    
        content {
          protocol  = egress.value["protocol"]
          rule_no   = egress.value["rule_no"]
          action    = "allow"
          from_port = egress.value["from_port"]
          to_port   = egress.value["to_port"]
        }
    
      }
    }
    

    And it will result in:

    Terraform will perform the following actions:
    
      # aws_network_acl.webapp will be created
      + resource "aws_network_acl" "webapp" {
          + arn        = (known after apply)
          + egress     = [
              + {
                  + action          = "allow"
                  + cidr_block      = ""
                  + from_port       = 22
                  + icmp_code       = null
                  + icmp_type       = null
                  + ipv6_cidr_block = ""
                  + protocol        = "tcp"
                  + rule_no         = 100
                  + to_port         = 22
                },
              + {
                  + action          = "allow"
                  + cidr_block      = ""
                  + from_port       = 3243
                  + icmp_code       = null
                  + icmp_type       = null
                  + ipv6_cidr_block = ""
                  + protocol        = "tcp"
                  + rule_no         = 120
                  + to_port         = 3243
                },
    ......