Append a new rule to aws network acl

looking to append a new rule in aws network acl, I am trying to use “aws_network_acl_rule” resource but this requires a rule number to be specified which is changing each time I need to append a new rule to the ACL. is there a way to append a new rule by making the the rule number incremented +1 each time the code is applied.

resource “aws_network_acl_rule” “main” {
network_acl_id = “${var.nacl_id}”
rule_number = 1 + length(aws_network_acl_rule)
egress = false
protocol = -1
rule_action = “allow”
cidr_block = var.publicIP
from_port = 0
to_port = 22

Hi @haytem75,

There is no inherent ordering between resources in Terraform, and so any rule you implement to deal with the numbering of your rules will need to be implemented manually by you as Terraform expressions.

I’m not sure I fully understood what you intend your final result to look like, but one way to manage this would be to arrange your rules into a list of objects and then derive your rule numbering from the indices of the list. This would then allow Terraform to renumber the rules automatically if you insert new rules into the list later, and ensure that all of the rule numbers are unique.

For example:

locals {
  acl_rules = tolist([
    {
      key         = "allow_ssh"
      egress      = false
      protocol    = "-1"
      rule_action = "allow"
      cidr_block  = var.publicIP
      from_port   = 0
      to_port     = 22
    },
    {
      key         = "allow_tcp:8000-8010"
      egress      = false
      protocol    = "tcp"
      rule_action = "allow"
      cidr_block  = var.publicIP
      from_port   = 8000
      to_port     = 8010
    },
  ])

  # This "inverts" the relationship between list
  # indices and keys, so that we have a map of
  # named rules that each have an index, rather
  # than a list of rules that each have a name.
  rules_map = tomap({
    for index, rule in local.acl_rules : merge(
      rule,
      { rule_number = 1 + index },
    )
  })
}

resource "aws_network_acl_rule" "all" {
  for_each = local.rules_map

  network_acl_id = var.nacl_id
  rule_number    = var.rule_number

  egress      = each.value.egress
  protocol    = each.value.protocol
  rule_action = each.value.rule_action
  cidr_block  = each.value.cidr_block
  from_port   = each.value.from_port
  to_port     = each.value.to_port
}

The reason for the extra step of “inverting” the map here is to tell Terraform that it should track these individual rules by their key strings rather than by their rule numbers. That means that the above will declare resource instances with addresses like this:

  • aws_network_rule.all["allow_ssh"] with rule_number = 1
  • aws_network_rule.all["allow_tcp:8000-8010"] with rule_number = 2

If you add a new rule to your list with key = "new_example" in between the allow_ssh rule and the allow_tcp:8000-8010 rule then because Terraform is tracking these instances by their keys rather than their indices Terraform will plan to make the following changes:

  • Create a new instance aws_network_rule.all["new_example"] with rule_number = 2
  • Update the existing instance aws_network_rule.all["allow_tcp:8000-8010"] to have rule_number = 3, to adjust for the insertion of the new_example rule.