Blocking Internet Access for Azure VMs

Hard drive dominoes
This post will answer a question that I always get when I am teaching the subject of network security groups, “How do I block Internet access for my Azure virtual machines?”


Blocking Internet Access

Every Azure virtual machine has direct connectivity to the Internet via a NAT IP address by default and that access is unfiltered.
Tip: That NAT IP address is the public IP address of the load balancer or NIC if the virtual machine is assigned to either one. You can use this for creating firewall rules to allow inbound access at remote sites for your Azure virtual machines.
Some organizations do not like any machine having such access. For example:

  • All access should be blocked, no matter what.
  • Internet traffic should be routed via on-premises (see an Azure solution called Forced Tunnelling, using user-defined routing).
  • Internet traffic should be controlled.

One reason might be to stop malware from activating after it reaches out to a controller on the Internet. Another reason is to stop data leakage.
One can use a number of solutions for accomplishing the above but in this post, I will show you how to do this using Network Security Groups.

Be Careful What You Ask For

The demand to “block all outbound traffic” is easily accomplished using Azure’s Layer-4 (TCP/UDP/etc) solution, Network Security Groups (NSGs). You create a single outbound rule to Deny traffic to the service tag (or location) of Internet.

This Azure NSG outbound ruleset is harmful to your employment status [Image Credit: Aidan Finn]
This Azure NSG Outbound Ruleset Is Harmful to Your Employment Status [Image Credit: Aidan Finn]
Within a month or two, you should get a call from your boss/client, not to thank you, but to demand to know why their virtual machine-based services are no longer available to users/customers. You’ll scratch your head, log into the Azure Portal and find that your virtual machines cannot boot up.

When you create a virtual machine in Azure, you probably take the wise step of doing things like enabling Diagnostics or Boot Diagnostics. Both of these troubleshooting features leverage a storage account:

  • Diagnostics: At the very least, performance metrics are written as Table data.
  • Boot Diagnostics: Stores a BMP screenshot of the virtual machine’s console as a blob.

When a virtual machine with either of these services enabled boots up, the virtual machine must have access to the storage account. And here’s the gotcha: The Internet tag included all IP ranges of the Azure services because it was neither a Load Balancer probe or the Virtual Network (the other two service tags or locations that were available). Without that access, the virtual machine would not boot up.
Note: Boot Diagnostics now includes a new text-based serial output full of useful information for Windows Server virtual machines.

The Old Workaround

What if you needed to block outbound traffic to the Internet but needed a solution to allow your virtual machines to boot up? Sadly, this was complicated. You would have to download the frequently updated list of IP addresses/ranges that are used by Azure and create exceptions to allow traffic to the Azure services.
This was cumbersome, fragile, probably didn’t scale well, and a nightmare to troubleshoot, not to mention that whatever script solution you came up with would have to be scheduled to run on a frequent basis. The kinds of organization that require outbound traffic to be controlled are probably the same organizations with strict change control rules, such as pharmaceuticals, and I cannot imagine what the bureaucracy around this would be been like.

Service Tags General Availability

Microsoft announced at Ignite that the location/Service Tag feature of NSGs would be updated to solve this problem. In January, Microsoft made those changes generally available. The old service tags still exist:

  • Load Balancer: Any probes in the Azure load balancer.
  • Virtual Network: The virtual network that the virtual machine is connected to.
  • Internet: Everything outside of the virtual machine’s virtual network, including all of Azure’s other services.

The following service tags were added along with the GA announcement:

  • Azure Storage: The IP address ranges of all Azure storage clusters (storage accounts)
  • Regional Azure Storage: Used to restrict access to Azure storage clusters in a specific region.
  • Regional Azure SQL: Used to control access to Azure SQL database and warehouse services in a specific region.

A Viable Solution

The new service tags for Azure services are dynamically updated by Microsoft. For example, if Microsoft adds new service fabrics for hosting Azure SQL in East US, the IP addresses used to access those services will be added to the SQL.EastUS service tag by Microsoft. I don’t have to change anything; I continue to use the same service tag. That means that:

  • I don’t need to script anything to download IP address ranges from Microsoft.
  • I simply allow access to Azure SQL or Azure storage.
  • If Microsoft makes changes, I don’t have to do anything and therefore, I don’t have to do change control, update documentation, or worry that my virtual machines will stop working.

How can we use service tags to block outbound traffic to the Internet for our virtual machines now? It’s easy.
First, you will create the Deny-to-Internet rule:

  • Source: Virtual Network
  • Source Port Range: *
  • Destination: Service Tag
  • Destination Service Tag: Internet
  • Protocol: Any
  • Action: Deny
  • Priority: 4096
  • Name: Deny-AllInternet

This Deny-AllInternet rule is set with the lowest possible user-defined priority, 4096. This leaves us plenty of capacity to create exception rules. The essential rule to create now is a higher-priority one that will allow access to Azure storage. You could allow access to all storage in all Azure regions but it would be better to restrict that access to the same region as the virtual machine, for example, Storage.EastUS. In my case, the virtual machine is running in West Europe (Amsterdam):

  • Source: Virtual Network
  • Source Port Range: *
  • Destination: Service Tag
  • Destination Service Tag: Storage.WestEurope
  • Protocol: Any
  • Action: Allow
  • Priority: 100
  • Name: Allow-StorageWestEurope

Now my virtual machine cannot talk to the Internet but it can talk to Azure Storage.
Note: I have seen a blog post that says this exception is required for Azure virtual machines to be protected by Azure Backup if Security Center’s Just In Time Virtual Machine Access is enabled.

Blocking Internet access for Azure virtual machines, but allowing Azure Storage access [Image Credit: Aidan Finn]
Blocking Internet Access for Azure Virtual Machines but Allowing Azure Storage Access [Image Credit: Aidan Finn]
What if the virtual machine also must talk to Azure SQL? In that case, we add another exception:

  • Source: Virtual Network
  • Source Port Range: *
  • Destination: Service Tag
  • Destination Service Tag: SQL.WestEurope
  • Protocol: Any
  • Action: Allow
  • Priority: 200
  • Name: Allow-SQLWestEurope

Blocking Internet access but enabling Azure service access for virtual machines [Image Credit: Aidan Finn]
Blocking Internet Access but Enabling Azure Service Access for Virtual Machines [Image Credit: Aidan Finn]

With these Service Tag-based rules, you can easily control access to the Internet while enabling Azure virtual machines to operate correctly with a minimum amount of effort or change.