Azure Synapse with Managed VNET and data exfiltration protection is great for security - until you realise your Spark pools can't reach anything.
Here's what's actually happening and how to fix it.
The Problem
When you enable a Managed VNET in Synapse, your Spark pools don't run in YOUR VNET. They run in a Microsoft-managed VNET that's injected/peered with yours.
Enable data exfiltration protection, and all outbound traffic is blocked by default.
That means your Spark pool can't reach:
- Your Event Hub (even with a private endpoint in your VNET)
- Your Storage Account
- Your Key Vault
- Log Analytics for diagnostics
Your existing private endpoints don't help because they're in your VNET, not Synapse's managed VNET.
The Solution: Managed Private Endpoints
You need to create private endpoints FROM Synapse's managed VNET TO your resources. These are called Managed Private Endpoints.
resource "azurerm_synapse_managed_private_endpoint" "eventhub" {
name = "mpe-eventhub"
synapse_workspace_id = azurerm_synapse_workspace.this.id
target_resource_id = azurerm_eventhub_namespace.this.id
subresource_name = "namespace" # NOT "eventhub"!
}
The Subresource Name Gotcha
The subresource_name parameter trips everyone up. It's not always obvious what to use:
| Azure Resource | Subresource Name |
|---|---|
| Event Hub | namespace |
| Storage (Blob) | blob |
| Storage (ADLS Gen2) | dfs |
| Key Vault | vault |
| Azure SQL | sqlServer |
| Cosmos DB | Sql, MongoDB, or Cassandra |
| Service Bus | namespace |
| Log Analytics (via AMPLS) | azuremonitor |
Get this wrong and the endpoint creation fails with an unhelpful error.
Approving the Connection
Managed private endpoints need approval on the target resource. Terraform can't do this automatically (it's a separate resource provider).
After terraform apply:
# List pending connections
az network private-endpoint-connection list \
--resource-name "your-eventhub-namespace" \
--resource-group "your-rg" \
--type Microsoft.EventHub/namespaces
# Approve the connection
az network private-endpoint-connection approve \
--resource-name "your-eventhub-namespace" \
--resource-group "your-rg" \
--type Microsoft.EventHub/namespaces \
--name "connection-name-from-list"
Or do it in the portal: go to the target resource → Private endpoint connections → Approve.
Testing with CLI
Before committing to Terraform, test with the CLI:
az synapse managed-private-endpoints create \
--workspace-name "your-synapse-ws" \
--resource-group "your-rg" \
--pe-name "mpe-test-eventhub" \
--group-id "namespace" \
--resource-id "/subscriptions/.../Microsoft.EventHub/namespaces/your-eh"
If it works, convert to Terraform. If not, you'll get a better error message.
Connecting to Log Analytics
This one's extra tricky. You can't create a managed private endpoint directly to Log Analytics. You need Azure Monitor Private Link Scope (AMPLS) in between.
# 1. Create AMPLS
resource "azurerm_monitor_private_link_scope" "this" {
name = "ampls-synapse"
resource_group_name = azurerm_resource_group.this.name
ingestion_access_mode = "Open" # Important!
query_access_mode = "Open"
}
# 2. Link Log Analytics to AMPLS
resource "azurerm_monitor_private_link_scoped_service" "law" {
name = "law-scoped"
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
}
# 3. Create managed PE from Synapse to AMPLS
resource "azurerm_synapse_managed_private_endpoint" "ampls" {
name = "mpe-ampls"
synapse_workspace_id = azurerm_synapse_workspace.this.id
target_resource_id = azurerm_monitor_private_link_scope.this.id
subresource_name = "azuremonitor"
}
Use "Open" mode for AMPLS unless you want to break Log Analytics for other workspaces that aren't in the scope.
Troubleshooting: Endpoints Disappearing
If your managed private endpoints keep disappearing:
-
Check for ARM template conflicts - If you have both Terraform and ARM/Bicep deploying Synapse resources, they can delete each other's endpoints.
-
Check the Activity Log:
AzureActivity
| where OperationNameValue contains "managedPrivateEndpoints/delete"
| project TimeGenerated, Caller, OperationNameValue, ResourceId
- Ensure Terraform state is authoritative - Use
lifecycle { prevent_destroy = true }if needed.
The Full Pattern
For a typical Synapse deployment with data exfiltration protection:
- Managed PE to ADLS Gen2 (subresource:
dfs) - Managed PE to Key Vault (subresource:
vault) - Managed PE to Event Hub (subresource:
namespace) - AMPLS + Managed PE for Log Analytics (subresource:
azuremonitor) - Approve all pending connections
Test connectivity from a Spark notebook before calling it done.
Struggling with Synapse networking? Get in touch - we've helped multiple clients navigate this complexity.