main.tf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 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
}