# Network ACLs =============================================================== # One NACL per logical key, associated to its subnet list at creation. # Rules are managed as separate resources to avoid inline rule conflicts. resource "aws_network_acl" "this" { for_each = var.network_acls vpc_id = var.vpc_id subnet_ids = each.value.subnet_ids tags = merge(var.tags, local.module_tags, { Name = "${var.name_prefix}-${local.region_abbr}-nacl-${each.key}" resource-type = "network-acl" }) lifecycle { precondition { condition = length("${var.name_prefix}-${local.region_abbr}-nacl-${each.key}") <= 255 error_message = "Assembled NACL name exceeds AWS's 255-character limit" } } } # Ingress Rules -------------------------------------------------------------- # Stateless — inbound traffic only. Return traffic must be explicitly allowed # in egress rules. Rules are evaluated lowest number first, first match wins. resource "aws_network_acl_rule" "ingress" { for_each = local.ingress_map network_acl_id = aws_network_acl.this[each.value.nacl_key].id rule_number = each.value.rule.rule_number egress = false rule_action = each.value.rule.action protocol = each.value.rule.protocol from_port = each.value.rule.protocol == "-1" ? null : each.value.rule.from_port to_port = each.value.rule.protocol == "-1" ? null : each.value.rule.to_port cidr_block = each.value.rule.cidr_block icmp_type = each.value.rule.icmp_type icmp_code = each.value.rule.icmp_code } # Egress Rules --------------------------------------------------------------- # Stateless — outbound traffic only. Must explicitly allow return traffic # for any inbound rule, including ephemeral ports (1024-65535) for TCP/UDP. resource "aws_network_acl_rule" "egress" { for_each = local.egress_map network_acl_id = aws_network_acl.this[each.value.nacl_key].id rule_number = each.value.rule.rule_number egress = true rule_action = each.value.rule.action protocol = each.value.rule.protocol from_port = each.value.rule.protocol == "-1" ? null : each.value.rule.from_port to_port = each.value.rule.protocol == "-1" ? null : each.value.rule.to_port cidr_block = each.value.rule.cidr_block icmp_type = each.value.rule.icmp_type icmp_code = each.value.rule.icmp_code }