# locals ===================================================================== data "aws_availability_zones" "available" { state = "available" } locals { region_abbr = split("-", data.aws_availability_zones.available.zone_ids[0])[0] module_tags = { managed-by = "terraform" module-name = "networking:security-groups" } sg_names = { for sg_key, sg in var.security_groups : sg_key => "${var.name_prefix}-${local.region_abbr}-${sg.name_suffix}" } # Ingress rules, step 1: expand each rule into one entry per source. # A rule with 2 CIDRs becomes 2 entries here, sharing the same # protocol, ports, and description. source_sg_key resolves to another # SG created by this module call; source_sg_id references any existing # SG by ID directly. Both collapse into a single "sg" source type, # disambiguated by a key:/id: prefix resolved at the resource block. ingress_sources = flatten([ for sg_key, sg in var.security_groups : [ for idx, rule in sg.ingress_rules : [ for source in concat( [for c in rule.ipv4_cidr_blocks : { type = "cidr4", value = c }], [for c in rule.ipv6_cidr_blocks : { type = "cidr6", value = c }], rule.source_sg_key != null ? [{ type = "sg", value = "key:${rule.source_sg_key}" }] : [], rule.source_sg_id != null ? [{ type = "sg", value = "id:${rule.source_sg_id}" }] : [], rule.self ? [{ type = "self", value = "" }] : [] ) : { sg_key = sg_key idx = idx rule = rule source_type = source.type source_value = source.value } ] ] ]) # Ingress rules, step 2: key each expanded entry for for_each. # The index keeps keys unique when a rule expands to multiple sources. ingress_rule_map = { for i, item in local.ingress_sources : "${item.sg_key}-ingress-${item.idx}-${item.source_type}-${i}" => item } # Egress rules, step 1: expand each rule into one entry per source. # A rule with 2 CIDRs becomes 2 entries here, sharing the same # protocol, ports, and description. source_sg_key resolves to another # SG created by this module call; source_sg_id references any existing # SG by ID directly. Both collapse into a single "sg" source type, # disambiguated by a key:/id: prefix resolved at the resource block. egress_sources = flatten([ for sg_key, sg in var.security_groups : [ for idx, rule in sg.egress_rules : [ for source in concat( [for c in rule.ipv4_cidr_blocks : { type = "cidr4", value = c }], [for c in rule.ipv6_cidr_blocks : { type = "cidr6", value = c }], rule.source_sg_key != null ? [{ type = "sg", value = "key:${rule.source_sg_key}" }] : [], rule.source_sg_id != null ? [{ type = "sg", value = "id:${rule.source_sg_id}" }] : [], rule.self ? [{ type = "self", value = "" }] : [] ) : { sg_key = sg_key idx = idx rule = rule source_type = source.type source_value = source.value } ] ] ]) # Egress rules, step 2: key each expanded entry for for_each. # The index keeps keys unique when a rule expands to multiple sources. egress_rule_map = { for i, item in local.egress_sources : "${item.sg_key}-egress-${item.idx}-${item.source_type}-${i}" => item } }