If you work with firewalls, proxies, or any system that restricts traffic based on IP addresses, you’re likely familiar with the challenges of maintaining access to dynamic cloud infrastructure. Microsoft understands this, which is why they publish the Azure IP Ranges and Service Tags – Public Cloud dataset — a JSON file containing up-to-date IP address ranges used by Azure services.
Table of Contents
Why Microsoft Publishes Azure IP Ranges
Microsoft Azure’s cloud infrastructure spans global data centers, with thousands of services running behind constantly shifting sets of IP addresses. To help organizations:
- Configure firewalls and security appliances
- Whitelist Azure service IPs
- Meet compliance or policy needs
- Route traffic appropriately
…Microsoft provides this public JSON file that includes IP ranges tied to Service Tags like Storage
, Sql
, AppService
, and many others, broken down by region.
If you are using Azure Firewall, then you can use these service tags directly in your firewall rules. More information can be found here. 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.
How Often Is the Data Updated?
Microsoft typically updates the Azure IP Ranges and Service Tags – Public Cloud file weekly, usually every Monday. Updates can reflect:
- New IPs added for expanding infrastructure
- Old ranges removed or reallocated
- Changes to service or region mappings
Each release includes a "changeNumber"
field and a "version"
field to help you detect updates. Automation is key here — hence the script!
Changes, Changes…
Azure public IP addresses can change weekly! What does that mean for us?
Every week, there may be new IP addresses added to the list. Others may be removed if they’re no longer in use by Azure.
Why does that matter?
Let’s say an on-prem application needs access to an AzureSQL database, you previously added its IPs to your firewall allow-list. Then Azure updates its IP ranges, and the on-prem application keeps using the same IP or IP ranges that’s not in your allow-list. Boom — access denied. Not because you intended to block it, but because you didn’t know about the change.
It’s not just about adding the new IPs. You also need to handle removals to prevent your allow-lists from becoming bloated and insecure.
This isn’t a new problem in networking. But in Azure, the pace of change is faster — often weekly — and automation becomes essential.
How Is the JSON File Structured?
The JSON file is well-organized and structured to support automation. Here’s what it generally looks like:
jsonCopyEdit{
"changeNumber": 20250401,
"cloud": "Public",
"values": [
{
"name": "AppService.WestUS",
"id": "AppService.WestUS",
"properties": {
"region": "westus",
"platform": "Azure",
"systemService": "AppService",
"addressPrefixes": [
"13.64.0.0/18",
"40.112.0.0/16"
]
}
},
...
]
}
Key fields:
values
: Array of service tag entriesname
/id
: Service and regionproperties.addressPrefixes
: List of IP ranges (in CIDR format)
You can easily filter entries by region, service tag, or even specific prefixes depending on your needs.
Common Use Cases for Downloading Azure IPs
There are many real-world situations where access to this list is helpful:
- Firewall Whitelisting: Allow only Azure
Storage
orSql
service traffic from a specific region. - Cloud Egress Policies: Identify what your workloads are connecting to by cross-referencing logs with Azure-owned IPs.
- Network Audits & Compliance: Ensure your infrastructure is only communicating with approved external services.
- CDN or WAF Configurations: Enable access to Azure Front Door, App Service, or other endpoints behind the scenes.
- Automation Pipelines: Pull the list programmatically during CI/CD to dynamically configure network security settings.
PowerShell Script to Download the File
To help automate this process, I wrote a PowerShell script that downloads the latest Azure IP Ranges JSON file:
What this script does,
- Fetches the HTML content of the page https://www.microsoft.com/en-us/download/details.aspx?id=56519 using Invoke-WebRequest.
- Extracts the JSON file URL from the page content using a regex match.
- Creates a folder named json_files if it does not already exist.
- Extracts the JSON file name from the URL and constructs the file path within the json_files folder.
- Checks if the JSON file already exists:
- If it exists, skips the download.
- If it does not exist, downloads the JSON file to the json_files folder.
- Parses the downloaded JSON file into a PowerShell object using ConvertFrom-Json.
- Creates a timestamped folder named AzureServicetags_<timestamp> in the directory called ‘AzureServicetags’ in the current directory.
- Creates three subfolders within the timestamped folder:
- All_IPs for all IP addresses.
- IPv4_IPs for IPv4 addresses.
- IPv6_IPs for IPv6 addresses.
- Iterates through each service tag in the JSON content:
- Extracts the service name and its associated IP address prefixes.
- Separates the IP addresses into IPv4 and IPv6 categories using regex matching.
- Creates text files for:
- All IP addresses.
- IPv4 addresses.
- IPv6 addresses.
- Writes the respective IP addresses into the corresponding text files.
- Outputs a message indicating the creation of files for each service.
- Skips services that do not have valid address prefixes and outputs a warning message.
- Outputs a message if the JSON URL is not found.
# Define the URL of the download page
$pageUrl = "https://www.microsoft.com/en-us/download/details.aspx?id=56519"
# Fetch the page source
$response = Invoke-WebRequest -Uri $pageUrl -UseBasicParsing
# Extract the JSON URL for 'url'
$jsonUrl = ($response.Content -match '"url":"(https://download\.microsoft\.com/download/[^"]+)"') | Out-Null
$jsonUrl = $matches[1]
# Output the JSON URL
if ($jsonUrl) {
Write-Output "JSON URL: $jsonUrl"
# Create the folder 'json_files' if it doesn't exist
$jsonFolder = "json_files"
if (-not (Test-Path -Path $jsonFolder)) {
New-Item -ItemType Directory -Path $jsonFolder | Out-Null
}
# Extract the file name from the JSON URL
$jsonFileName = $jsonUrl.Split("/")[-1]
$jsonFilePath = Join-Path -Path $jsonFolder -ChildPath $jsonFileName
# Check if the JSON file already exists
if (Test-Path -Path $jsonFilePath) {
Write-Output "File '$jsonFileName' already exists. Skipping download."
}
else {
# Download the JSON file into the 'json_files' folder
Invoke-WebRequest -Uri $jsonUrl -OutFile $jsonFilePath
Write-Output "Downloaded JSON file: $jsonFileName"
}
# Parse the JSON file
$jsonContent = Get-Content -Path $jsonFilePath -Raw | ConvertFrom-Json
# Create a folder with the current date and time stamp
$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm"
$folderName = ".\AzureServicetags\AzureServicetags_$timestamp"
New-Item -ItemType Directory -Path $folderName | Out-Null
# Create subfolders for All_IPs, IPv4_IPs, and IPv6_IPs
$allIPsFolder = Join-Path -Path $folderName -ChildPath "All_IPs"
$ipv4Folder = Join-Path -Path $folderName -ChildPath "IPv4_IPs"
$ipv6Folder = Join-Path -Path $folderName -ChildPath "IPv6_IPs"
foreach ($subFolder in @($allIPsFolder, $ipv4Folder, $ipv6Folder)) {
if (-not (Test-Path -Path $subFolder)) {
New-Item -ItemType Directory -Path $subFolder | Out-Null
}
}
# Iterate through each service tag and create text files
foreach ($service in $jsonContent.values) {
$serviceName = $service.name
if ($service -and $service.properties -and $service.properties.addressPrefixes) {
$ipAddresses = $service.properties.addressPrefixes
$ipv4Addresses = $ipAddresses | Where-Object { $_ -match '\.' -and $_ -notmatch '\:' }
$ipv6Addresses = $ipAddresses | Where-Object { $_ -match '\:' }
# Create files for all IPs, IPv4 IPs, and IPv6 IPs
$allIPsFilePath = Join-Path -Path $allIPsFolder -ChildPath "$serviceName`_all_IPs.txt"
$ipv4FilePath = Join-Path -Path $ipv4Folder -ChildPath "$serviceName`_v4_IPs.txt"
$ipv6FilePath = Join-Path -Path $ipv6Folder -ChildPath "$serviceName`_v6_IPs.txt"
$ipAddresses | Out-File -FilePath $allIPsFilePath -Encoding UTF8
$ipv4Addresses | Out-File -FilePath $ipv4FilePath -Encoding UTF8
$ipv6Addresses | Out-File -FilePath $ipv6FilePath -Encoding UTF8
Write-Output "Created files for service: $serviceName"
}
else {
Write-Warning "Service '$serviceName' does not have valid address prefixes. Skipping."
}
}
}
else {
Write-Output "JSON URL not found."
}
Thanks for stopping by. ✌