Skip to content

VNet Integration

Deploy Container Apps in a custom virtual network for network isolation.

Overview

Container Apps can be deployed into a custom VNet to: - Isolate traffic from the public internet - Connect to private resources (databases, storage) - Control ingress/egress with NSG rules

Subnet sizing is not optional

The Container Apps infrastructure subnet must be at least /23. Smaller subnets commonly fail at environment provisioning time.

Architecture

flowchart TD
    subgraph VNet ["Virtual Network (10.0.0.0/16)"]
        subgraph CASubnet ["Container Apps Subnet (10.0.0.0/23)"]
            subgraph Environment ["Container Apps Environment"]
                CA1[App 1]
                CA2[App 2]
                INV[Ingress: Envoy]
            end
        end

        subgraph PESubnet ["Private Endpoint Subnet (10.0.2.0/24)"]
            PE[Private Endpoint]
        end
    end

    subgraph Internet [Public Internet]
        U[User]
    end

    U -- External Ingress --> INV
    INV -- Routing --> CA1
    CA1 -- VNet-Local Call --> CA2
    CA1 -- Private Link --> PE

Portal view: non-integrated baseline for the Bicep example

This screenshot is used here as a visual contrast baseline for the Bicep example in Deploy Container Apps Environment with VNet.

Networking blade showing "General" selected; "Public Network Access" with "Enable: Allows incoming traffic from the public internet." selected; "Virtual network" section reading "This environment isn't integrated"; tab strip lists "General", "Ingress settings", "Request Routing", "Encryption", "Custom DNS Suffix"

[Observed] The Public Network Access section has Enable: Allows incoming traffic from the public internet. selected. The Virtual network section reads This environment isn't integrated. The tab strip lists General, Ingress settings, Request Routing, Encryption, Custom DNS Suffix. No subnet resource ID or CIDR value is visible in the shown content.

[Inferred] The visible This environment isn't integrated text is consistent with the Bicep example in Deploy Container Apps Environment with VNet introducing networking properties that are not shown on this blade. The absence of any visible subnet resource ID value appears to map to the infrastructureSubnetId property in that same example.

[Not Proven] This image does not show the infrastructureSubnetId property from Deploy Container Apps Environment with VNet. It does not show the internal: true vs internal: false choice from Internal vs External Ingress. It does not show the /23 minimum subnet sizing from Overview. It does not show the NSG rules from Network Security Groups. It does not show the private endpoint connectivity discussed in Access Private Resources.

Prerequisites

  • Azure subscription with VNet creation permissions
  • Existing VNet or create new one

Create VNet with Subnets

Container Apps requires a dedicated subnet with minimum /23 CIDR block.

Using Azure CLI:

# Create VNet
az network vnet create \
  --name vnet-containerapp \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --address-prefix 10.0.0.0/16

# Create subnet for Container Apps (minimum /23)
az network vnet subnet create \
  --name snet-containerapp \
  --vnet-name vnet-containerapp \
  --resource-group $RESOURCE_GROUP \
  --address-prefix 10.0.0.0/23
Command Why it is used
az network vnet create ... Creates or inspects networking resources such as VNets, DNS zones, routes, or private endpoints.

Using Bicep:

resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = {
  name: 'vnet-containerapp'
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: ['10.0.0.0/16']
    }
    subnets: [
      {
        name: 'snet-containerapp'
        properties: {
          addressPrefix: '10.0.0.0/23'
        }
      }
    ]
  }
}

Deploy Container Apps Environment with VNet

resource containerAppEnv 'Microsoft.App/managedEnvironments@2023-05-01' = {
  name: 'cae-${baseName}'
  location: location
  properties: {
    vnetConfiguration: {
      infrastructureSubnetId: vnet.properties.subnets[0].id
      internal: false  // true for internal-only access
    }
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logAnalytics.properties.customerId
        sharedKey: logAnalytics.listKeys().primarySharedKey
      }
    }
  }
}

Internal vs External Ingress

For the full ingress model, including the app-level external property, transport selection, TCP rules, headers, and request handling behavior, see Ingress in Azure Container Apps. This section focuses on the environment-level VNet posture.

Mode Description Use Case
internal: false Public IP + VNet Public APIs with VNet backend access
internal: true Private IP only Internal microservices, no public access

Access Private Resources

Once in a VNet, Container Apps can access: - Private Endpoints (Azure SQL, Storage, Key Vault) - VNet-peered resources - On-premises via VPN/ExpressRoute

Treat DNS as part of networking design

Private endpoint connectivity depends on DNS zone linkage and name resolution. Validate DNS records before investigating application code.

Example: Connect to Private Azure SQL

import os
import pyodbc

# Connection string uses private endpoint DNS
conn_str = os.environ['SQL_CONNECTION_STRING']
# Server=myserver.database.windows.net -> resolves to private IP

Network Security Groups

Apply NSG rules to the Container Apps subnet:

resource nsg 'Microsoft.Network/networkSecurityGroups@2023-05-01' = {
  name: 'nsg-containerapp'
  location: location
  properties: {
    securityRules: [
      {
        name: 'AllowHTTPS'
        properties: {
          priority: 100
          direction: 'Inbound'
          access: 'Allow'
          protocol: 'Tcp'
          sourceAddressPrefix: '*'
          sourcePortRange: '*'
          destinationAddressPrefix: '*'
          destinationPortRange: '443'
        }
      }
    ]
  }
}

Troubleshooting

Container can't reach private endpoint

  1. Check DNS resolution inside container
  2. Verify private endpoint is in same/peered VNet
  3. Check NSG rules allow outbound traffic

Public access not working

  1. Verify internal: false in environment config
  2. Check ingress is enabled on container app
  3. Verify FQDN is correctly configured

See Also

Sources