Define Azure network security groups (NSGs) and attach to Vnets

This is the last post in a series on Azure virtual networks and how to define them in Azure Resource Manager (ARM) templates.

Prior posts discussed how to create Vnets, peer Azure virtual networks and subnets and how to create user-defined routes (UDRs) for Azure Vnets. There were a couple of interesting (and I hope useful) detours in this series. The first compared the relative ease of using PowerShell to create Vnets in multiple subscriptions to the complexity of doing it in ARM templates. The second detour is a bit of a rant: I discuss the five resource group limitation in a single ARM template deployment.

This post, which is the conclusion of the series, offers a sample ARM template for creating network security groups. Taken together, these posts should provide enough samples for you to build a fairly sophisticated (and secure) Azure virtual network infrastructure.

Here are some notes on the template and parameter files included below:

  • As with all the other examples in this series, the NSG sample is designed to permit definition of NSGs in different Azure subscriptions. That means you are limited to five resource groups in a single deployment of the template so make sure to break up your input parameter files with this in mind. Due to the way I like to deploy the template, using PowerShell, one of the five resource groups is “used up” by specifying it on the command line. I actually like this because that “dummy” resource group then contains the deployment results.
  • Also like the other examples, this template uses a nested template. This is the only way one can “switch” subscriptions in an Azure template. That is done by creating a resource called Microsoft.Resources/deployments one of whose properties is template:. Used with copy (whose count is determined by the number of items in the input parameter array), you can specify a different subscriptionID:s for each copied element. The child resources in the nested template then execute against the current subscription specified in the parameter file.
  • Note that the properties of the NSG are in an array in the parameter file. Those properties, whose names are the same as the Microsoft definitions, are themselves contained in an array of subnets which are to have the NSG applied to them. The outer array (subnets) corresponds to the outer resource’s copy: parameter; the inner array in each subnet corresponds to the NSG rules to be applied to the subnet. copy: is used in the child resource Microsoft.Network/networkSecurityGroups so that all rules specified in the array are applied to each subnet.
  • The sample parameters provided here describe four subnets, two that permit inbound SQL Server traffic on TCP 1433 and two that permit Oracle traffic on TCP 1521. Clearly, these are Vnet-only, back-end subnets that are not to ever to be exposed to a public IP address via a route.
  • All parameters shown in the example are required by the template.

Here’s the template file, followed by the parameter file. Both are (c) 2018 Air11 Technology LLC and are licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "ParameterArray": {
            "type": "array"
        }
    },
    "variables": {},
    "resources": [
        {
            "apiVersion": "2017-05-10",
            "type": "Microsoft.Resources/deployments",
            "name": "[concat('Deploy-Nsg-',parameters('ParameterArray')[copyIndex('Nsgs')].name)]",
            "subscriptionId": "[parameters('ParameterArray')[copyIndex('Nsgs')].SubscriptionId]",
            "resourceGroup": "[parameters('ParameterArray')[copyIndex('Nsgs')].ResourceGroupName]",
            "copy": {
                "name": "Nsgs",
                "count": "[length(parameters('ParameterArray'))]"
            },
            "properties": {
                "mode": "Incremental",
                "template": {
                    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
                    "contentVersion": "1.0.0.0",
                    "variables": {},
                    "resources": [
                        {
                            "apiVersion": "2017-10-01",
                            "type": "Microsoft.Network/networkSecurityGroups",
                            "name": "[concat('Nsg-',parameters('ParameterArray')[copyIndex('Nsgs')].name)]",
                            "location": "[parameters('ParameterArray')[copyIndex('Nsgs')].Region]",
                            "properties": {
                                "copy": [
                                    {
                                        "name": "securityRules",
                                        "count": "[length(parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules)]",
                                        "input": {
                                            "name": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].name]",
                                            "properties": {
                                                "protocol": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].protocol]",
                                                "sourcePortRange": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].sourcePortRange]",
                                                "destinationPortRange": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].destinationPortRange]",
                                                "access": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].access]",
                                                "sourceAddressPrefix": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].sourceAddressPrefix]",
                                                "destinationAddressPrefix": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].destinationAddressPrefix]",
                                                "direction": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].direction]",
                                                "priority": "[parameters('ParameterArray')[copyIndex('Nsgs')].SecurityRules[copyIndex('securityRules')].priority]"
                                            }
                                        }
                                    }
                                ]
                            }
                        },
                        {
                            "apiVersion": "2018-03-01",
                            "type": "Microsoft.Network/virtualNetworks/subnets",
                            "name": "[concat(parameters('ParameterArray')[copyIndex('Nsgs')].VnetName, '/', parameters('ParameterArray')[copyIndex('Nsgs')].name)]",
                            "location": "[parameters('ParameterArray')[copyIndex('Nsgs')].Region]",
                            "dependsOn": [
                                "[concat('Nsg-',parameters('ParameterArray')[copyIndex('Nsgs')].name)]"
                            ],
                            "properties": {
                                "addressPrefix": "[parameters('ParameterArray')[copyIndex('Nsgs')].addressPrefix]",
                                "networkSecurityGroup": {
                                    "id": "[resourceId(parameters('ParameterArray')[copyIndex('Nsgs')].SubscriptionId,parameters('ParameterArray')[copyIndex('Nsgs')].ResourceGroupName,'Microsoft.Network/networkSecurityGroups',concat('Nsg-',parameters('ParameterArray')[copyIndex('Nsgs')].name))]"
                                }
                            }
                        }
                    ]
                }
            }
        }
    ],
    "outputs": {}
}
{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "0.0.0.1",
    "parameters": {
        "ParameterArray": {
            "value": [
                {
                    "name": "Subnet-10-120-24-0-26-SQL-Server-1",
                    "addressPrefix": "10.120.24.0/26",
                    "VnetName": "VnetSharedDatabasesDev",
                    "ResourceGroupName": "RgSharedDatabasesDev",
                    "SubscriptionId": "87654321-0000-FFFF-940f-0123456789ABC",
                    "Region": "eastus2",
                    "SecurityRules": [
                        {
                            "name": "AllowAllInboundSQLServer",
                            "protocol": "Tcp",
                            "sourcePortRange": "*",
                            "sourceAddressPrefix": "10.120.8.0/26",
                            "destinationAddressPrefix": "*",
                            "destinationPortRange": "1433",
                            "access": "Allow",
                            "direction": "Inbound",
                            "priority": "100"
                        }
                    ]
                },
                {
                    "name": "Subnet-10-120-24-64-26-SQL-Server-2",
                    "addressPrefix": "10.120.24.64/26",
                    "VnetName": "VnetSharedDatabasesDev",
                    "ResourceGroupName": "RgSharedDatabasesDev",
                    "SubscriptionId": "87654321-0000-FFFF-940f-0123456789ABC",
                    "Region": "eastus2",
                    "SecurityRules": [
                        {
                            "name": "AllowAllInboundSQLServer",
                            "protocol": "Tcp",
                            "sourcePortRange": "*",
                            "sourceAddressPrefix": "10.120.8.0/26",
                            "destinationAddressPrefix": "*",
                            "destinationPortRange": "1433",
                            "access": "Allow",
                            "direction": "Inbound",
                            "priority": "100"
                        }
                    ]
                },
                {
                    "name": "Subnet-10-120-24-128-26-Oracle-1",
                    "addressPrefix": "10.120.24.128/26",
                    "VnetName": "VnetSharedDatabasesDev",
                    "ResourceGroupName": "RgSharedDatabasesDev",
                    "SubscriptionId": "87654321-0000-FFFF-940f-0123456789ABC",
                    "Region": "eastus2",
                    "SecurityRules": [
                        {
                            "name": "AllowAllInboundOracle",
                            "protocol": "Tcp",
                            "sourcePortRange": "*",
                            "sourceAddressPrefix": "10.120.8.0/26",
                            "destinationAddressPrefix": "*",
                            "destinationPortRange": "1521",
                            "access": "Allow",
                            "direction": "Inbound",
                            "priority": "100"
                        }
                    ]
                },
                {
                    "name": "Subnet-10-120-24-192-26-Oracle-2",
                    "addressPrefix": "10.120.24.192/26",
                    "VnetName": "VnetSharedDatabasesDev",
                    "ResourceGroupName": "RgSharedDatabasesDev",
                    "SubscriptionId": "87654321-0000-4d2b-940f-0123456789ABC",
                    "Region": "eastus2",
                    "SecurityRules": [
                        {
                            "name": "AllowAllInboundOracle",
                            "protocol": "Tcp",
                            "sourcePortRange": "*",
                            "sourceAddressPrefix": "10.120.8.0/26",
                            "destinationAddressPrefix": "*",
                            "destinationPortRange": "1521",
                            "access": "Allow",
                            "direction": "Inbound",
                            "priority": "100"
                        }
                    ]
                }
            ]
        }
    }
}

 


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *