Skip to content

Egress Control

Control outbound traffic from Container Apps.

Default Behavior

By default, Container Apps can access: - Public internet - Azure services via public endpoints - Resources in the same VNet (if VNet integrated)

Uncontrolled egress increases data exfiltration risk

Production workloads should define explicit outbound paths and approved destinations, especially when handling regulated or sensitive data.

Egress Strategy Comparison

Strategy Primary Goal Trade-off Typical Fit
Default outbound Fast setup Minimal governance Dev/test environments
UDR + Azure Firewall Domain/IP filtering and inspection Higher complexity and cost Regulated production workloads
NAT Gateway Static outbound IP for allow-lists No L7 filtering by itself SaaS allow-list integrations

User-Defined Routes (UDR)

Route outbound traffic through Azure Firewall or NVA:

flowchart LR
    subgraph VNet [Virtual Network]
        subgraph Subnet [CAE Subnet]
            APP[Container App]
        end

        subgraph FWSubnet [AzureFirewallSubnet]
            FW[Azure Firewall]
        end

        subgraph RT [Route Table]
            R[0.0.0.0/0 -> Firewall IP]
        end
    end

    subgraph Internet [Public Internet]
        EXT[Public API]
    end

    APP -- 1. Outbound Request --> RT
    RT -- 2. Next Hop --> FW
    FW -- 3. Policy Check --> EXT
resource routeTable 'Microsoft.Network/routeTables@2023-05-01' = {
  name: 'rt-containerapp'
  location: location
  properties: {
    routes: [
      {
        name: 'default-route'
        properties: {
          addressPrefix: '0.0.0.0/0'
          nextHopType: 'VirtualAppliance'
          nextHopIpAddress: firewallPrivateIp
        }
      }
    ]
  }
}

Azure Firewall Rules

Allow required outbound traffic:

NAT Gateway Architecture

flowchart TD
    subgraph VNet [Virtual Network]
        subgraph Subnet [CAE Subnet]
            APP[Container App]
        end

        NGW[NAT Gateway]
        PIP[Public IP Address]
    end

    subgraph Internet [Public Internet]
        EXT[Public Dependency]
    end

    APP -- 1. Outbound Traffic --> NGW
    NGW -- 2. Source NAT (PIP) --> EXT
resource firewallPolicy 'Microsoft.Network/firewallPolicies@2023-05-01' = {
  name: 'fw-policy'
  properties: {
    sku: { tier: 'Standard' }
  }
}

Azure Firewall Rules

Allow required outbound traffic:

resource firewallPolicy 'Microsoft.Network/firewallPolicies@2023-05-01' = {
  name: 'fw-policy'
  properties: {
    sku: { tier: 'Standard' }
  }
}

resource appRuleCollection 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2023-05-01' = {
  parent: firewallPolicy
  name: 'container-apps-rules'
  properties: {
    priority: 100
    ruleCollections: [
      {
        ruleCollectionType: 'FirewallPolicyFilterRuleCollection'
        name: 'allow-external-apis'
        priority: 100
        action: { type: 'Allow' }
        rules: [
          {
            ruleType: 'ApplicationRule'
            name: 'allow-jsonplaceholder'
            protocols: [{ protocolType: 'Https', port: 443 }]
            targetFqdns: ['jsonplaceholder.typicode.com']
            sourceAddresses: ['10.0.0.0/23']
          }
        ]
      }
    ]
  }
}

NAT Gateway for Static Outbound IP

Assign static IP for outbound traffic:

resource natGateway 'Microsoft.Network/natGateways@2023-05-01' = {
  name: 'nat-containerapp'
  location: location
  sku: { name: 'Standard' }
  properties: {
    publicIpAddresses: [{ id: publicIp.id }]
  }
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-05-01' = {
  name: 'snet-containerapp'
  properties: {
    addressPrefix: '10.0.0.0/23'
    natGateway: { id: natGateway.id }
  }
}

Combine NAT and firewall when needed

Use NAT Gateway for predictable source IP and Azure Firewall for destination governance when both compliance and partner allow-list requirements exist.

Verify Outbound IP

import requests

@app.route('/api/my-ip')
def my_ip():
    # Use standard service to verify public outbound IP
    response = requests.get('https://api.ipify.org?format=json')
    return response.json()  # Returns NAT Gateway's public IP

See Also

Sources