Janne Mattila

From programmer to programmer -- Programming just for the fun of it

Using Azure IP Ranges and Service Tags JSON file

Posted on: January 22, 2024

Sometimes you need to restrict traffic from your network to only allowlisted Azure IP addresses or to allowed services.

Very simple example could be enabling Application Insights monitoring in an otherwise closed network. To achieve this, you need to know all the IP addresses used by Application Insights and enable traffic to those IP addresses in your firewalls. These individual service specific IP addresses are grouped together into IP address prefixes and those prefixes are then grouped together into Service tags. That page tells that AzureMonitor service tag contains all the IP prefixes for Application Insights.

If you are using Azure Firewall, then you can use these service tags directly in your firewall rules. More information can be found here.

Example Azure Firewall rule using AzureMonitor service tag:

You can use the same service tags also in Network Security Groups:

Service tags are also supported in User-defined routes:

If you are using some other firewall, then you need to check if they support service tags directly e.g., Palo Alto Networks & External Dynamic Lists (EDL).

If you don’t have support for service tags in your firewall, then you need to use IP address prefixes directly. This is not ideal, since you need to update your firewall rules every time when new IP address prefixes are added or removed. This is why automating this process is important.

Updates to Azure IP Ranges and Service Tags (Public Cloud) are published as JSON file. Important things to highlight from the download page:

This file is updated weekly.
New ranges appearing in the file will not be used in Azure for at least one week.
Please download the new json file every week and perform the necessary changes at your site to correctly identify services running in Azure

Okay let’s test this out. We’ll use Application Insights as an example.

First, let’s look at connection string from one of my Application Insights resources (line breaks added for readability):

InstrumentationKey=d4a1648a-2321-4cdf-b011-3e8444d41edc;
IngestionEndpoint=https://northeurope-2.in.applicationinsights.azure.com/;
LiveEndpoint=https://northeurope.livediagnostics.monitor.azure.com/

It contains two addresses referring to northeurope region since my resource is deployed there.

Let’s see what IP addresses are behind those addresses. We can use my tool for that:

The first address looks like this:

$ip = (Resolve-DnsName "northeurope-2.in.applicationinsights.azure.com").IP4Address
Get-AzureDatacenterIPOrNo -IP $ip | Format-Table

Output:

Region      Source                      IpRange         SystemService Ip
------      ------                      -------         ------------- --
            ServiceTags_Public_20231225 20.166.40.64/28 AzureMonitor  20.166.40.67
northeurope ServiceTags_Public_20231225 20.166.40.64/28 AzureMonitor  20.166.40.67
northeurope ServiceTags_Public_20231225 20.166.0.0/16                 20.166.40.67
            ServiceTags_Public_20231225 20.166.0.0/16                 20.166.40.67

Similarly, the second address looks like this:

$ip = (Resolve-DnsName "northeurope.livediagnostics.monitor.azure.com").IP4Address
Get-AzureDatacenterIPOrNo -IP $ip | Format-Table

Output:

Region      Source                      IpRange         SystemService Ip
------      ------                      -------         ------------- --
            ServiceTags_Public_20231225 20.50.68.128/29 AzureMonitor  20.50.68.128
northeurope ServiceTags_Public_20231225 20.50.68.128/29 AzureMonitor  20.50.68.128
northeurope ServiceTags_Public_20231225 20.50.64.0/20                 20.50.68.128
            ServiceTags_Public_20231225 20.50.64.0/20                 20.50.68.128

So, indeed those addresses are from AzureMonitor service tag in northeurope region. They are also part of the global AzureMonitor service tag but we’re going to focus on the region-specific service tags.

I’ve taken relevant pieces of the code from the above repository and put them into this script example. It downloads the JSON file and then picks up the relevant IP address prefixes based on the service tag name and region name.

Here’s the script:

# Update this name based on service and region
$name = "AzureMonitor.NorthEurope"

# Fetch the JSON file
$response = Invoke-WebRequest "https://www.microsoft.com/en-us/download/details.aspx?id=56519"
$fileStartIndex = $response.Content.IndexOf("ServiceTags_Public_")
$fileEndIndex = $response.Content.IndexOf(".json", $fileStartIndex)
$fileName = $response.Content.Substring($fileStartIndex, $fileEndIndex - $fileStartIndex)
$downloadLink = "https://download.microsoft.com/download/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/$fileName.json"
$data = Invoke-RestMethod $downloadLink

# Find all relevant IP addresses
$addresses = @()
foreach ($item in $data.values) {
  if ($item.name -eq $name) {
    foreach ($ip in $item.properties.addressPrefixes) {
      $addresses += $ip
    }
  }
}

# Print the results
$addresses

Example abbreviated output:

13.69.229.64/29
...
20.50.68.128/29
...
20.166.40.64/28

The previously mentioned addresses are on this list as expected.

Now you need to schedule this script to be executed regularly and update your firewall rules accordingly. Previously I’ve blogged about Automating maintenance tasks with Azure Functions and PowerShell, so that’s definitely one option to use for hosting this automation.

I hope you find this useful!