public by default
is the ingress configuration when Container Apps are deployed without explicit network settings -- any Container App with external ingress enabled is accessible from the internet without IP restriction, authentication, or WAF protection
internal ingress
restricts the Container App to traffic from within the virtual network only -- the app receives a private FQDN accessible only from within the VNet or peered networks, removing all external internet exposure
VNet injection
deploys the Container Apps environment into a dedicated subnet within a customer-controlled virtual network, enabling private connectivity to other Azure resources, on-premises networks, and private endpoint configuration for the environment itself
Dapr secret store
component in Container Apps must be configured with Azure Key Vault as the backing store rather than Kubernetes secrets, with managed identity authentication rather than client secrets, to prevent secret exposure through Dapr's HTTP API without authentication

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

Azure Container Apps abstracts the complexity of Kubernetes while providing a managed environment for containerized microservices. The trade-off for that abstraction is that security decisions that would be explicit in a self-managed Kubernetes environment are implicit in Container Apps -- and the implicit defaults favor accessibility over restriction.

By default, a Container App with external ingress enabled is accessible from the internet. There is no IP restriction, no WAF, no authentication requirement at the ingress layer (unless the application itself implements authentication), and no network isolation from other Container Apps environments in the same region. For a development workload, this is acceptable. For a production workload handling sensitive data, it is not.

The networking model for Container Apps has two layers of configuration. The environment level -- whether the Container Apps environment is deployed into a customer-managed virtual network or uses the Microsoft-managed shared network infrastructure -- determines the fundamental network isolation model. The app level -- external vs. internal ingress, IP restriction rules, traffic splitting -- controls how individual apps within the environment are exposed.

This guide covers the environment-level VNet injection pattern that provides private network isolation, the app-level ingress configuration that restricts exposure, the Application Gateway integration that provides WAF and IP restriction upstream of the Container Apps environment, Dapr security configuration for Container Apps that use the Dapr sidecar, and the Azure Policy definitions that enforce these requirements at the organization level.

Default Container Apps Ingress: What Is Exposed and Why

Understanding the default exposure helps scope the hardening work required.

Default environment (consumption plan, no VNet injection). When a Container Apps environment is created without specifying a virtual network, it is deployed into a Microsoft-managed shared network infrastructure. The environment receives a shared outbound IP and a managed ingress IP. Container Apps with external ingress enabled in this configuration are accessible from the internet on the environment's public IP. There is no network isolation between this environment and other tenants' Container Apps environments at the network layer -- isolation relies on the Container Apps platform's logical isolation, not network-level isolation.

External ingress by default. When a Container App is deployed with the Azure CLI using az containerapp create without specifying --ingress internal, it defaults to external ingress if ingress is enabled. The resulting FQDN (e.g., myapp.azurecontainerapps.io) resolves to a public IP and is accessible from any internet source with no restriction.

No IP restriction without explicit configuration. External Container Apps have no default IP restriction. The equivalent of a security group or firewall rule blocking traffic to the ingress does not exist without explicit configuration of either: IP security restrictions in the ingress configuration (available in the environment), or an upstream WAF/Application Gateway.

Authentication not provided by default. Container Apps supports Easy Auth (Azure AD-integrated authentication) but it is not enabled by default. An external Container App that does not implement application-layer authentication and does not have Easy Auth enabled accepts unauthenticated requests from any internet source.

Dapr sidecar API exposed within the environment. If Dapr is enabled for a Container App, the Dapr sidecar HTTP API (port 3500) is accessible to other apps within the same Container Apps environment. By default, there is no per-app Dapr API authentication -- any app in the environment can call the Dapr API of any other app.

Restricting Ingress to Internal Traffic Only

For Container Apps that do not need external internet access, internal ingress is the appropriate configuration. Internal ingress makes the Container App accessible only from within the virtual network.

Setting internal ingress via Azure CLI:

az containerapp ingress update \
  --name myapp \
  --resource-group myresourcegroup \
  --type internal

With internal ingress, the Container App receives a private FQDN in the format myapp.internal.[environment-domain] that resolves to a private IP address within the Container Apps environment's subnet. This FQDN is only resolvable and accessible from within the virtual network.

Setting internal ingress in Bicep:

resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
  name: 'myapp'
  properties: {
    configuration: {
      ingress: {
        external: false
        targetPort: 8080
        transport: 'http'
      }
    }
  }
}

The external: false setting is the critical parameter.

VNet injection requirement for internal ingress to be meaningful. Internal ingress restricts accessibility to within the Container Apps environment's network. If the environment is not VNet-injected (not deployed into a customer-managed virtual network), "internal" means accessible from within Microsoft's shared network for that region -- other Container Apps environments in the same region potentially. For meaningful internal ingress isolation, the Container Apps environment must be deployed with VNet injection so that the internal network is your organization's controlled virtual network.

Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Virtual Network Integration and Private Endpoint Configuration

VNet injection deploys the Container Apps environment into a dedicated subnet within a customer-controlled Azure virtual network. This provides network-level isolation and enables connectivity to other Azure resources, on-premises networks, and private endpoint configuration.

Requirements for VNet-injected environment:

  • Dedicated subnet with a minimum /23 CIDR (512 addresses) for Consumption plan environments
  • Subnet must be delegated to Microsoft.App/environments
  • No other resources in the dedicated subnet
  • The subnet must have outbound internet access if the Container Apps need to pull images from public registries or access external services

Creating a VNet-injected environment:

az containerapp env create \
  --name myenvironment \
  --resource-group myresourcegroup \
  --location eastus \
  --infrastructure-subnet-resource-id /subscriptions/[subid]/resourceGroups/[rg]/providers/Microsoft.Network/virtualNetworks/[vnet]/subnets/[subnet] \
  --internal-only true

The --internal-only true flag makes the environment's load balancer internal-only (no public IP on the environment's ingress), requiring all traffic to enter through the virtual network.

Private endpoint for the Container Apps environment. For environments that need to be accessed from on-premises networks without traversing the public internet, configure a private endpoint for the Container Apps environment in a separate subnet:

az network private-endpoint create \
  --name myenv-pe \
  --resource-group myresourcegroup \
  --vnet-name myvnet \
  --subnet pe-subnet \
  --private-connection-resource-id [containerapp-env-resource-id] \
  --group-id managedEnvironments \
  --connection-name myenv-connection

Then create a Private DNS Zone for azurecontainerapps.io linked to the virtual network to ensure DNS resolution of the Container App FQDNs resolves to the private IP.

IP Restriction and WAF Integration via Application Gateway

For Container Apps that must accept external internet traffic, the recommended pattern is to route traffic through Azure Application Gateway with WAF enabled, which provides IP restriction, TLS termination, and OWASP rule-based protection upstream of the Container Apps environment.

Architecture pattern. Deploy the Container Apps environment with internal ingress and VNet injection. Place the Application Gateway in a separate subnet of the same virtual network. Configure Application Gateway to forward requests to the Container App's internal FQDN. External traffic reaches Application Gateway's public IP, traverses the WAF policy, and is forwarded to the internal Container App.

Application Gateway backend pool for Container Apps:

az network application-gateway address-pool create \
  --gateway-name my-appgw \
  --resource-group myresourcegroup \
  --name containerapp-backend \
  --servers myapp.internal.[environment-domain]

The backend pool uses the Container App's internal FQDN. Application Gateway resolves this within the VNet and forwards to the Container App's private IP.

WAF policy configuration. Enable the OWASP 3.2 ruleset on the Application Gateway WAF policy:

az network application-gateway waf-policy create \
  --name my-waf-policy \
  --resource-group myresourcegroup \
  --type OWASP \
  --version 3.2 \
  --state Enabled \
  --mode Prevention

Prevention mode blocks requests that match OWASP rules. Detection mode logs but does not block -- start in Detection mode and review logs for false positives before switching to Prevention.

IP restriction via Application Gateway. Configure custom WAF rules to block traffic from IP ranges not in your allowlist:

az network application-gateway waf-policy custom-rule create \
  --policy-name my-waf-policy \
  --resource-group myresourcegroup \
  --name BlockUnknownSources \
  --priority 100 \
  --rule-type MatchRule \
  --action Block \
  --match-conditions '[{"matchVariables":[{"variableName":"RemoteAddr"}],"operator":"IPMatch","negationConditon":true,"matchValues":["203.0.113.0/24","198.51.100.0/24"]}]'

This blocks any request not originating from the specified IP ranges. Adjust the IP ranges to your allowlisted sources.

Dapr Component Security in Container Apps

Azure Container Apps integrates Dapr as a sidecar. Dapr components (secret stores, state stores, pub/sub, bindings) in Container Apps require specific security configuration to prevent unauthorized access to secrets and state.

Secret store: use Key Vault with managed identity, not component secret files. The Dapr secret store component should be backed by Azure Key Vault with managed identity authentication:

az containerapp env dapr-component set \
  --name myenvironment \
  --resource-group myresourcegroup \
  --dapr-component-name secretstore \
  --yaml - <<EOF
componentType: secretstores.azure.keyvault
version: v1
metadata:
  - name: vaultName
    value: mykeyvault
  - name: azureClientId
    value: [managed-identity-client-id]
EOF

Using managed identity authentication (azureClientId pointing to the Container App's assigned managed identity) eliminates the need for client secrets in the Dapr component configuration. Managed identities are rotated automatically by Azure.

Scoping Dapr components to specific apps. Restrict Dapr components to only the Container Apps that need them using the scopes field:

scopes:
  - myapp-frontend
  - myapp-backend

Without scoping, any app in the Container Apps environment with Dapr enabled can access any Dapr component. Scoping limits component access to named apps only.

Dapr API mTLS between apps. Dapr automatically provisions mTLS between sidecars for service-to-service calls within the environment. Verify that mTLS is not disabled in the Dapr configuration -- the mtls.enabled setting should remain true (the default). Disabling mTLS exposes inter-service communication to network sniffing within the Container Apps environment.

Service invocation access control. Configure Dapr access control policies to restrict which apps can invoke which other apps via Dapr service invocation:

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  accessControl:
    defaultAction: deny
    trustDomain: cluster.local
    policies:
      - appId: myapp-backend
        defaultAction: allow
        namespace: default
        operations:
          - name: /api/data
            httpVerb: ['GET']
            action: allow

The default action of deny requires explicit allow rules for each service-to-service invocation, enforcing least privilege between Container Apps.

Environment-Level Network Isolation Policies

Azure Policy enforces Container Apps network security requirements at the organization or subscription level, preventing deployments that violate security requirements before they reach production.

Policy: Require VNet injection for Container Apps environments. The built-in Azure Policy Container Apps environments should use virtual network injection can be assigned at the subscription or management group level to audit or deny environments created without VNet injection:

az policy assignment create \
  --name require-vnet-injection \
  --scope /subscriptions/[subscription-id] \
  --policy /providers/Microsoft.Authorization/policyDefinitions/[built-in-policy-id] \
  --enforcement-mode Default

Set --enforcement-mode Default (deny mode) to prevent non-compliant environments from being created. Use DoNotEnforce (audit mode) initially to assess the existing environment before enabling enforcement.

Policy: Deny external ingress without WAF. Create a custom policy that denies Container Apps with external ingress enabled if the environment is not fronted by Application Gateway with WAF. This requires a custom policy definition that checks for the presence of an Application Gateway backend pool configuration -- typically implemented as a deny policy on Container Apps with configuration.ingress.external = true without an associated Application Gateway resource tag or parameter.

Network Security Group on the Container Apps subnet. For VNet-injected environments, associate an NSG with the Container Apps subnet that allows:

  • Inbound: TCP 443 from Application Gateway subnet (or Azure Front Door service tag)
  • Inbound: Required Azure infrastructure ports (Container Apps requires specific inbound rules for platform management -- reference the Azure documentation for current required rules)
  • Outbound: TCP 443 to Azure Container Registry (for image pulls), Azure Key Vault, and required Azure services
  • Deny all other inbound and outbound traffic

Do not restrict Container Apps subnet traffic more aggressively than documented -- the platform requires specific connectivity for health checks and management operations.

The bottom line

Azure Container Apps defaults expose ingress publicly without IP restriction, WAF protection, or network isolation -- defaults that are appropriate for development but require explicit hardening for production. The two foundational controls are VNet injection (deploying the Container Apps environment into a customer-controlled virtual network rather than the Microsoft-managed shared network) and internal ingress (restricting the Container App to private FQDN accessible only within the VNet). External traffic should route through Azure Application Gateway with WAF enabled, providing OWASP rule-based protection and IP restriction upstream of the Container Apps environment. Dapr components must use managed identity authentication with Azure Key Vault as the secret store backend, component scoping to limit which apps can access which components, and service invocation access control policies with a default-deny posture. Azure Policy assignments at the subscription or management group level enforce these requirements and prevent non-compliant environments from being deployed.

Frequently asked questions

What is the difference between external and internal ingress in Azure Container Apps?

External ingress makes the Container App accessible from the internet via a public FQDN and public IP. Internal ingress makes the Container App accessible only from within the Container Apps environment's virtual network via a private FQDN that resolves to a private IP. External ingress is the default when ingress is enabled. Internal ingress requires either VNet injection for the environment (so the internal network is your organization's VNet) or explicit internal ingress configuration in the app settings.

What is VNet injection for Azure Container Apps and why is it needed?

VNet injection deploys the Container Apps environment into a customer-owned subnet within an Azure virtual network, rather than into Microsoft's managed shared network infrastructure. Without VNet injection, the environment is on shared Microsoft infrastructure and cannot use private endpoints, cannot access private Azure resources via private IP, and internal ingress means accessible from within Microsoft's shared region network rather than your organization's private network. VNet injection is required for meaningful network isolation, private connectivity to other Azure resources, and Private Endpoint configuration for the Container Apps environment.

Can I use Azure Front Door instead of Application Gateway for WAF and IP restriction?

Yes. Azure Front Door Premium provides WAF capabilities, DDoS protection, and global load balancing, and can be positioned in front of Container Apps environments. The architecture differs from Application Gateway: Front Door operates at the edge (global) rather than within the virtual network (regional). For Container Apps with VNet injection and internal ingress, Front Door requires the Private Link integration to reach the internal environment without exposing it publicly. Application Gateway is simpler for regional deployments where VNet adjacency is acceptable; Front Door is preferred for globally distributed deployments or when edge DDoS protection is a requirement.

What ports does Azure Container Apps require for platform management?

The Container Apps platform requires specific inbound connectivity to the environment's subnet for health checks, platform management, and Kubernetes control plane communication. Microsoft documents the required ports in the Container Apps networking documentation. The requirements include inbound from the AzureLoadBalancer and AzureCloud service tags on specific ports. If an NSG on the Container Apps subnet blocks these ports, the environment may enter a failed state or health checks may fail. Always reference the current Microsoft documentation for required NSG rules rather than inferring them, as they can change with platform updates.

How does Dapr mTLS work in Azure Container Apps?

Dapr automatically provisions mutual TLS (mTLS) between sidecars for service-to-service communication within the Container Apps environment. Each Dapr sidecar receives a certificate issued by the Dapr control plane. When App A calls App B via Dapr service invocation, the Dapr sidecars on both apps authenticate each other using these certificates before establishing the connection. The mTLS configuration is managed by the Dapr control plane embedded in the Container Apps environment -- you do not need to provision certificates manually. The critical configuration requirement is to not disable mTLS, which would expose inter-service traffic to network inspection within the environment.

What is Easy Auth in Azure Container Apps and how does it differ from application-layer authentication?

Easy Auth (Azure App Service Authentication) in Container Apps is a platform-managed authentication middleware that validates Azure AD (Entra ID) tokens before requests reach the application container. It handles token validation, session management, and authentication redirect flows without requiring changes to the application code. Application-layer authentication is authentication implemented within the containerized application itself. Easy Auth is appropriate for protecting internal tools and APIs accessed by Azure AD users; application-layer authentication is more flexible and supports custom authentication schemes. Easy Auth does not restrict which Azure AD users can access the app (all valid Azure AD users can authenticate by default unless groups-based authorization is added).

Sources & references

  1. Microsoft: Azure Container Apps Networking Overview
  2. Microsoft: Azure Container Apps Ingress Configuration
  3. Microsoft: Dapr Integration in Azure Container Apps
  4. Microsoft: Secure a Custom HTTPS Domain with Azure Container Apps

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.