SOLVED

ARM Template To create Multiple NSG's associate with existing Subnet

Contributor

Hi All,

 

I am trying to create Multiple NSG with multiple rules associate with subnets. Can anyone give me the Template file which is used as single Template file for Multiple NSG.

Attached is the current files used by me for creating NSG.

 

The problem in the below script is, It is not creating more than 2 NSG's. So that i am expecting to have a single Template and parameter file to create multiple NSG's. More likely to use copy loops.

 

Template File:

 

{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
"contentVersion": "1.0.0.1",
"parameters": {
"virtualNetworkName": {
"type": "String"
},
"networkSecurityGroupName1": {
"type": "String"
},
"subnetName1": {
"type": "String"
},
"networkSecurityGroupRules1": {
"type": "Array"
},
"networkSecurityGroupName2": {
"type": "String"
},
"subnetName2": {
"type": "String"
},
"networkSecurityGroupRules2": {
"type": "Array"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2018-03-01",
"name": "[parameters('networkSecurityGroupName1')]",
"location": "[resourceGroup().location]",
"properties": {
"securityRules": "[parameters('networkSecurityGroupRules1')]"
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2017-08-01",
"name": "apply-nsg-to-subnet1",
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName1'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2018-03-01",
"type": "Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(parameters('virtualNetworkName'), '/', parameters('subnetName1'))]",
"location": "[resourceGroup().location]",
"properties": {
"addressPrefix": "[reference(resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName1')), '2018-03-01').addressPrefix]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName1'))]"
}
}
}
]
}
},
"resourceGroup": "[resourceGroup().name]"
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2018-03-01",
"name": "[parameters('networkSecurityGroupName2')]",
"location": "[resourceGroup().location]",
"properties": {
"securityRules": "[parameters('networkSecurityGroupRules2')]"
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2017-08-01",
"name": "apply-nsg-to-subnet2",
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName2'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2018-03-01",
"type": "Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(parameters('virtualNetworkName'), '/', parameters('subnetName2'))]",
"location": "[resourceGroup().location]",
"properties": {
"addressPrefix": "[reference(resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName2')), '2018-03-01').addressPrefix]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName2'))]"
}
}
}
]
}
},
"resourceGroup": "[resourceGroup().name]"
}
],
"outputs": {}
}

19 Replies
best response confirmed by vigneshkrcegmailcom (Contributor)
Solution

@vigneshkrcegmailcom 

Hi!

 

I've put together a template for you that solves your problem using copy loops for both the NSGs and the subnet association. You can find it here: https://gist.github.com/StefanIvemo/31cda6faa214824b2049a1e98f0e279b

 

I've created a parameter called NSGs of the type array in the template. Take a look at the example parameter file and adjust it to your needs. All you have to do is add/remove objects to the array and fill in NSGName, SubnetName and your SecurityRules. 

 

The template will first deploy all the NSGs and then do a nested deployment to do the subnet association.

 

Good luck with your deployment!

 

@StefanIvemo

 

Fantastic, NSG is working Expected. In the same way i need to create Route Tables and Number of Routes in each route tables. Can you please help me on that ??

@StefanIvem,

 

Can you please help me to create ARM for Route Tables associate with existing Subnets. 

Inside Each Routes i need numbers of Routes should be attached with properties.

 

Thanks,

Vignesh

@vigneshkrcegmailcom 

You can continue with the template I provided. Just add a property for routes to the parameter file for each of the objects in the array, the same way as for securityRules. E.g. "routes": [], and add your custom routes to it.

 

Then create a copy loop to create Microsoft.Network/routeTables just like the one for NSGs but modify the properties to work with the Route Table resource.

 

In the nested deploy where the NSG is associated with the subnet you add the routeTable property.

 

Good luck!

 

     

@StefanIvemo 

 

Hi,

 

Thanks for the quick update.....

 

I have modified as per your request but deployment is failing. Below is the Modified Template and Para files.

 

{
    "contentVersion""1.0.0.0",
    "parameters": {
        "location": {
            "type""String"
        },
        "VNetName": {
            "type""String",
            "metadata": {
                "description""description"
            }
        },
        "RTs": {
            "type""Array"
        }
    },
    "resources": [
        {
            "type""Microsoft.Network/routeTables",
            "apiVersion""2020-05-01",
            "name""[concat(parameters('RTs')[copyIndex()].properties.RTName)]",
            "location""[parameters('Location')]",
            "properties": {
                "Routes""[parameters('RTs')[copyIndex()].properties.Routes]"
            },
            "copy": {
                "name""RTs",
                "count""[length(parameters('RTs'))]"
            }
        },
        {
            "type""Microsoft.Resources/deployments",
            "apiVersion""2020-06-01",
            "name""[concat('apply',parameters('RTs')[copyIndex()].properties.RTName)]",
            "dependsOn": [
                "RTs"
            ],
            "properties": {
                "mode""Incremental",
                "template": {
                    "$schema""https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
                    "contentVersion""1.0.0.0",
                    "resources": [
                        {
                            "apiVersion""2020-05-01",
                            "type""Microsoft.Network/virtualNetworks/subnets",
                            "name""[concat(parameters('VNetName'), '/', parameters('RTs')[copyIndex()].properties.SubnetName)]",
                            "location""[resourceGroup().location]",
                            "properties": {
                                "addressPrefix""[reference(resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks/subnets', parameters('VNetName'), parameters('RTs')[copyIndex()].properties.SubnetName), '2018-03-01').addressPrefix]",
                                "networkSecurityGroup": {
                                    "id""[resourceId('Microsoft.Network/routeTables', parameters('RTs')[copyIndex()].properties.RTName)]"
                                }
                            }
                        }
                    ]
                }
            },
            "copy": {
                "name""association",
                "count""[length(parameters('RTs'))]",
                "mode""Serial"
            }
        }
    ]
}
 
======================================
 
{
    "contentVersion""1.0.0.0",
    "parameters": {
        "location": {
            "value""East US"
        },
        "VNetName": {
            "value""VN02"
        },
        "RTs": {
            "value": [
                {
                    "properties": {
                        "RTName""RT01",
                        "SubnetName""sub01",
                        "securityRules": [
                            {
                            
                "addressPrefix""10.1.0.0/16",
                "nextHopType""VnetLocal"
            }
                        ]
                    }
                },
                {
                    "properties": {
                        "RTName""RT02",
                        "SubnetName""sub02",
                        "securityRules": [
                        {
                "addressPrefix""10.2.0.0/16",
                "nextHopType""VnetLocal"
            }
                        ]
                    }
                },
                {
                    "properties": {
                        "RTName""RT03",
                        "SubnetName""sub03",
                        "securityRules": [
                            {
                                "addressPrefix""10.3.0.0/16",
                                "nextHopType""VnetLocal"
                            }

                        ]
                    }
                }
            ]
        }
    }
}
 
 

@vigneshkrcegmailcom 

 

I've updated the NSG template provided earlier with route tables as well. You can find it here:

https://gist.github.com/StefanIvemo/1862a1401fa982cc8f124a6148eda5f5

 

You can now deploy NSGs and Route Tables at the same time and update the subnets.

 

Hope it works for you!

@StefanIvemo 

 

Hi Stefan,

 

This is working as expected, Is it possible to create Multiple Routes inside One Route Table using this Same template and para files.

Can you please help me to create Multiple Routes inside route Table.

 

https://gist.github.com/StefanIvemo/1862a1401fa982cc8f124a6148eda5f5

 

I am trying to add two Routes inside one route table as below but i am not able to get it, Can you please help on this.

 

"disableBgpRoutePropagation"true,
            "routes": [
              {
                "name""Route1",
                "properties": {
                  "addressPrefix""0.0.0.0/0",
                  "nextHopType""VirtualAppliance",
                  "nextHopIpAddress""10.0.0.4"
                }
              },
              [
                {
                  "name""Route2",
                  "properties": {
                    "addressPrefix""0.0.0.0/0",
                    "nextHopType""VirtualAppliance",
                    "nextHopIpAddress""10.0.0.5"
                  }
                }
              ]
            ]

 

Regards,

Vignesh

@vigneshkrcegmailcom 

 

You can add additional routes by adding another route object in the routes array in the parameter file:

 

  "routes": [
    {
      "name""route1",
      "properties": {
        "addressPrefix""10.0.0.0/24",
        "nextHopType""VirtualAppliance",
        "nextHopIpAddress""10.0.0.4"
      }
    },
    {
      "name""route2",
      "properties": {
        "addressPrefix""10.10.0.0/24",
        "nextHopType""VirtualAppliance",
        "nextHopIpAddress""10.10.0.68"
      }
    }
  ]
 
Your example is almost correct, you have some square brackets [] in the wrong place. 
 

@StefanIvemo 

 

Hi Stefan,

 

It is working good, But it is mandate to create RouteTable and Routes every time while using this script>

Is it possible to give options that Routes and Route Tables needs to create only when needed.

If i give null value or does not give Route and Route Tables along with NSG it is not creating.

Can you please help me on this.

 

Regards,

Vignesh

Why do you want to avoid creating route tables and routes every time?

@michaelelleby123 

 

Hi,

 

I do not need Route Table and Routes created at every time, I only needed to create when i needs.

But here it is mandate to create everytime which i do not need.

 

Regards,
Vignesh

@michaelelleby123

 

Basically I will be using this template to run via Azure DevOps pipeline. Meaning it will run most of the time as pipeline task.

With this NSG template I need to associate the routes rather than create, consider this scenario if there are two nsgs i need to create one needs routes and other doesnt needs association in that case i cannot skip the route parameter for 1 nsg

It was ok if all the NSG would have routes as mandate which is ok to create everytime as you said but not all NSG will have routes.

Other options is to have a separate route(multiple) template and parameter file - can you pls. help me that?

@StefanIvemo

 

Basically I will be using this template to run via Azure DevOps pipeline. Meaning it will run most of the time as pipeline task.

With this NSG template I need to associate the routes rather than create, consider this scenario if there are two nsgs i need to create one needs routes and other doesnt needs association in that case i cannot skip the route parameter for 1 nsg

It was ok if all the NSG would have routes as mandate which is ok to create everytime as you said but not all NSG will have routes.

Other options is to have a separate route(multiple) template and parameter file - can you pls. help me that?

@vigneshkrcegmailcom 

In my opinion a subnet should always be created with a route table and NSG. If you don't need any custom routes just edit the parameter file and set the following properties for the subnets where you don't need any custom routing. With no routes and disableBgpRoutePropagation set to false the subnet will use the default routing in Azure even with a route table associated to the subnet.

"disableBgpRoutePropagation": false,
"routes": []

 

If/when the time comes to add a custom route to the subnet, the route table is there and you can just inject the routes to it. 

 

@StefanIvemo 

 

Hi Stefan,

 

Yes, From the Below point i can understand that Route table will create and creating Routes is our wish. But i do not need to create "Route Table" every time when i am running the script.

 

Example:

 

I tried to run the script below. In that i have removed "RouteName" and for routes i have given [], But without "RouteName" the script is not running. So i need to run the script without Route Table creation. Only i need to give Route Name when i need Route Table. Is that possible. Pls help me !!!

 

Below I have removed RouteName but it is throwing error. I need to run without Creating RouteTable

 

{
"properties": {
"NSGName": "NSG03",
"SubnetName": "sub03",

"RouteName": "I Do not need this property"
"securityRules": [
{
"name": "Inbound_Allow_Http",
"properties": {
"description": "Allow inbound http traffic",
"protocol": "TCP",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationPortRange": "80",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 4096,
"direction": "Inbound"
}
}
],
"disableBgpRoutePropagation": false,
"routes": []

}
]
}
}
]
}
}
}

@StefanIvemo 

 

Hi Stefan,

 

Any update on this please, The point is we don't need to create Route tables while running the script. If we need Route table we will add Route Property in parameter files. But while doing with this script it is throwing error. I am not sure how to modify Template file accordingly !!!

 

Vignesh

@StefanIvemo 

 

Hi Stefan,

 

Any update on this please, The point is we don't need to create Route tables while running the script. If we need Route table we will add Route Property in parameter files. But while doing with this script it is throwing error. I am not sure how to modify Template file accordingly !!!

 

Vignesh

@StefanIvemo 

Hi Stefan,

 

 The main aim is we don't need to create Route tables while running the script. If we need Route table we will add Route Property in parameter files. But while doing with this script it is throwing error. I am not sure how to modify Template file accordingly !!!

 

For example if i am running this script now I need to give names of NSG and Route tables as Mandate. If i will not give the route name it is throwing error. So i need to change this, while creating NSG's if needed i need to create Route table or else i will not give the names of Route Table Name as input.

 

Below is the para i have modified. In first property i am creating 1 NSG and 1 Route and in second property i need only NSG, so i am not giving Route Table Name. But this is not working as it is throwing template error.

 

"SubnetInfo": {
"value": [
{
"properties": {
"NSGName": "NSG01",
"SubnetName": "sub01",
"RouteName": "RT01",
"securityRules": [
{
"name": "Inbound_Deny_All",
"properties": {
"description": "Deny all inbound traffic",
"protocol": "*",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationPortRange": "*",
"destinationAddressPrefix": "*",
"access": "Deny",
"priority": 4096,
"direction": "Inbound"
}
}
],
"disableBgpRoutePropagation": true,
"routes": [
{
"name": "route1",
"properties": {
"addressPrefix": "10.0.0.0/24",
"nextHopType": "VirtualAppliance",
"nextHopIpAddress": "10.0.0.4"
}
}
}
]
}
},
{
"properties": {
"NSGName": "NSG02",
"SubnetName": "sub02",
"securityRules": [
{
"name": "Outbound_Deny_All",
"properties": {
"description": "Deny all inbound traffic",
"protocol": "*",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationPortRange": "*",
"destinationAddressPrefix": "*",
"access": "Deny",
"priority": 4096,
"direction": "Outbound"
}
}
],

}
]
}
}

 

Vignesh

Hi @vigneshkrcegmailcom !

 

I've updated the template I've shared before with some additional functionality to be able to achieve the task. 


Now if you leave the RouteName property empty in a subnet object in the parameters file no route table will be created for that subnet.

 

The following changes have been made:

 

  •  I've added a condition to the route table resource to define that a route table should only be created if RouteName is provided.
"condition": "[not(empty(parameters('SubnetInfo')[copyIndex()].properties.RouteName))]"
  • I've added a variable iteration called routetableid, to use in the nested deployment where the subnet is created, this is used to build an array with resourceIDs.
"variables": {
        "copy": [
            {
                "name": "routetableid",
                "count": "[length(parameters('SubnetInfo'))]",
                "input": {
                    "id": "[if(empty(parameters('SubnetInfo')[copyIndex('routetableid')].properties.RouteName),'fakeid',resourceId('Microsoft.Network/routeTables', parameters('SubnetInfo')[copyIndex('routetableid')].properties.RouteName))]"
                }
            }
        ]
    }
  • And finally in the nested deployment where the route table is associated with the subnet I've added this if statement to the routeTable property. If a routeName is present the resourceID will be provided from the variable iteration routetableid if not json('null') will be inserted.
"routeTable": "[if(empty(parameters('SubnetInfo')[copyIndex()].properties.RouteName), json('null') ,variables('routetableid')[copyIndex()])]"

 

https://gist.github.com/StefanIvemo/d9fecb77d9089bd282638aa52a2fffb2

 

 

Good luck with your deployment!