Blog Post

Core Infrastructure and Security Blog
3 MIN READ

How to Find Azure Resources with Public IP Addresses

wernerrall's avatar
wernerrall
Icon for Microsoft rankMicrosoft
Feb 14, 2022

 

Overview

Creating Resources in Azure is so simple for IT teams these days but finding all the public endpoints that could be visible to the internet can be challenging. Why do I need to understand which IP's are exposed to the internet? Without a proper understanding of which Public IPs are available to the internet we cannot fully secure or protect our resources. In this article we will look at using the Azure Native Graph Explorer solution to query not only Virtual Machine Public IP Addresses but other resources containing IP addresses in our Azure Tenant. 

 

The Method

 

Using Resource Graph Explorer we can see there is already a pre-built query called "List all public IP addresses". 

 

 

looking at the results we can see this supplies us with the public IP addresses from "Resources" that has a type that contains 'publicIPAddresses'. 

 

 

but what if a resource does not contain the type 'publicIPAddresses' ? Examples of resources could be Local Network Gateways, Virtual Network Gateways, Web Sites and many others.

That is where the power of Resource Graph Explorer comes in. We can use Regex to expand our queries to look through all properties of all resources and identify IP Addresses. 

 

The query to identify anything that looks like an IP could look like this:

 

 

 

 

resources
| where properties matches regex @'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'
|project  name, type, location, resourceGroup, subscriptionId, properties

 

 

 

 

and our results will look something like this:

 

This is a great start, we can search anything that looks like an IP address. But this means we are also including our private IP Ranges like 10.0.0.0

 

We can also streamline the Regex query by using two websites

1. IP Range Regular Expression Builder - AnalyticsMarket

 

This website allows you to build regex expressions by entering the required IP Addresses.

For this example I will use the range 100.0.0.0 - 255.255.255.255

 

 

2. regex101: build, test, and debug regex

 

This website analyzes your regex query and allows you to test it on a string. 

 

 

Now that we have our new range, we can make a small modification to our original Resource Graph Query.

 

 

 

 

resources
| where properties matches regex @'[12]\d\d(\.([1-9]?\d|[12]\d\d)){3}'
|project  name, type, location, resourceGroup, subscriptionId, properties

 

 

 

 

and it will return only IP Addresses in our chosen range from 

 

 

With this information now retrieved we need to ask the question, "Do we need publicly accessible endpoints for these resources?". If we do then we need to secure these resources according to the best practices in the Azure Security Benchmark, if we don't then they can be removed and replaced with items like Private Endpoints, Private Link, Azure Bastion... and others. 

I hope this query can help you further explore and secure Azure resources that have Public IP addresses. 

 

Take Note: Although this query provides more information by looking at every resource type that contains an IP Address in its Properties, some resources like Storage Accounts, Key Vaults etc that does not have an IP in its properties could still be exposed to the internet and needs to be investigated. 

 

More Resources

 

Quickstart: Your first portal query - Azure Resource Graph | Microsoft Docs

Azure Resource Graph: From beginner to expert (microsoft.com)

Azure Security Benchmark overview | Microsoft Docs

 

 

 

Disclaimer
The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.

Updated Feb 14, 2022
Version 2.0
  • wbsoul's avatar
    wbsoul
    Copper Contributor

    Below is a resource graph KQL query to list all Public IPs with attached resource details for each. Also VM Details attached details If attached resource type is NIC.

    It’s not neat as it should be, but at least it get the details:

    Resources
    | join kind=inner  
        (resourcecontainers 
        | where type == 'microsoft.resources/subscriptions' 
        | project SubscriptionName=name, subscriptionId
        )
        on subscriptionId 
    | where type == 'microsoft.network/publicipaddresses'
    | where SubscriptionName startswith "ag-azr-"
    | project
        PIP_LOC = location,
        PIP_SUB = SubscriptionName,
        PIP_RG = resourceGroup, 
        PIP_Name = name,
        PIP_skuName = sku.name,
        PIP_skuTier = sku.tier,
        PIP_zones = zones,
        PIP_ddos = properties.ddosSettings.protectionMode,
        publicIPAllocationMethod = properties.publicIPAllocationMethod,
        publicIPAddressVersion = properties.publicIPAddressVersion,
        ipAddress = properties.ipAddress,
        Attched_resourceID = tolower(split(properties.ipConfiguration.id, '/ipConfigurations')[0]), 
        Attched_resourceName = split(properties.ipConfiguration.id, '/')[8],
        Attched_resourceRG = split(properties.ipConfiguration.id, '/')[4],
        Attched_resourceType = strcat(split(properties.ipConfiguration.id, '/')[6], "/", split(properties.ipConfiguration.id, '/')[7])
    | join kind=leftouter  
        (resources
        | where type == "microsoft.network/networkinterfaces"
        | project Attched_resourceID = tolower(id),
          VMID = properties.virtualMachine.id
        )
        on Attched_resourceID 
    | project-away Attched_resourceID1
    | extend VM_RG = split(VMID, '/')[4]
    | extend VM_Name = split(VMID, '/')[8]

     

  • Fuellbier's avatar
    Fuellbier
    Copper Contributor

    The query is ugly, but I think it works. It matches IPv4 without RFC1918 private addresses. To be precise, it matches more than just IPv4 (.e.g. 0.999.999.999), but I think it should do the trick here.

    resources
    | where properties matches regex @'\b[0-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b1[1-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b[2-9][0-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b1[0-6][0-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b171\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b172\.3[3-9]\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b172\.[4-9][0-9]\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b17[3-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b18[0-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b19[0-1]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b192\.[0-9]\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b192\.[1-9][0-9]\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b192\.1[0-5][0-9]\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b192\.16[0-7]\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b192\.169\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b192\.1[7-9][0-9]\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b192\.2[0-5][0-9]\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b19[3-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' or
    properties matches regex @'\b2[0-5][0-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'
    |project  name, type, location, resourceGroup, subscriptionId, properties

     

  • AlanOld's avatar
    AlanOld
    Copper Contributor

    Hi @wernerrall

     

    Could you advise the query you would need to check for all non rfc1918 addresses.

     

    0.0.0.0 - 9.255.255.255

    11.0.0.0 - 171.255.255.255

    172.33.0.0 - 192.167.255.255

    192.169.0.0 - 255.255.255.255

     

    I have tried this... 

    | where properties matches regex @'\b(?!10\.|192\.168\.|172\.(?:1[6-9]|2[0-9]|3[01])\.)(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}\b'
    | where type !~ 'microsoft.network/networksecuritygroups'
    |project name, type, location, resourceGroup, subscriptionId, properties
     
     
     
    But Azure Graph states its an ill-formed regex
     

    Thanks in advance

  • JohnTie Thank you for the questions! Easiest way to interpret the properties are to understand which resources contain which properties. A VM would for example have a different set of IP Properties than a SQL Database or a Load Balancer. Our documentation for each of the technologies would explain it better. 

    By learning about the IP properties it would also expand your understanding on how to possibly protect them. 

    In our MS Security Documentation we have articles like Azure security baseline for Azure Public IP | Microsoft Docs which explains very carefully how to protect al types of resources. Hope this helps!

  • JohnTie's avatar
    JohnTie
    Copper Contributor

    wernerrall Thanks for this article - very helpful. I'm relatively new to Azure. Any tips for how to interpret the properties output generated by the query? For example an I see non private IP addresses next to words like 

     

    possibleInboundIpAddresses

    destinationAddresses

    nexthopIPAddress

     

    If it was you, what would you do next when you have your output, to test whether the IPs are IPs which are truly public (and attackable)?

     

    Thanks!

  • guidovbrakel That works great for VMs, the problem comes in when the "type" for an IP is not called publicipaddresses (I saw this in a few other resources). Not an easy way to get Sub Names so for specific subscription names I use the Graph Explorer "Scope" filter to choose my subscription. I am sure a join could be completed which will show the names. Will keep this in mind. Thanks

  • guidovbrakel's avatar
    guidovbrakel
    Brass Contributor

    Wouldn't it be easier to just query for the resource type: microsoft.network/publicipaddresses. How can we integrate the subscriptionname in this query? wernerrall