User Tools

Site Tools


burim:azure:azureresourcegraphexplorer

Azure Application Gateways: Private & Public Listener Query Cookbook

This page documents how to use Azure Resource Graph Explorer (ARG) to report on Azure Application Gateways (App GWs) that have private listeners, public listeners, or both. It also explains the “No listener associated to the private” message you may see in the Azure Portal.

Problem: “No listener associated to the private”

When Azure shows “No listener associated to the private”, it only matters if you *expect* traffic to reach that private front-end IP.

Explanation

  • The private front-end IP exists on the gateway, but no listener is bound to it; traffic to that IP is ignored.
  • A listener binds an IP/port/hostname tuple to a routing rule and backend. No listener ⇒ no traffic handling.

Impact Summary

Scenario Impact
Only using public endpoint No issue — safe to ignore
Need to serve internal clients Traffic to private IP fails
Security No new exposure (no open port without listener)
Management hygiene Consider deleting unused config

Fix (if needed)

  1. Create a listener using the private front-end IP.
  2. Bind it to a request routing rule and backend pool.
  3. Update internal DNS (private zone) if clients will use an FQDN.

Using Azure Resource Graph Explorer

All queries below run in Azure Portal → Resource Graph Explorer. Before running, click Scope → Select all subscriptions (unless you intentionally scope smaller).


Queries

Below are reusable Kusto snippets. Each `

` block begins with a comment line naming the query so context is preserved when copying the code block alone.
 
----
 
==== List Application Gateways with *Private Listeners* ====
 
<code kusto>
// ==== Private Listeners ====
// Lists App GWs that have at least one listener bound to a PRIVATE frontend IP.
Resources
| where type == "microsoft.network/applicationgateways"
| extend listeners = properties.httpListeners
| mv-expand listener = listeners
| extend frontendIP = tostring(listener.properties.frontendIPConfiguration.id)
| join kind=inner (
    Resources
    | where type == "microsoft.network/applicationgateways/frontendipconfigurations"
    | extend ipAddress = tostring(properties.privateIPAddress)
    | extend frontendIPId = id
    | project frontendIPId, ipAddress
) on $left.frontendIP == $right.frontendIPId
| project resourceGroup, name, listenerName=tostring(listener.name), privateIP=ipAddress

List Application Gateways with *Public Listeners*

// ==== Public Listeners ====
// Lists App GWs that have at least one listener bound to a PUBLIC frontend IP (resource ID only).
Resources
| where type == "microsoft.network/applicationgateways"
| extend listeners = properties.httpListeners
| mv-expand listener = listeners
| extend frontendIP = tostring(listener.properties.frontendIPConfiguration.id)
| join kind=inner (
    Resources
    | where type == "microsoft.network/applicationgateways/frontendipconfigurations"
    | extend publicIPId = tostring(properties.publicIPAddress.id)
    | extend frontendIPId = id
    | project frontendIPId, publicIPId
) on $left.frontendIP == $right.frontendIPId
| project resourceGroup, name, listenerName=tostring(listener.name), publicIPResourceId=publicIPId

Troubleshooting: Public Query Returned *No Results*

If the query above returned nothing, run this quick front-end scan to confirm whether any App GWs actually reference a Public IP at all.

// ==== Public Frontends Quick Check ====
// Shows ALL App GW frontend configs that reference a Public IP (whether or not a listener uses them).
Resources
| where type =~ "microsoft.network/applicationgateways"
| extend fips = properties.frontendIPConfigurations
| mv-expand fip = fips
| extend publicIpId = tostring(fip.properties.publicIPAddress.id)
| where isnotempty(publicIpId)
| project subscriptionId, resourceGroup, gatewayName = name,
         frontendName = tostring(fip.name),
         publicIpResourceId = publicIpId

Public Listeners *with Actual IP Address*

// ==== Public Listeners with actual IP address ====
// Resolves Public IP resource ID to its routable IPv4/IPv6 address.
Resources
| where type =~ "microsoft.network/applicationgateways"
| extend fips = properties.frontendIPConfigurations
| mv-expand fip = fips
| extend publicIpId = tostring(fip.properties.publicIPAddress.id)
| where isnotempty(publicIpId)
| project subscriptionId, resourceGroup, gatewayName = name,
         frontendName = tostring(fip.name),
         publicIpResourceId = publicIpId
| join kind = leftouter (
    Resources
    | where type =~ "microsoft.network/publicipaddresses"
    | project publicIpResourceId = id,
              publicIpAddress = properties.ipAddress
) on publicIpResourceId
| project subscriptionId, resourceGroup, gatewayName, frontendName, publicIpAddress, publicIpResourceId

Private Front-End Configurations

// ==== Private Frontend Configs ====
// Lists every App GW frontend that carries a PRIVATE IP (whether or not a listener uses it).
Resources
| where type =~ "microsoft.network/applicationgateways"
| extend fips = properties.frontendIPConfigurations
| mv-expand fip = fips
| extend privateIpAddress = tostring(fip.properties.privateIPAddress)
| where isnotempty(privateIpAddress)
| project subscriptionId, resourceGroup, gatewayName = name,
         frontendName = tostring(fip.name),
         privateIpAddress,
         frontendIPConfigId = tostring(fip.id)

Listeners Bound to *Private* IPs

// ==== Private-bound Listeners ====
// Shows which listeners on each App GW are tied to PRIVATE frontends.
Resources
| where type =~ "microsoft.network/applicationgateways"
| extend listeners = properties.httpListeners,
         fips      = properties.frontendIPConfigurations
| mv-expand listener = listeners
| mv-expand fip      = fips
| extend listenerFipId  = tostring(listener.properties.frontendIPConfiguration.id)
| where listenerFipId == fip.id
| extend privateIpAddress = tostring(fip.properties.privateIPAddress)
| where isnotempty(privateIpAddress)
| project subscriptionId, resourceGroup, gatewayName = name,
         listenerName = tostring(listener.name),
         privateIpAddress, frontendName = tostring(fip.name)

Gateways that have *Both* Private **and** Public Listeners

Use these when you need to identify “dual-homed” gateways.


Summary: Counts & Resource IDs

// ==== Gateways with BOTH Private & Public Listeners (IDs only) ====
// Counts listeners of each type; returns sets of private IPs + Public IP *resource IDs*.
Resources
| where type =~ "microsoft.network/applicationgateways"
| extend listeners = properties.httpListeners,
         fips      = properties.frontendIPConfigurations
| mv-expand listener = listeners
| mv-expand fip      = fips
| extend listenerFipId = tostring(listener.properties.frontendIPConfiguration.id)
| where listenerFipId == tostring(fip.id)
| extend isPrivate = iff(isnotempty(fip.properties.privateIPAddress), 1, 0),
         isPublic  = iff(isnotempty(fip.properties.publicIPAddress.id), 1, 0)
| summarize
     privateListenerCount = countif(isPrivate == 1),
     publicListenerCount  = countif(isPublic  == 1),
     privateIPs           = make_set(fip.properties.privateIPAddress, 5),
     publicIPIds          = make_set(fip.properties.publicIPAddress.id, 5)
  by subscriptionId, resourceGroup, gatewayName = name
| where privateListenerCount > 0 and publicListenerCount > 0
| project subscriptionId, resourceGroup, gatewayName,
          privateListenerCount, publicListenerCount,
          privateIPs, publicIPIds

Summary: Counts & *Actual* Public IP Address

// ==== Gateways with BOTH Private & Public Listeners (actual Public IPs) ====
// Resolves public IP resource IDs to addresses and summarizes per gateway.
let publicIPs = Resources
    | where type =~ "microsoft.network/publicipaddresses"
    | project publicIpResourceId = id,
             publicIpAddress     = properties.ipAddress;
Resources
| where type =~ "microsoft.network/applicationgateways"
| extend listeners = properties.httpListeners,
         fips      = properties.frontendIPConfigurations
| mv-expand listener = listeners
| mv-expand fip      = fips
| extend listenerFipId = tostring(listener.properties.frontendIPConfiguration.id)
| where listenerFipId == tostring(fip.id)
| extend privateIpAddress   = tostring(fip.properties.privateIPAddress),
         publicIpResourceId = tostring(fip.properties.publicIPAddress.id),
         isPrivate = iff(isnotempty(privateIpAddress), 1, 0),
         isPublic  = iff(isnotempty(publicIpResourceId), 1, 0)
| join kind = leftouter publicIPs on publicIpResourceId
| summarize
     privateListenerCount = countif(isPrivate == 1),
     publicListenerCount  = countif(isPublic  == 1),
     privateIPs           = make_set(privateIpAddress, 5),
     publicIPs            = make_set(publicIpAddress, 5)
  by subscriptionId, resourceGroup, gatewayName = name
| where privateListenerCount > 0 and publicListenerCount > 0
| project subscriptionId, resourceGroup, gatewayName,
          privateListenerCount, publicListenerCount,
          privateIPs, publicIPs

Tips

  • In ARG Explorer, always confirm Scope includes all required subscriptions.
  • Use the Download results button in ARG Explorer to export CSV for reporting.
  • To filter to a single subscription, prepend:

`| where subscriptionId == “<SUBSCRIPTION-GUID>“` after the main `Resources` line.

  • To filter to a region:

`| where location =~ “westeurope”` (case-insensitive).


End of document.

burim/azure/azureresourcegraphexplorer.txt · Last modified: 2025/07/21 10:22 by burim

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki