Simplify Azure NSG Rules With Augmented Rules and Service Tags

Historically Azure Network Security Groups (NSG’s) have only allowed you to enter a single value for things things like source or destination IP and source or destination port. This has meant that for complex setups you end up with a very large amount of NSG’s. This is especially if you are trying to filter a large amount of IP’s, for example the Azure Data Center IP ranges, which is a common requirement if you want to restrict outbound access but allow access to PaaS resources.

At Ignite last year MS announced the concept of augmented NSG rules which would allow you to provide multiple values in a single NSG, which should help simplify complex NSG setups. This feature has now hit general availiblity and is available in all regions. At the same time MS also added some additional “service tags” to the NSG spec to allow for filtering of traffic for Azure PaaS resources.

In the rest of this article we are going to take a look at how you can create these augmented rules using ARM templates and utilizing the new service tags. It’s also possible to use the portal, PowerShell and cmd line to create these NSG rules but we won’t cover that in this article.

Creating Augmented Rules

It’s not initially very clear on how you create augemented rules, if you just try and add multiple values to the the existing ARM template for NSG it will not work. Instead we need to tweak the NSG declaration. Here is a simple NSG rule in the existing format that we will work to update:

{
    "apiVersion": "2017-06-01",
    "type": "Microsoft.Network/networkSecurityGroups",
    "name": "networkSecurityGroupName",
    "location": "[resourceGroup().location]",
    "properties": {
        "securityRules": [
            {
                "name": "Allow-RDP",
                "properties": {
                    "description": "Allow RDP Traffic",
                    "protocol": "*",
                    "sourcePortRange": "*",
                    "destinationPortRange": "3389",
                    "sourceAddressPrefix": "*",
                    "destinationAddressPrefix": "10.20.30.10/32",
                    "access": "Allow",
                    "priority": 299,
                    "direction": "Inbound"
                }
            }
        ]
    }
}

The first thing we need to do is update the API version, to use Augmented rules you need to use at lest the 207-10-01 api version.

apiVersion": "2017-10-01",

The next step is to update the property names, to use Augmented Rules you need to update these to use the plural versions:

  • sourcePortRange becomes sourcePortRanges
  • destinationPortRange becomes destinationPortRanges
  • sourceAddressPrefix becomes sourceAddressPrefixes
  • destinationAddressPrefix becomes destinationAddressPrefixes

You can mix and match between singular and plurals depending on your need. In our example we are going to use the plural version for destination port ranges and source prefix

"sourcePortRange": "*",
"destinationPortRanges": "3389",
"sourceAddressPrefix": "*",
"destinationAddressPrefixes": "10.20.30.10/32",

Now we have the properties updated we need to update the values to actually provide multiple entries. These need to be supplied as an array, either of single values or ranges. So in this example we are going to allow access to two IP addresses, and on the destination ports we will supply both a single value and a range. Here’s the full version with these new rules.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {},
    "resources": [
        {
            "apiVersion": "2017-10-01",
            "type": "Microsoft.Network/networkSecurityGroups",
            "name": "networkSecurityGroup1",
            "location": "[resourceGroup().location]",
            "properties": {
                "securityRules": [
                    {
                        "name": "Allow-RDP",
                        "properties": {
                            "description": "Allow RDP Traffic",
                            "protocol": "*",
                            "sourcePortRange": "*",
                            "destinationPortRanges": [
                                "3389-3390",
                                "443"
                            ],
                            "sourceAddressPrefix": "*",
                            "destinationAddressPrefixes": [
                                "10.20.30.10/32",
                                "10.20.30.20/32"
                            ],
                            "access": "Allow",
                            "priority": 299,
                            "direction": "Inbound"
                        }
                    }
                ]
            }
        }
    ],
    "outputs": {}
}

You can see here we are still using the singular version for sourcePortRange and sourceAddressPrefix as we don’t need the augmented version here.

Augmented rules do have some limitations, if you want to mix the protocol in use and have a mix of TCP and UDP you will still need to have multiple rules.

Service Tags

Additional service tags have been added to allow for filtering of specific Azure PaaS data, in the initial release this is for Storage and SQL data. What this will allow you to do is to create an NSG rule that allows, or denies, communication with Azure storage or SQL using a single tag, rather than having to try and list all of the Azure data center IP ranges (which is nearly impossible these days). These are in addition to the existing tags that have been available for some time for Internet, Virtual Network, Load Balancer and Traffic Manager.

To use a tag all you need to do is replace either the source or destination address prefix with the tag. For the new Azure storage and SQL tags this is most likely going to be an outbound rule, so you would use the destination prefix like below:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {},
    "resources": [
        {
            "apiVersion": "2017-10-01",
            "type": "Microsoft.Network/networkSecurityGroups",
            "name": "networkSecurityGroup1",
            "location": "[resourceGroup().location]",
            "properties": {
                "securityRules": [
                    {
                        "name": "Allow-SQL",
                        "properties": {
                            "description": "Allow SQL Traffic",
                            "protocol": "*",
                            "sourcePortRange": "*",
                            "destinationPortRange": "*",
                            "sourceAddressPrefix": "*",
                            "destinationAddressPrefix": "Sql",
                            "access": "Allow",
                            "priority": 299,
                            "direction": "Outbound"
                        }
                    }
                ]
            }
        }
    ],
    "outputs": {}
}

Unfortunately it does seem that at the moment we can’t use augmented rules with service tags, so we can’t allow SQL and Storage in the same rule.

Further Reading

Augmented Security Rules – https://docs.microsoft.com/en-us/azure/virtual-network/security-overview#augmented-security-rules

Service Tags – https://docs.microsoft.com/en-us/azure/virtual-network/security-overview#service-tags