Minimum Viable Template: Add a Network Security Group

This post is part of a series of posts showing how to create a “minimum viable ARM template” and how to modify it to suit various scenarios. To see the full list of posts in this series, see this page: https://negatblog.wordpress.com/minimum-viable-arm-templates/.

For added security, we want to lock down our minimum viable VM to limit public network traffic. We will do this by adding a network security group to our template. We start from the “minimum-viable-vm” branch (https://github.com/gatneil/MinimumViableArmTemplate/blob/minimum-viable-vm/azuredeploy.json) and end at the “vm-with-nsg” branch (https://github.com/gatneil/MinimumViableArmTemplate/blob/vm-with-nsg/azuredeploy.json). Below is the diff.

We can see that we have added a new resource of type “Microsoft.Network/networkSecurityGroups”. This resource only requires one property, which is a list of security rules. In this case, we specify only one security rule, which allows inbound TCP traffic on port 22 from any source address (“*” means “any”) and from any source port to any destination address. This is still a fairly lenient rule (for instance, instead of allowing any source, we may want to restrict to traffic originating from our data centers), but it is a fine rule for demo purposes. Note that we specify “priority”: 1000. The priority allows us to specify which rules take precedence over others. Note that lower numbers means higher priority. For instance, if we have a rule at priority 1 that allows ssh traffic and a rule at priority 2 that denies ssh traffic, the priority 1 rule will win. Also note that Azure has some “default” rules for security groups that get applied even without us specifying them. At a high level, these rules allow local traffic within the VNet and allow outward connections from the VNet but disallow inward connections into the VNet (for more details, see this document: https://docs.microsoft.com/azure/virtual-network/network-security-groups-overview#default-security-rules):

...
+    {
+      "type": "Microsoft.Network/networkSecurityGroups",
+      "apiVersion": "2020-06-01",
+      "name": "myNsg",
+      "location": "[resourceGroup().location]",
+      "properties": {
+        "securityRules": [
+          {
+            "name": "SSH",
+            "properties": {
+              "priority": 1000,
+              "protocol": "TCP",
+              "access": "Allow",
+              "direction": "Inbound",
+              "sourceAddressPrefix": "*",
+              "sourcePortRange": "*",
+              "destinationAddressPrefix": "*",
+              "destinationPortRange": "22"
+            }
+          }
+        ]
+      }
+    },

...

Once we’ve added the network security group to the template, we need to tell the network interface to actually use it. To do this, we add the network security group to the “dependsOn” for the network interface (so the network interface will wait for the network security group to complete before being created) and specify networkSecurityGroup.id in the IP Configuration for the network interface:

...
     {
       "type": "Microsoft.Network/networkInterfaces",
       "apiVersion": "2020-06-01",
       "name": "myNic",
       "location": "[resourceGroup().location]",
       "dependsOn": [
         "[resourceId('Microsoft.Network/virtualNetworks/', 'myVnet')]",

-        "[resourceId('Microsoft.Network/publicIpAddresses/', 'myPip')]"
+        "[resourceId('Microsoft.Network/publicIpAddresses/', 'myPip')]",
+        "[resourceId('Microsoft.Network/networkSecurityGroups/', 'myNsg')]"

       ],
       "properties": {
         "ipConfigurations": [
           {
             "name": "myIpConfig",
             "properties": {
               "subnet": {
                 "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'myVnet', 'mySubnet')]"
               },
               "publicIpAddress": {
                 "id": "[resourceId('Microsoft.Network/publicIPAddresses', 'myPip')]"
               }
             }
           }

-        ]
+        ],
+        "networkSecurityGroup": {
+          "id": "[resourceId('Microsoft.Network/networkSecurityGroups', 'myNsg')]"
+        }

       }
     },
...

Leave a comment