Back to Blog
Azure
4 min read

Azure Monitor Private Link Scope - Selective Configuration

AzureMonitoringPrivate LinkLog AnalyticsNetworking

Azure Monitor Private Link Scope (AMPLS) provides private connectivity to Log Analytics and Application Insights. But configure it wrong and you'll break access to all workspaces across your tenant.

The Problem

When you link the privatelink.monitor.azure.com DNS zone to a VNET:

  • All Log Analytics queries from that VNET go to the private endpoint
  • Workspaces not in your AMPLS become unreachable
  • This affects every workspace, even ones in other subscriptions

If you have 50 workspaces and only add 5 to AMPLS, the other 45 break.

Understanding AMPLS Modes

ModeBehavior
OpenPrivate endpoint for AMPLS resources, public for others
Private OnlyOnly AMPLS resources accessible, everything else blocked

For most scenarios, use Open mode.

Setting Up AMPLS Correctly

1. Create the AMPLS Resource

resource "azurerm_monitor_private_link_scope" "this" {
  name                = "ampls-production"
  resource_group_name = azurerm_resource_group.this.name

  # Use Open mode to allow access to non-AMPLS workspaces
  ingestion_access_mode = "Open"
  query_access_mode     = "Open"
}

2. Add Workspaces Selectively

Only add workspaces that need private connectivity:

resource "azurerm_monitor_private_link_scoped_service" "workspace" {
  name                = "link-to-workspace"
  resource_group_name = azurerm_resource_group.this.name
  scope_name          = azurerm_monitor_private_link_scope.this.name
  linked_resource_id  = azurerm_log_analytics_workspace.this.id
}

# Add Application Insights if needed
resource "azurerm_monitor_private_link_scoped_service" "appinsights" {
  name                = "link-to-appinsights"
  resource_group_name = azurerm_resource_group.this.name
  scope_name          = azurerm_monitor_private_link_scope.this.name
  linked_resource_id  = azurerm_application_insights.this.id
}

3. Create the Private Endpoint

resource "azurerm_private_endpoint" "ampls" {
  name                = "pe-ampls"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
  subnet_id           = azurerm_subnet.private_endpoints.id

  private_service_connection {
    name                           = "psc-ampls"
    private_connection_resource_id = azurerm_monitor_private_link_scope.this.id
    subresource_names              = ["azuremonitor"]
    is_manual_connection           = false
  }
}

4. Selective DNS Zone Linking

This is the critical part. Don't link all zones to all VNETs.

AMPLS creates entries in these zones:

  • privatelink.monitor.azure.com
  • privatelink.oms.opinsights.azure.com
  • privatelink.ods.opinsights.azure.com
  • privatelink.agentsvc.azure-automation.net
  • privatelink.blob.core.windows.net (for data collection)

Only link to VNETs that need private access to AMPLS workspaces:

# Only link to VNETs that need AMPLS access
resource "azurerm_private_dns_zone_virtual_network_link" "ampls" {
  for_each = toset(["hub-vnet"])  # Only specific VNETs

  name                  = "link-${each.key}"
  resource_group_name   = azurerm_resource_group.dns.name
  private_dns_zone_name = azurerm_private_dns_zone.monitor.name
  virtual_network_id    = azurerm_virtual_network.hub.id
  registration_enabled  = false
}

Managing Hundreds of Workspaces

With many workspaces, you can't add all to one AMPLS (limit of 10 per AMPLS, 5 AMPLS per workspace).

Strategy 1: Regional AMPLS

Create AMPLS per region:

locals {
  regions = ["uksouth", "ukwest", "northeurope"]
}

resource "azurerm_monitor_private_link_scope" "regional" {
  for_each = toset(local.regions)

  name                  = "ampls-${each.key}"
  resource_group_name   = azurerm_resource_group.this.name
  ingestion_access_mode = "Open"
  query_access_mode     = "Open"
}

Strategy 2: Workload-Based AMPLS

Group by workload or environment:

# Production workspaces
resource "azurerm_monitor_private_link_scope" "production" {
  name                  = "ampls-production"
  resource_group_name   = azurerm_resource_group.this.name
  ingestion_access_mode = "Open"
  query_access_mode     = "Open"
}

# Development/Test workspaces - maybe don't need private link
# Use public access for dev

Troubleshooting

Queries Timing Out

Check if the workspace is in the AMPLS:

Get-AzMonitorPrivateLinkScope -Name "ampls-production" -ResourceGroupName "rg" |
  Get-AzMonitorPrivateLinkScopedResource

"Resource Not Found" Errors

Your VNET might have the DNS zone linked but the workspace isn't in AMPLS:

# Check DNS resolution
Resolve-DnsName "workspace-id.ods.opinsights.azure.com"

# If it returns a private IP but workspace isn't in AMPLS, that's your problem

Data Not Ingesting

  1. Check agent connectivity
  2. Verify private endpoint is approved
  3. Check if Log Analytics public access is disabled
$workspace = Get-AzOperationalInsightsWorkspace -Name "workspace" -ResourceGroupName "rg"
$workspace.PublicNetworkAccessForIngestion
$workspace.PublicNetworkAccessForQuery

Best Practices

  1. Always use Open mode unless you have specific compliance requirements
  2. Link DNS zones selectively - not every VNET needs private monitor access
  3. Test in dev first - AMPLS changes can break monitoring
  4. Document your AMPLS topology - it gets complex fast
  5. Monitor the AMPLS limits - 10 resources per scope, 5 scopes per resource

Need help with Azure Monitor and private connectivity? Get in touch - we help organisations implement secure monitoring solutions.

Need help with your Azure environment?

Get in touch for a free consultation.

Get in Touch