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
| Mode | Behavior |
|---|---|
| Open | Private endpoint for AMPLS resources, public for others |
| Private Only | Only 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.comprivatelink.oms.opinsights.azure.comprivatelink.ods.opinsights.azure.comprivatelink.agentsvc.azure-automation.netprivatelink.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
- Check agent connectivity
- Verify private endpoint is approved
- Check if Log Analytics public access is disabled
$workspace = Get-AzOperationalInsightsWorkspace -Name "workspace" -ResourceGroupName "rg"
$workspace.PublicNetworkAccessForIngestion
$workspace.PublicNetworkAccessForQuery
Best Practices
- Always use Open mode unless you have specific compliance requirements
- Link DNS zones selectively - not every VNET needs private monitor access
- Test in dev first - AMPLS changes can break monitoring
- Document your AMPLS topology - it gets complex fast
- 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.