Navigating the End of Azure VM Direct Internet Access: Part 4 - Implementing Azure Load Balancer with Outbound Rules

Azure VM Internet - Load Balancers Outbound Rules

Welcome to another installment of our series addressing the deprecation of direct internet access for Azure Virtual Machines (VMs). Throughout this journey, we’ve explored several robust solutions to maintain and secure outbound internet connectivity:

  1. Part 1: Implemented a NAT Gateway for scalable and simplified outbound connectivity.
  2. Part 2: Deployed an Azure Firewall to enhance security and control over network traffic.
  3. Part 3: Leveraged Network Virtual Appliances (NVAs) for advanced networking capabilities.

In Part 4, we’ll delve into using the Azure Load Balancer with Outbound Rules as an effective method to manage outbound internet traffic for your Azure VMs. This solution not only provides outbound connectivity but also integrates seamlessly with your existing load balancing infrastructure.

Understanding Azure Load Balancer with Outbound Rules

The Azure Load Balancer is a Layer 4 (TCP, UDP) load balancing service that distributes incoming traffic among healthy instances of services in your backend pool. While it’s commonly used for inbound traffic distribution, it also possesses powerful capabilities for managing outbound connections through Outbound Rules.

Why Use Azure Load Balancer for Outbound Connectivity?

  • Consolidated Management: Manage inbound and outbound connectivity within a single load balancer.
  • Consistent Source IP: Ensure that outbound traffic from your VMs appears to come from the same public IP address(es).
  • Port Allocation Control: Define how ports are allocated for outbound connections.
  • Cost-Effective: Utilize existing load balancer configurations without incurring additional costs for separate NAT solutions.
  • High Availability: The service is built for high throughput and low latency, supporting high-performance scenarios.

Architecting the Network Topology

Designing an effective network layout is crucial. Here’s an illustrative topology:

graph LR; A["Azure Virtual Network & Virtual Machines"] B["Load Balancer Backend Pool"] C["Internet"] A --> B B --> C

Implementation Overview

We’ll cover two scenarios:

  1. Scenario A: You have an existing Standard SKU Load Balancer used for inbound traffic and want to enable outbound connectivity for your VMs.
  2. Scenario B: You need outbound connectivity but don’t require inbound load balancing.

In both cases, we’ll implement outbound rules using the Azure Portal and Azure Resource Manager (ARM) templates via Bicep.

ℹ️

Prerequisites

  • Azure Subscription: An active subscription.
  • Virtual Network (VNet): A VNet with one or more subnets.
  • Virtual Machines: VMs deployed in the subnet that require outbound internet access.
  • Standard SKU Load Balancer: Required for outbound rules; the Basic SKU does not support this feature.

Scenario A: Enabling Outbound Connectivity on an Existing Load Balancer

Step 1: Verify Your Load Balancer SKU

Ensure your load balancer is of the Standard SKU.

  • Navigate to Load Balancers in the Azure Portal.
  • Select your load balancer.
  • Check the SKU under the Overview section.

Note: If you have a Basic SKU load balancer, you need to upgrade to Standard SKU or create a new one.

Step 2: Configure Backend Pool

Ensure your VMs are part of the load balancer’s backend pool.

  • In your load balancer, select Backend pools.
  • Add or verify that your VMs’ network interfaces are associated with the backend pool.

Step 3: Create an Outbound Rule

  1. Navigate to Outbound Rules:
    • In the load balancer settings, select Outbound rules.
    • Click on + Add to create a new rule.
  2. Configure the Outbound Rule:
    • Name: Enter a name, e.g., OutboundRule1.
    • Outbound Rule Type: Choose Load balancer.
    • Frontend IP Configuration:
      • Select your load balancer’s frontend IP.
      • If you don’t have one, create a new Public IP address.
    • Backend Pool:
      • Select the backend pool containing your VMs.
    • Protocol: Choose All (or specify TCP / UDP as needed).
    • Idle Timeout: Default is 4 minutes, adjust if necessary.
    • SNAT Port Allocation:
      • Automatic: Azure manages port allocation.
      • Manual: Specify the number of SNAT ports per VM instance.
        • Useful for high-connection scenarios.
        • Recommended to use automatic unless you have specific requirements.
    • Enable TCP Reset on Idle Timeout: Optionally enable for faster connection recovery.
  3. Review and Add:
    • Review your settings.
    • Click “Add” to create the outbound rule.

Step 4: Verify Outbound Connectivity

  1. Connect to a VM:
    • Use RDP (Windows) or SSH (Linux) to access a VM in the backend pool.
  2. Check Outbound IP Address:
    • From the VM, open a web browser (Windows) or curl (Linux).
    • Navigate to ifconfig.me or ident.me.
    • Verify that the reported IP address matches the load balancer’s frontend public IP.

Congratulations! Your VMs now have outbound internet access through the Azure Load Balancer.


Scenario B: Configuring Outbound-Only Load Balancer

If you don’t require inbound load balancing but need outbound internet connectivity with control over the source IP, you can create a load balancer solely for outbound purposes.

Step 1: Create a Standard SKU Public IP Address

  1. Navigate to Public IP Addresses:
    • In the Azure Portal, search for “Public IP addresses”.
  2. Create a New Public IP:
    • Click "+ Create".
    • Basics Tab:
      • Subscription: Your subscription.
      • Resource Group: Select or create a new one.
      • Name: myOutboundPublicIP.
      • Region: The same region as your VNet.
      • SKU: Standard.
      • IP Version: IPv4.
      • Assignment: Static.
    • Click “Review + Create” and then “Create”.

Step 2: Create a Standard SKU Load Balancer

  1. Navigate to Load Balancers:
    • Search for “Load balancers”.
  2. Create a New Load Balancer:
    • Click "+ Create".
    • Basics Tab:
      • Subscription: Your subscription.
      • Resource Group: Same as above.
      • Name: myOutboundLoadBalancer.
      • Region: Same as your VNet.
      • SKU: Standard.
      • Type: Public.
      • Public IP Address: Select myOutboundPublicIP.
    • Click “Review + Create” and then “Create”.

Step 3: Create a Backend Pool

  1. Navigate to Your Load Balancer:
    • Go to Load Balancers and select myOutboundLoadBalancer.
  2. Add Backend Pool:
    • Select Backend pools.
    • Click "+ Add".
    • Name: myBackendPool.
    • Backend Pool Configuration:
      • Virtual Network: Select your VNet.
      • Associated to: Virtual machines.
      • Virtual Machines: Add your VMs.
      • IP Version: IPv4.
    • Click “Add”.

Step 4: Create an Outbound Rule

Follow the same steps as in Scenario A, ensuring you select myBackendPool and myOutboundPublicIP.

Step 5: Update Network Security Groups (NSGs)

Ensure that outbound internet traffic is allowed:

  • Outbound Rules:
    • Default allows outbound internet traffic; if modified, ensure ports are open.
  • Inbound Rules:
    • If necessary, restrict inbound traffic since this load balancer is for outbound use only.

Step 6: Verify Outbound Connectivity

Repeat the verification steps from Scenario A.


Implementing with Bicep

For those preferring Infrastructure as Code (IaC), here’s how to implement the outbound load balancer using a Bicep template.

Prerequisites

  • Azure CLI: Latest version with Bicep support.
  • Text Editor: Visual Studio Code with Bicep extension recommended.

Step 1: Write the Bicep Template

Create a file named outboundLoadBalancer.bicep.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Parameters
@description('Location for all resources')
param location string = resourceGroup().location

@description('Azure Virtual Network Name')
param vnetName string = 'myVNet'

@description('Azure Virtual Network Subnet Name')
param subnetName string = 'mySubnet'

@description('Name of the Load Balancer')
param loadBalancerName string = 'myOutboundLoadBalancer'

@description('Azure LoadBalancer Public IP Name')
param lbPublicIPName string = 'myOutboundLB-PublicIP'

@description('Name of the Backend Pool')
param backendPoolName string = 'myBackendPool'

@description('Virtual Machine Name')
param virtualMachineName string = 'myVirtualMachine'

@description('Virtual Machine Login Username')
param adminUsername string = 'azureuser'

@description ('Virtual Machine User Password')
@secure()
param adminPassword string

// 1. Virtual Network with a default subnet
resource vnet 'Microsoft.Network/virtualNetworks@2024-05-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: subnetName
        properties: {
          addressPrefix: '10.0.0.0/24'
        }
      }
    ]
  }
}

// 2. Public IP for the Load Balancer frontend
resource lbPublicIP 'Microsoft.Network/publicIPAddresses@2024-05-01' = {
  name: lbPublicIPName
  location: location
  sku: {
    name: 'Standard'
  }
  properties: {
    publicIPAllocationMethod: 'Static'
  }
}

// 3. Load Balancer for outbound access with a backend pool and outbound rule
resource loadBalancer 'Microsoft.Network/loadBalancers@2024-05-01' = {
  name: loadBalancerName
  location: location
  sku: {
    name: 'Standard'
  }
  properties: {
    // Frontend configuration referencing the public IP
    frontendIPConfigurations: [
      {
        name: 'LoadBalancerFrontEnd'
        properties: {
          publicIPAddress: {
            id: lbPublicIP.id
          }
        }
      }
    ]
    // Define the backend pool
    backendAddressPools: [
      {
        name: backendPoolName
      }
    ]
    // Outbound rule so VMs in the backend pool can access the internet
    outboundRules: [
      {
        name: 'LBOutboundRule'
        properties: {
          frontendIPConfigurations: [
            {
              id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', loadBalancerName, 'LoadBalancerFrontend')
            }
          ]
          backendAddressPool: {
            id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', loadBalancerName, backendPoolName)
          }
          protocol: 'All'
          idleTimeoutInMinutes: 5
          allocatedOutboundPorts: 1024
        }
      }
    ]
  }
}

// 4. Network Interface attached to the vNet and associated with the LB backend pool
resource nic 'Microsoft.Network/networkInterfaces@2024-05-01' = {
  name: 'vmNic'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: '${vnet.id}/subnets/default'
          }
          // Associate NIC with the Load Balancer backend pool for outbound connectivity
          loadBalancerBackendAddressPools: [
            {
              id: '${loadBalancer.id}/backendAddressPools/backendPool'
            }
          ]
        }
      }
    ]
  }
}

// 5. Linux Virtual Machine attached to the NIC
resource linuxVM 'Microsoft.Compute/virtualMachines@2024-07-01' = {
  name: 'vm'
  location: location
  properties: {
    hardwareProfile: {
      vmSize: 'Standard_DS1_v2'
    }
    osProfile: {
      computerName: virtualMachineName
      adminUsername: adminUsername
      adminPassword: adminPassword
      linuxConfiguration: {
        disablePasswordAuthentication: false
      }
    }
    storageProfile: {
      imageReference: {
        publisher: 'Canonical'
        offer: 'UbuntuServer'
        sku: '18.04-LTS'
        version: 'latest'
      }
      osDisk: {
        createOption: 'FromImage'
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
  }
}

Step 2: Deploy the Bicep Template

Deploy:

1
2
3
   az deployment group create \\
   --resource-group 'YourResourceGroup' \\
   --template-file outboundLoadBalancer.bicep

Step 3: Verify Deployment

  • Ensure that the load balancer, public IP, and backend pool are created.
  • Check that the NICs are associated with the backend pool.

Step 4: Verify Outbound Connectivity

Repeat the verification steps as previously described.

Additional Considerations

SNAT Port Exhaustion

  • What is SNAT Port Exhaustion?
    • SNAT (Source Network Address Translation) ports are used to map internal private IP addresses and ports to the public IP address and ports.
    • If the number of outbound connections exceeds the available SNAT ports, new connections may fail.
  • Mitigation Strategies:
    • Use Multiple Frontend IPs: Increases the number of available SNAT ports.
    • Manual Port Allocation: Specify the number of ports per instance in the outbound rule.
    • Use NAT Gateway: For high-volume scenarios, consider using a NAT Gateway, which provides more SNAT ports.

Compatibility with Virtual Machine Scale Sets (VMSS)

  • Automatic Backend Pool Association:
    • When using VMSS, instances can be automatically added to the backend pool.
    • Ensure the scale set is associated with the load balancer.

Network Security Groups (NSGs)

  • Outbound Traffic:
    • Default NSG rules allow outbound internet traffic.
    • If you’ve customized NSGs, ensure that outbound traffic to the internet is permitted.

Multi-Region Deployments

  • For high availability, consider deploying load balancers and resources across multiple regions and using Azure Traffic Manager or Front Door.

Conclusion

By implementing an Azure Load Balancer with outbound rules, you’ve established a reliable and scalable method for managing outbound internet connectivity for your Azure VMs. This approach is particularly beneficial if you’re already utilizing load balancers for inbound traffic or seeking a cost-effective solution without introducing additional network components.

Key Takeaways:

  • Unified Solution: Manage inbound and outbound connectivity within a single service.
  • Control and Flexibility: Customize outbound rules to suit your application’s needs.
  • Cost Efficiency: Utilize existing infrastructure to minimize costs.
  • High Availability: Leverage Azure’s robust infrastructure for reliable connectivity.

Learn More