You want to secure your Service Bus with VNET rules or private endpoints. Then your Power Automate flows stop working. Here's how to handle this common scenario.
The Problem
Power Automate runs on Microsoft's shared infrastructure. It doesn't have a static IP range you can whitelist, and it doesn't support private endpoints natively.
When you enable network rules on Service Bus:
resource "azurerm_servicebus_namespace" "this" {
name = "sb-production"
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
sku = "Premium" # Required for network rules
network_rule_set {
default_action = "Deny"
trusted_services_allowed = true # Important!
network_rules {
subnet_id = azurerm_subnet.apps.id
}
}
}
Power Automate flows get "403 Forbidden" because they're not coming from your VNET.
Solution 1: Trusted Microsoft Services
The simplest approach - allow Microsoft first-party services:
network_rule_set {
default_action = "Deny"
trusted_services_allowed = true # This allows Power Automate
}
What this allows:
- Azure Event Grid
- Azure Stream Analytics
- Azure IoT Hub
- Azure API Management
- Power Automate / Logic Apps
- Azure Functions (with managed identity)
What this doesn't allow:
- Random internet traffic
- Traffic from other tenants' Power Automate
Solution 2: Managed Connector with On-Premises Gateway
For stricter requirements, use a data gateway:
- Deploy on-premises data gateway in your VNET
- Use Service Bus connector via the gateway
- Gateway connects to Service Bus via private endpoint
# Private endpoint for Service Bus
resource "azurerm_private_endpoint" "servicebus" {
name = "pe-servicebus"
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
subnet_id = azurerm_subnet.gateway.id
private_service_connection {
name = "psc-servicebus"
private_connection_resource_id = azurerm_servicebus_namespace.this.id
subresource_names = ["namespace"]
is_manual_connection = false
}
}
Solution 3: Azure Functions as Middleware
Create a Function App that Power Automate calls, which then talks to Service Bus:
// Azure Function with VNET integration
[FunctionName("SendToServiceBus")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
[ServiceBus("myqueue", Connection = "ServiceBusConnection")] IAsyncCollector<string> outputQueue)
{
string messageBody = await new StreamReader(req.Body).ReadToEndAsync();
await outputQueue.AddAsync(messageBody);
return new OkResult();
}
# Function App with VNET integration
resource "azurerm_linux_function_app" "middleware" {
name = "func-sb-middleware"
resource_group_name = azurerm_resource_group.this.name
location = azurerm_resource_group.this.location
service_plan_id = azurerm_service_plan.this.id
storage_account_name = azurerm_storage_account.func.name
storage_account_access_key = azurerm_storage_account.func.primary_access_key
virtual_network_subnet_id = azurerm_subnet.functions.id
site_config {
vnet_route_all_enabled = true
}
}
SKU Requirements
Standard SKU: No network rules available. Use Shared Access Signatures for security.
Premium SKU: Full network isolation with:
- IP firewall rules
- VNET service endpoints
- Private endpoints
- Trusted services bypass
resource "azurerm_servicebus_namespace" "premium" {
name = "sb-production"
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
sku = "Premium"
capacity = 1 # 1, 2, 4, 8, or 16 messaging units
premium_messaging_partitions = 1
}
IP Firewall Alternative
If you need to allow specific IPs (e.g., known partner systems):
resource "azurerm_servicebus_namespace_network_rule_set" "this" {
namespace_id = azurerm_servicebus_namespace.this.id
default_action = "Deny"
trusted_services_allowed = true
public_network_access_enabled = true
ip_rules = [
"203.0.113.0/24", # Partner network
"198.51.100.10" # Specific server
]
network_rules {
subnet_id = azurerm_subnet.apps.id
}
}
Monitoring Access
Check who's accessing your Service Bus:
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.SERVICEBUS"
| where Category == "OperationalLogs"
| summarize count() by CallerIpAddress, OperationName
| order by count_ desc
Look for blocked access attempts:
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.SERVICEBUS"
| where ResultType == "Unauthorized" or ResultType == "Forbidden"
| project TimeGenerated, CallerIpAddress, OperationName, ResultType
Decision Matrix
| Requirement | Solution |
|---|---|
| Simple, good security | Trusted services bypass |
| Maximum isolation | Data gateway + private endpoint |
| Standard SKU | SAS tokens, no network isolation |
| Need audit trail | Premium + diagnostic logging |
Need help securing your Azure messaging infrastructure? Get in touch - we help organisations implement secure integration patterns.