1
votes

I would like to create a set of network security (nsg) rules in Azure between different subnets by using Terraform. For that purpose, i have written the below code:

#here, a set of subnets are created according to the value of count. 
resource "azurerm_subnet" "mysubnets" {
    count = var.subnet_number
    name = join("-", ["subnet", count.index])
    resource_group_name = var.rgname
    virtual_network_name = azurerm_virtual_network.Global_VNet.name
    address_prefix = join(".", ["10.0", "${count.index}", "0/24"])
}

product variable below is created in order to create nsg rule with subnet pairs. It enables to iterate over the subnets pair. I retrieve address_prefixes inside the declaration of resource azurerm_network_security_rule

locals {
  product = "${setproduct(azurerm_subnet.mysubnets, azurerm_subnet.mysubnets)}"
}

resource "azurerm_network_security_rule" "myNSGrule" {
      count                       = var.subnet_number * var.subnet_number
      source_address_prefix       = lookup(element(local.product, count.index)[0],"address_prefix")
      destination_address_prefix  = lookup(element(local.product, count.index)[1],"address_prefix")
      name                        = join("-", ["nsg","${count.index}"])
      priority                    = 100 + count.index
      direction                   = "Outbound"
      access                      = "Allow"
      protocol                    = "*"
      source_port_range           = "*"
      destination_port_range      = "*"
      resource_group_name         = var.rgname
      network_security_group_name = azurerm_network_security_group.myNSG.name

}


resource "azurerm_virtual_network" "Global_VNet" {
  name                = var.vnetname
  resource_group_name = var.rgname
  address_space       = var.VNetAddressSpace
  location            = var.location
}

resource "azurerm_network_security_group" "myNSG" {
  name                = join("-", ["${var.rgname}", "nsg"])
  location            = var.location
  resource_group_name = var.rgname
}


#NSG subnet association
 resource "azurerm_subnet_network_security_group_association" "LabNSGAssoc" {
  count                     = var.subnet_number
  subnet_id                 = azurerm_subnet.mysubnets[count.index].id
  network_security_group_id = azurerm_network_security_group.myNSG.id
} 

I want to avoid nsg rules where destination and source prefix are identical as below: enter image description here

I have tried several different Terraform function but couldn't find a solution. Do you have any ideas?

1
Is it unclear how the config relates to the question, but it sounds like you are asking how to create a Map from a List, where every element is a key, and an array of every element that is not identical to the key is the value. Is that accurate?Matt Schuchard
i guess in a set variable, all the elements are different. But you got the idea. I have tried distinct() function with distinct(setproduct(azurerm_subnet.mysubnets, azurerm_subnet.mysubnets)). But it doesn't eliminate. I will add some more comments to clarify it.MoonHorse
Without specific information about your config, you should be able to do something with a lambda like: [for i, j in zipmap(<subnet_list>, <subnet_list>): {i: j} if i != j]. Although that would probably work, it does also feel kind of suboptimal as I am speculating on your config and just kind of spitballing here.Matt Schuchard
i am trying to realize that algorytm within TerraformMoonHorse

1 Answers

1
votes

You can filter a collection using the optional if clause of a for expression:

locals {
  product = [
    for pair in setproduct(azurerm_subnet.mysubnets, azurerm_subnet.mysubnets) : pair
    if pair[0] != pair[1]
  ]
}

The if clause filters out any elements where the given condition doesn't hold, so with the above condition the result will include only the items where the first and second element of pair are different.