Search code examples
terraformterraform-provider-azureazure-rm

Terraform azurerm provider count and csvdecode


I'm trying to populate NSG rules from a CSV file.

CSV file:

name,priority,direction,access,protocol,source_port_range,destination_port_range,destination_port_ranges,source_address_prefix,destination_address_prefix,resource_group_name,network_security_group_name
allowindatasubnet,600,inbound,allow,*,*,*,,192.168.3.0/24,*,resourcegroup1,networksecgroup1
allowinremote,700,inbound,allow,*,*,,"3389,22",192.168.1.128/27,*,resourcegroup1,networksecgroup1
denyinall,1000,inbound,deny,*,*,*,,*,*,resourcegroup1,networksecgroup1

tf file:

locals {
  network_security_group_rules = csvdecode(file("/csvfile.csv"))
}
resource "azurerm_network_security_rule" "network_security_rule_WL1" {

  count = length(local.network_security_group_rules)

  name                        = local.network_security_group_rules[count.index].name
  priority                    = local.network_security_group_rules[count.index].priority
  direction                   = local.network_security_group_rules[count.index].direction
  access                      = local.network_security_group_rules[count.index].access
  protocol                    = local.network_security_group_rules[count.index].protocol
  source_port_range           = local.network_security_group_rules[count.index].source_port_range
  destination_port_range      = local.network_security_group_rules[count.index].destination_port_range
  destination_port_ranges     = [local.network_security_group_rules[count.index].destination_port_ranges]
  source_address_prefix       = local.network_security_group_rules[count.index].source_address_prefixyes
  destination_address_prefix  = local.network_security_group_rules[count.index].destination_address_prefix
  resource_group_name         = local.network_security_group_rules[count.index].resource_group_name
  network_security_group_name = local.network_security_group_rules[count.index].network_security_group_name

}

This works fine without the destination_port_ranges attribute within the nsg rule resource block, but when I add it in I get an error:

Error: "destination_port_ranges": conflicts with destination_port_range

I understand that I need to use one argument or the other, but can anyone help me with the syntax or suggest changes that I can make allowing me to keep the same CSV format?

Also is my config correct for specifying a list of ports for the destination_port_ranges argument?

UPDATE: I tried the following which was suggested by a friend but this threw up the same exception.

destination_port_range      = local.network_security_group_rules[count.index].destination_port_range != "" ? local.network_security_group_rules[count.index].destination_port_range : null
destination_port_ranges     = local.network_security_group_rules[count.index].destination_port_ranges != "" ? split(",", local.network_security_group_rules[count.index].destination_port_ranges) : null

Thanks!


Solution

  • As you said that you just need one argument, not both. As I see, all your destination port is a list or the character * and it means a range. Let's see the description of the argument destination_port_ranges and destination_port_range:

    destination_port_range - (Optional) Destination Port or Range. Integer or range between 0 and 65535 or * to match any. This is required if destination_port_ranges is not specified.

    destination_port_ranges - (Optional) List of destination ports or port ranges. This is required if destination_port_range is not specified.

    You use a list of destination ports or port ranges, so you just need to set the argument destination_port_ranges in the csv file for the network security rules.

    Update:

    You can use a module for the rules, the module is used to decide use which attribute for each rule:

    ./main.tf

    locals {
      network_security_group_rules = csvdecode(file("/csvfile.csv"))
    }
    
    module "rules" {
        source = "./modules/rules"
    
        count = length(local.network_security_group_rules)
        rule = local.network_security_group_rules[count.index]
    }
    

    ./modules/rules/main.tf

    variable "rule" {}
    
    resource "azurerm_network_security_rule" "network_security_rule_WL1" {
    
      count = rule.destination_port_range == null ? 0 : 1
    
      name                        = local.network_security_group_rules[count.index].name
      priority                    = local.network_security_group_rules[count.index].priority
      direction                   = local.network_security_group_rules[count.index].direction
      access                      = local.network_security_group_rules[count.index].access
      protocol                    = local.network_security_group_rules[count.index].protocol
      source_port_range           = local.network_security_group_rules[count.index].source_port_range
      destination_port_range      = local.network_security_group_rules[count.index].destination_port_range
      source_address_prefix       = local.network_security_group_rules[count.index].source_address_prefixyes
      destination_address_prefix  = local.network_security_group_rules[count.index].destination_address_prefix
      resource_group_name         = local.network_security_group_rules[count.index].resource_group_name
      network_security_group_name = local.network_security_group_rules[count.index].network_security_group_name
    
    }
    
    resource "azurerm_network_security_rule" "network_security_rule_WL1" {
    
      count = rule.destination_port_ranges == null ? 0 : 1
    
      name                        = local.network_security_group_rules[count.index].name
      priority                    = local.network_security_group_rules[count.index].priority
      direction                   = local.network_security_group_rules[count.index].direction
      access                      = local.network_security_group_rules[count.index].access
      protocol                    = local.network_security_group_rules[count.index].protocol
      source_port_range           = local.network_security_group_rules[count.index].source_port_range
      destination_port_ranges     = [local.network_security_group_rules[count.index].destination_port_ranges]
      source_address_prefix       = local.network_security_group_rules[count.index].source_address_prefixyes
      destination_address_prefix  = local.network_security_group_rules[count.index].destination_address_prefix
      resource_group_name         = local.network_security_group_rules[count.index].resource_group_name
      network_security_group_name = local.network_security_group_rules[count.index].network_security_group_name
    
    }
    

    In this way, you can't create a rule with both two attributes not null, I mean each rule only can have one of the two attributes.