Microsoft Fabric is powerful for data analytics but integrating it with private Azure resources - storage accounts, databases, Key Vaults behind firewalls - requires planning.
Fabric Networking Landscape
Unlike Azure Synapse, Fabric doesn't have a managed VNET you control. Instead you have:
- VNET Data Gateway - Bridge between Fabric and your VNET
- Trusted Microsoft Services - Bypass for some Azure services
- Managed Private Endpoints (Preview) - Direct private connectivity
Environment Strategy
Typical setup for production:
┌─────────────────────────────────────────────────────────────┐
│ Azure Tenant │
│ ┌─────────────────┐ ┌──────────────────────────────┐ │
│ │ Fabric Tenant │ │ Azure VNET │ │
│ │ ┌───────────┐ │ │ ┌─────────────────────────┐ │ │
│ │ │Workspace │──┼────┼──│ VNET Data Gateway │ │ │
│ │ │ - NPD │ │ │ └───────────┬─────────────┘ │ │
│ │ │ - PRD │ │ │ │ │ │
│ │ └───────────┘ │ │ ┌───────────▼─────────────┐ │ │
│ └─────────────────┘ │ │ Private Endpoints │ │ │
│ │ │ - Storage │ │ │
│ │ │ - SQL │ │ │
│ │ │ - Key Vault │ │ │
│ │ └────────────────────────-┘ │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Setting Up VNET Data Gateway
1. Create the Subnet
resource "azurerm_subnet" "fabric_gateway" {
name = "snet-fabric-gateway"
resource_group_name = azurerm_resource_group.this.name
virtual_network_name = azurerm_virtual_network.this.name
address_prefixes = ["10.0.10.0/24"]
delegation {
name = "fabric-delegation"
service_delegation {
name = "Microsoft.PowerPlatform/vnetaccesslinks"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
}
}
}
2. Create Private Endpoints
For each service Fabric needs to access:
# Storage Account
resource "azurerm_private_endpoint" "storage" {
name = "pe-storage-fabric"
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-storage"
private_connection_resource_id = azurerm_storage_account.datalake.id
subresource_names = ["dfs"]
is_manual_connection = false
}
private_dns_zone_group {
name = "dns-group"
private_dns_zone_ids = [azurerm_private_dns_zone.dfs.id]
}
}
# SQL Database
resource "azurerm_private_endpoint" "sql" {
name = "pe-sql-fabric"
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-sql"
private_connection_resource_id = azurerm_mssql_server.this.id
subresource_names = ["sqlServer"]
is_manual_connection = false
}
private_dns_zone_group {
name = "dns-group"
private_dns_zone_ids = [azurerm_private_dns_zone.sql.id]
}
}
3. Configure the Gateway in Fabric
In the Fabric admin portal:
- Go to Settings → Manage connections and gateways
- Create new VNET data gateway
- Select your subscription and VNET
- Wait for provisioning (can take 15-30 minutes)
Managed Private Endpoints (Preview)
Fabric now supports managed private endpoints for direct connectivity:
# This is configured in the Fabric portal, not Terraform
# But you can approve the endpoint on the Azure side
resource "azurerm_private_endpoint_connection" "approve_fabric" {
name = "pec-fabric-storage"
resource_group_name = azurerm_resource_group.this.name
private_endpoint_id = "FABRIC_MANAGED_PE_ID"
private_service_connection_id = "FABRIC_PSC_ID"
is_manual_connection = true
request_message = "Approved for Fabric"
status = "Approved"
}
NPD vs PRD Configuration
Non-Production
More relaxed for development velocity:
# Allow Fabric trusted services
resource "azurerm_storage_account" "npd" {
name = "stdatalakenpd"
resource_group_name = azurerm_resource_group.npd.name
location = azurerm_resource_group.npd.location
account_tier = "Standard"
account_replication_type = "LRS"
network_rules {
default_action = "Deny"
bypass = ["AzureServices"] # Allow Fabric
ip_rules = [var.developer_ip] # Allow dev access
}
}
Production
Strict - VNET gateway only:
resource "azurerm_storage_account" "prd" {
name = "stdatalakeprd"
resource_group_name = azurerm_resource_group.prd.name
location = azurerm_resource_group.prd.location
account_tier = "Standard"
account_replication_type = "GRS"
network_rules {
default_action = "Deny"
bypass = ["None"] # No bypass
virtual_network_subnet_ids = [azurerm_subnet.fabric_gateway.id]
}
}
Testing Connectivity
From a Fabric notebook:
# Test storage connectivity
from notebookutils import mssparkutils
try:
files = mssparkutils.fs.ls("abfss://[email protected]/")
print("Storage connectivity: OK")
for f in files:
print(f" {f.name}")
except Exception as e:
print(f"Storage connectivity: FAILED - {e}")
# Test SQL connectivity
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
try:
df = spark.read \
.format("jdbc") \
.option("url", "jdbc:sqlserver://server.database.windows.net:1433;database=mydb") \
.option("query", "SELECT 1") \
.option("authentication", "ActiveDirectoryMSI") \
.load()
print("SQL connectivity: OK")
except Exception as e:
print(f"SQL connectivity: FAILED - {e}")
Performance Considerations
- VNET gateways add latency (~10-20ms)
- For large data volumes, consider OneLake shortcuts
- Position gateway in same region as data sources
- Use Premium capacity for production workloads
Need help integrating Microsoft Fabric with your Azure infrastructure? Get in touch - we help organisations design secure data platforms.