Creating multiple NSGs using a single terraform module

I am new to terraform. I have created a module to create single NSG with some pre defined rules and custom rules.
The module is working fine. I wanted to know if the same module can be used to create multiple NSGs in single call of the module.

Please let me know if this is possible.
Below is the code for single NSG creation:

locals.tf

locals {

predefined_rules = {

for r in var.predefined_rules :

r.name => {

  name                                       = r.name

  priority                                   = lookup(r, "priority", 4096 - length(var.predefined_rules) + index(var.predefined_rules, r))

  direction                                  = element(var.rules[lookup(r, "name")], 0)

  access                                     = element(var.rules[lookup(r, "name")], 1)

  protocol                                   = element(var.rules[lookup(r, "name")], 2)

  source_port_ranges                         = split(",", replace(lookup(r, "source_port_range", "*"), "*", "0-65535"))

  destination_port_range                     = element(var.rules[lookup(r, "name")], 4)

  description                                = element(var.rules[lookup(r, "name")], 5)

  source_address_prefix                      = lookup(r, "source_application_security_group_ids", null) == null && var.source_address_prefixes == null ? join(",", var.source_address_prefix) : null

  source_address_prefixes                    = lookup(r, "source_application_security_group_ids", null) == null ? var.source_address_prefixes : null

  destination_address_prefix                 = lookup(r, "destination_application_security_group_ids", null) == null && var.destination_address_prefixes == null ? join(",", var.destination_address_prefix) : null

  destination_address_prefixes               = lookup(r, "destination_application_security_group_ids", null) == null ? var.destination_address_prefixes : null

  resource_group_name                        = data.azurerm_resource_group.rg.name

  network_security_group_name                = azurerm_network_security_group.nsg.name

  source_application_security_group_ids      = lookup(r, "source_application_security_group_ids", null)

  destination_application_security_group_ids = lookup(r, "destination_application_security_group_ids", null)

}

}

custom_rules = {

for r in var.custom_rules :

r.name => {

  name                                       = r.name

  priority                                   = lookup(r, "priority")

  direction                                  = lookup(r, "direction", "Any")

  access                                     = lookup(r, "access", "Allow")

  protocol                                   = lookup(r, "protocol", "*")

  source_port_ranges                         = split(",", replace(lookup(r, "source_port_range", "*"), "*", "0-65535"))

  destination_port_ranges                    = split(",", replace(lookup(r, "destination_port_range", "*"), "*", "0-65535"))

  source_address_prefix                      = lookup(r, "source_application_security_group_ids", null) == null && lookup(r, "source_address_prefixes", null) == null ? lookup(r, "source_address_prefix", "*") : null

  source_address_prefixes                    = lookup(r, "source_application_security_group_ids", null) == null ? lookup(r, "source_address_prefixes", null) : null

  destination_address_prefix                 = lookup(r, "destination_application_security_group_ids", null) == null && lookup(r, "destination_address_prefixes", null) == null ? lookup(r, "destination_address_prefix", "*") : null

  destination_address_prefixes               = lookup(r, "destination_application_security_group_ids", null) == null ? lookup(r, "destination_address_prefixes", null) : null

  description                                = lookup(r, "description", "Security rule for ${lookup(r, "name", "default_rule_name")}")

  resource_group_name                        = data.azurerm_resource_group.rg.name

  network_security_group_name                = azurerm_network_security_group.nsg.name

  source_application_security_group_ids      = lookup(r, "source_application_security_group_ids", null)

  destination_application_security_group_ids = lookup(r, "destination_application_security_group_ids", null)

}

}

}

main.tf

data “azurerm_resource_group” “rg” {

name = var.resource_group_name

}

resource “azurerm_network_security_group” “nsg” {

name = var.name

resource_group_name = data.azurerm_resource_group.rg.name

location = data.azurerm_resource_group.rg.location

}

resource “azurerm_network_security_rule” “predefined_rules” {

for_each = local.predefined_rules

name = each.value.name

priority = each.value.priority

direction = each.value.direction

access = each.value.access

protocol = each.value.protocol

source_port_ranges = each.value.source_port_ranges

destination_port_range = each.value.destination_port_range

description = each.value.description

source_address_prefix = each.value.source_address_prefix

source_address_prefixes = each.value.source_address_prefixes

destination_address_prefix = each.value.destination_address_prefix

destination_address_prefixes = each.value.destination_address_prefixes

resource_group_name = data.azurerm_resource_group.rg.name

network_security_group_name = azurerm_network_security_group.nsg.name

source_application_security_group_ids = each.value.source_application_security_group_ids

destination_application_security_group_ids = each.value.destination_application_security_group_ids

}

resource “azurerm_network_security_rule” “custom_rules” {

for_each = local.custom_rules

name = each.value.name

priority = each.value.priority

direction = each.value.direction

access = each.value.access

protocol = each.value.protocol

source_port_ranges = each.value.source_port_ranges

destination_port_ranges = each.value.destination_port_ranges

description = each.value.description

source_address_prefix = each.value.source_address_prefix

source_address_prefixes = each.value.source_address_prefixes

destination_address_prefix = each.value.destination_address_prefix

destination_address_prefixes = each.value.destination_address_prefixes

resource_group_name = data.azurerm_resource_group.rg.name

network_security_group_name = azurerm_network_security_group.nsg.name

source_application_security_group_ids = each.value.source_application_security_group_ids

destination_application_security_group_ids = each.value.destination_application_security_group_ids

}

output.tf

output “name” {

description = “The network security group name.”

value = azurerm_network_security_group.nsg.name

}

output “id” {

description = “The network security group id.”

value = azurerm_network_security_group.nsg.id

}

output “resource_group_name” {

description = <<EOT

The name of the resource group where the network security group is created.

EOT

value = azurerm_network_security_group.nsg.resource_group_name

}

output “location” {

description = <<EOT

The location/region where the network security group is created.

EOT

value = azurerm_network_security_group.nsg.location

}

variables.tf

variable “resource_group_name” {

description = <<EOT

The name of the resource group in which to create the network security group.

The Resource Group must already exist.

EOT

type = string

}

variable “name” {

description = <<EOT

The name of the network security group.

Changing this forces a new resource to be created.

EOT

type = string

}

variable “predefined_rules” {

description = “Predefined rules”

type = any

default = [

      {

  name     = "DenyAllIn"

  priority = "4096"

},

{

    name = "DenyAllOut"

    priority = "4096"

}

]

}

Custom security rules

[priority, direction, access, protocol, source_port_range, destination_port_range, description]"

All the fields are required.

variable “custom_rules” {

description = <<EOT

Security rules for the network security group using this format:

name = [

priority,

direction,

access,

protocol,

source_port_range,

destination_port_range,

source_address_prefix,

destination_address_prefix,

description

]

EOT

type = any

default =

}

variable “rules” {

description = <<EOT

Standard set of predefined rules using this format:

name = [

direction,

access,

protocol,

source_port_range,

destination_port_range,

description

]

This variable is used to set the predefined rules.

EOT

type = map(any)

default = {

#DenyAllin

DenyAllIn = ["Inbound", "Deny", "TCP", "*", "*", "DenyAllIn"]

#DenyAllout

DenyAllOut = ["Outbound", "Deny", "TCP", "*", "*", "DenyAllOut"]

}

}

variable “source_address_prefix” {

description = <<EOT

Source address prefix to be applied to all predefined rules

list(string) only allowed one element (CIDR, *, source IP range or Tags)

Example [“10.0.3.0/24”] or [“VirtualNetwork”]

EOT

type = list(string)

default = ["*"]

}

variable “source_address_prefixes” {

description = <<EOT

Destination address prefix to be applied to all predefined rules

Example [“10.0.3.0/32”,“10.0.3.128/32”]

EOT

type = list(string)

default = null

}

variable “destination_address_prefix” {

description = <<EOT

Destination address prefix to be applied to all predefined rules

list(string) only allowed one element (CIDR, *, source IP range or Tags)

Example [“10.0.3.0/24”] or [“VirtualNetwork”]

EOT

type = list(string)

default = ["*"]

}

variable “destination_address_prefixes” {

description = <<EOT

Destination address prefix to be applied to all predefined rules

Example [“10.0.3.0/32”,“10.0.3.128/32”]

EOT

type = list(string)

default = null

}