Azure Logic Apps — Standard Logic Apps: VNet Integration

Outbound via VNet, Private Endpoint Inbound, and Hybrid Connectivity


Introduction

Azure Logic Apps Standard provides VNet integration capabilities that enable secure communication with on-premises resources, private endpoints, and other Azure services without exposing them to the public internet. This is essential for enterprise architectures requiring compliance, security, and hybrid cloud scenarios.

This guide covers:

  • VNet integration basics — How outbound traffic works
  • Private endpoints — Securing inbound access
  • On-premises connectivity — Hybrid integration patterns
  • Network security — NSG rules and firewall configuration
  • Real-world scenarios — Complete implementation patterns

Understanding VNet Integration

Architecture Overview

┌─────────────────────────────────────────────────────────────────────┐
│              LOGIC APPS VNET INTEGRATION ARCHITECTURE               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │                   Azure VNet                                │   │
│   │                                                             │   │
│   │   ┌──────────────┐                                          │   │
│   │   │ Logic App    │◀── VNet Integration                      │   │
│   │   │ (App Service)│    (Outbound Traffic)                    │   │
│   │   └──────────────┘                                          │   │
│   │        │                                                    │   │
│   │        │         Private Endpoint                           │   │
│   │        │         (Inbound Traffic)                          │   │
│   │        ▼                                                    │   │
│   │   ┌──────────────┐                                          │   │
│   │   │ Private      │                                          │   │
│   │   │ Endpoint     │                                          │   │
│   │   └──────────────┘                                          │   │
│   │                                                             │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                              │                                      │
│         ┌────────────────────┼────────────────────┐                 │
│         ▼                    ▼                    ▼                 │
│   ┌─────────────┐    ┌─────────────┐    ┌─────────────┐             │
│   │ On-Premises │    │   Azure     │    │   Azure     │             │
│   │ SQL Server  │    │ Key Vault   │    │ SQL         │             │
│   │ (VPN/Express)    │ (Private)   │    │ (Private)   │             │
│   └─────────────┘    └─────────────┘    └─────────────┘             │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

How VNet Integration Works

  1. Outbound Traffic — Logic App routes traffic through VNet subnet
  2. Private Endpoints — Traffic arrives via private IP addresses
  3. On-Premises Access — Use VPN or ExpressRoute for hybrid connectivity
  4. No Public Exposure — Services only accessible within VNet

Configure VNet Integration

Prerequisites

  • Virtual Network — With available subnet
  • Delegated Subnet — For App Service integration
  • Premium/Standard tier — Logic App Standard tier
  • Regional VNet integration — Same region required

Create Logic App with VNet

# Create Logic App with VNet integration during creation
az logicapp create \
  --name my-logic-app \
  --resource-group my-rg \
  --plan my-app-service-plan \
  --location eastus \
  --storage-account mystorageaccount

# Enable VNet route all
az logicapp config appsettings set \
  --name my-logic-app \
  --resource-group my-rg \
  --settings "WEBSITE_VNET_ROUTE_ALL=1"

# Add VNet integration
az logicapp config vnet-integration add \
  --name my-logic-app \
  --resource-group my-rg \
  --vnet-name my-vnet \
  --subnet-name logic-app-subnet

# Verify VNet integration
az logicapp config vnet-integration show \
  --name my-logic-app \
  --resource-group my-rg

Configure Subnet for Integration

# Create subnet with delegation
az network vnet subnet create \
  --name logic-app-subnet \
  --vnet-name my-vnet \
  --resource-group my-rg \
  --address-prefixes 10.0.1.0/24 \
  --delegations Microsoft.Web/serverFarms

ARM Template Configuration

{
  "resources": [
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2021-02-01",
      "name": "my-logic-app",
      "location": "eastus",
      "properties": {
        "virtualNetworkSubnetId": "/subscriptions/xxx/resourceGroups/my-rg/providers/Microsoft.Network/virtualNetworks/my-vnet/subnets/logic-app-subnet",
        "appSettings": [
          {
            "name": "WEBSITE_VNET_ROUTE_ALL",
            "value": "1"
          }
        ]
      }
    }
  ]
}

Private Endpoints for Inbound Access

Create Private Endpoint

# Create private endpoint for Logic App workflow
az network private-endpoint create \
  --name logic-app-pe \
  --resource-group my-rg \
  --location eastus \
  --subnet-name private-subnet \
  --vnet-name my-vnet \
  --connection-name logic-app-connection \
  --private-link-service-id /subscriptions/xxx/Microsoft.Logic/workflows/my-logic-app

Private Endpoint for Specific Workflow

# Create private endpoint targeting specific workflow
az network private-endpoint create \
  --name order-workflow-pe \
  --resource-group my-rg \
  --subnet-name private-subnet \
  --connection-name order-workflow-connection \
  --target-resource /subscriptions/xxx/resourceGroups/my-rg/providers/Microsoft.Logic/workflows/my-logic-app/workflows/order-processing

DNS Configuration

{
  "dnsConfig": {
    "zoneName": "internal.contoso.com",
    "privateDnsZoneGroup": {
      "zoneConfigs": [
        {
          "name": "private-endpoint-zone",
          "privateDnsZoneId": "/subscriptions/xxx/resourceGroups/my-rg/providers/Microsoft.AnalysisServices/servers"
        }
      ]
    }
  }
}

On-Premises Integration

Connect via VPN Gateway

# Configure Logic App to use VPN
az network vnet-gateway create \
  --name vpn-gateway \
  --resource-group my-rg \
  --location eastus \
  --gateway-type Vpn \
  --vpn-type RouteBased \
  --sku VpnGw1 \
  --vnet my-on-prem-vnet

Access On-Premises SQL Server

{
  "actions": {
    "Query_Orders": {
      "type": "Sql",
      "inputs": {
        "databaseName": "OrdersDB",
        "gatewayName": "my-on-prem-gateway",
        "query": "SELECT OrderId, CustomerName, Total FROM Orders WHERE Status = @status",
        "parameters": {
          "status": {
            "type": "string",
            "value": "pending"
          }
        }
      }
    }
  }
}

Configure On-Premises Data Gateway

# Install and register data gateway
# Download from: https://aka.ms/gatewayinstall

# Create gateway resource in Azure
az logicapp create \
  --name my-gateway \
  --resource-group my-rg \
  --location eastus

# Add gateway to Logic App
az logicapp update \
  --name my-logic-app \
  --resource-group my-rg \
  --params-file @gateway-config.json

HTTP Call to On-Premises API

{
  "triggers": {
    "HTTP_Request": {
      "type": "Request",
      "kind": "Http"
    }
  },
  "actions": {
    "Call_On_Prem_API": {
      "type": "Http",
      "inputs": {
        "method": "POST",
        "uri": "http://192.168.1.100:8080/api/orders",
        "headers": {
          "Content-Type": "application/json"
        },
        "authentication": {
          "type": "Basic",
          "username": "@appsettings('OnPremUsername')",
          "password": "@appsettings('OnPremPassword')"
        }
      }
    }
  }
}

Accessing Private Azure Services

Connect to Azure Key Vault

{
  "actions": {
    "Get_Connection_String": {
      "type": "KeyVault",
      "inputs": {
        "host": {
          "connection": {
            "name": "keyvault"
          }
        },
        "method": "getSecret",
        "parameters": {
          "secretName": "storage-connection-string"
        }
      }
    },
    "Use_Secret": {
      "type": "Http",
      "inputs": {
        "method": "GET",
        "uri": "https://mystorageaccount.blob.core.windows.net/data/file.json",
        "authentication": {
          "type": "Raw",
          "value": "@outputs('Get_Connection_String')"
        }
      }
    }
  }
}

Connect to Azure SQL

{
  "actions": {
    "Query_Customers": {
      "type": "Sql",
      "inputs": {
        "host": {
          "connection": {
            "name": "azuresql"
          }
        },
        "method": "query",
        "databaseName": "CustomerDB",
        "query": "SELECT * FROM Customers WHERE Region = @region",
        "parameters": {
          "region": {
            "type": "string",
            "value": "US"
          }
        }
      }
    }
  }
}

Connect to Azure Storage (Private)

{
  "actions": {
    "Read_Blob": {
      "type": "Blob",
      "inputs": {
        "host": {
          "connection": {
            "name": "azureblob"
          }
        },
        "method": "read",
        "path": "container/file.json"
      }
    }
  }
}

Network Security Configuration

Network Security Groups

{
  "securityRules": [
    {
      "name": "Allow-Ingress-From-VNet",
      "protocol": "Tcp",
      "sourcePortRange": "*",
      "destinationPortRange": "443",
      "sourceAddressPrefix": "10.0.0.0/16",
      "destinationAddressPrefix": "10.0.1.0/24",
      "access": "Allow",
      "direction": "Inbound",
      "priority": 100
    },
    {
      "name": "Allow-LogicApp-To-SQL",
      "protocol": "Tcp",
      "sourcePortRange": "*",
      "destinationPortRange": "1433",
      "sourceAddressPrefix": "10.0.1.0/24",
      "destinationAddressPrefix": "10.0.2.0/24",
      "access": "Allow",
      "direction": "Outbound",
      "priority": 110
    },
    {
      "name": "Deny-Public-Internet",
      "protocol": "*",
      "sourcePortRange": "*",
      "destinationPortRange": "*",
      "sourceAddressPrefix": "Internet",
      "destinationAddressPrefix": "*",
      "access": "Deny",
      "direction": "Outbound",
      "priority": 1000
    }
  ]
}

Application Security Groups

{
  "applicationSecurityGroups": [
    {
      "name": "LogicApps-ASG",
      "location": "eastus"
    }
  ]
}

Firewall Rules for On-Premises

# Allow Logic App IP range through firewall
# Outbound ports needed:
# - 443 (HTTPS)
# - 1433 (SQL)
# - 5672 (Service Bus)
# - 11000-11025 (Storage)

# Configure NSG outbound rules
az network nsg rule create \
  --nsg-name my-nsg \
  --resource-group my-rg \
  --name Allow-LogicApp-Outbound \
  --protocol Tcp \
  --source-address-prefix "10.0.1.0/24" \
  --destination-address-prefix "10.0.2.0/24" \
  --destination-port-range "*" \
  --access Allow \
  --priority 100

Complete Workflow Example

Order Processing with Private Services

{
  "definition": {
    "triggers": {
      "When_order_received": {
        "type": "ServiceBus",
        "inputs": {
          "queueName": "orders"
        }
      }
    },
    "actions": {
      "Get_Order_Details": {
        "type": "Sql",
        "inputs": {
          "databaseName": "OrdersDB",
          "gatewayName": "on-prem-gateway",
          "query": "SELECT * FROM Orders WHERE OrderId = @orderId",
          "parameters": {
            "orderId": {
              "type": "string",
              "value": "@triggerBody()['orderId']"
            }
          }
        }
      },
      "Call_Inventory_API": {
        "type": "Http",
        "inputs": {
          "method": "POST",
          "uri": "http://192.168.1.50/api/inventory/check",
          "body": {
            "items": "@body('Get_Order_Details')['items']"
          }
        }
      },
      "Update_Order_Status": {
        "type": "Sql",
        "inputs": {
          "databaseName": "OrdersDB",
          "gatewayName": "on-prem-gateway",
          "query": "UPDATE Orders SET Status = @status WHERE OrderId = @orderId",
          "parameters": {
            "orderId": {
              "type": "string",
              "value": "@triggerBody()['orderId']"
            },
            "status": {
              "type": "string",
              "value": "processed"
            }
          }
        }
      },
      "Send_Confirmation": {
        "type": "KeyVault",
        "inputs": {
          "operation": "getSecret",
          "secretName": "email-api-key"
        }
      }
    }
  }
}

Best Practices

PracticeDescription
Use private endpointsSecure inbound access
Enable VNet route allRoute all traffic through VNet
Implement NSG rulesControl inbound and outbound traffic
Use managed identityAvoid storing credentials
Enable diagnosticsSend logs to Log Analytics
Use separate subnetsIsolate Logic Apps from other resources
Configure DNSUse private DNS zones

Troubleshooting

Common Issues

IssueSolution
Cannot connect to VNetVerify subnet delegation
Private endpoint not accessibleCheck DNS resolution
On-prem SQL timeoutCheck firewall rules, VPN
Key Vault access deniedAdd Logic App to access policy

Diagnostic Commands

# Check VNet integration status
az logicapp config vnet-integration show \
  --name my-logic-app \
  --resource-group my-rg

# Test network connectivity from Logic App
az functionapp show \
  --name my-logic-app \
  --resource-group my-rg \
  --query "outboundIpAddresses"

# Check NSG flow logs
az network nsg show \
  --name my-nsg \
  --resource-group my-rg

Azure Integration Hub - Advanced Level