Skip to content

Public Ingress with Application Gateway

Network-isolated deployments keep Container Apps private by default. The Container Apps environment is internal-only and is normally reached from inside the virtual network, for example from the jumpbox.

Use Public Ingress when one Container App needs a controlled public entry point. The Bicep template provisions Azure Application Gateway WAF v2 in front of the private Container Apps environment, without making the environment itself public.

This is a configuration reference, not another landing-zone deployment procedure. Apply its reviewed parameter changes through Deploy infrastructure only or Deploy the full stack.

Cost and teardown

Application Gateway WAF v2 and Standard Public IP incur hourly charges while deployed. Turning publicIngress.enabled back to false does not delete resources that were already created by an incremental ARM deployment. Use azd down for full teardown, or manually delete the gateway, Public IP, WAF policy, NSG, and gateway identity.

What gets created

When publicIngress.enabled=true, and the deployment also has networkIsolation=true, deployContainerEnv=true, deployContainerApps=true, and at least one app in containerAppsList, the template creates:

Resource Purpose
Application Gateway WAF v2 Public HTTPS entry point for one Container App backend.
Standard Public IP Public address for the gateway.
WAF policy Managed WAF rules, using Prevention mode by default.
User-assigned identity Lets Application Gateway read the TLS certificate from Key Vault.
NSG for AppGatewaySubnet Keeps the gateway closed until source CIDRs are configured.
Diagnostic settings Sends gateway logs and metrics to Log Analytics.

The backend defaults to the first app in containerAppsList. Use publicIngress.backendAppIndex to point to a different app.

Operating states

Public Ingress is intentionally a two-step workflow.

State Configuration Behavior
Skeleton mode enabled=true, but frontendHostName or sslCertSecretId is empty The gateway resources exist, but Internet traffic is not opened through the NSG.
Live mode enabled=true, frontendHostName and sslCertSecretId are set, and allowed source CIDRs are provided HTTPS on 443 is enabled, HTTP redirects to HTTPS, and only configured CIDRs can reach the gateway.

This keeps the post-provision configuration in source control instead of relying on portal edits that can be overwritten later.

Gateway skeleton configuration

In main.parameters.json, enable Public Ingress:

"publicIngress": {
  "value": {
    "enabled": true
  }
}

Apply this through the canonical provisioning step, then capture PUBLIC_INGRESS_PUBLIC_IP from its outputs or the resource-group deployment outputs in the Azure portal.

Hostname and certificate ownership

Choose the public hostname, for example:

app.contoso.com

From the jumpbox, use the ACME client installed by the bootstrap script:

C:\tools\win-acme\wacs.exe

Use a DNS-01 flow with your DNS provider, then import the certificate into the landing-zone Key Vault. The jumpbox managed identity has the Key Vault certificate permissions needed for this workflow.

After import, copy the versionless Key Vault secret URI for the certificate:

https://<key-vault-name>.vault.azure.net/secrets/<certificate-name>

Use the versionless URI, not a URI that includes a certificate version.

Public DNS

In your public DNS provider, create or update an A record:

Record Value
app.contoso.com PUBLIC_INGRESS_PUBLIC_IP

Wait for DNS propagation before validating the endpoint.

Live configuration

Update main.parameters.json with the hostname, certificate secret URI, and source CIDRs that are allowed to reach the gateway:

"publicIngress": {
  "value": {
    "enabled": true,
    "frontendHostName": "app.contoso.com",
    "sslCertSecretId": "https://<key-vault-name>.vault.azure.net/secrets/<certificate-name>",
    "allowedSourceAddressPrefixes": ["203.0.113.0/24"]
  }
}

Apply the reviewed change through the canonical provisioning step again. The template configures the HTTPS listener, attaches the Key Vault certificate, redirects HTTP to HTTPS, and opens the NSG only for the configured source CIDRs.

Validation expectations

From an allowed source:

curl -v https://app.contoso.com/
curl -v http://app.contoso.com/

Expected behavior:

Test Expected result
https://app.contoso.com/ Returns the Container App response.
http://app.contoso.com/ Redirects to HTTPS.
Source outside allowedSourceAddressPrefixes Cannot reach the gateway on 443.

Parameter reference

publicIngress: {
  enabled: bool
  backendAppIndex: int?
  frontendHostName: string?
  sslCertSecretId: string?
  allowedSourceAddressPrefixes: string[]?
  wafMode: ('Prevention' | 'Detection')?
  wafCustomRules: object[]?
  capacity: object?
  sslPolicy: object?
}
Parameter Default Description
enabled false Master switch for Public Ingress.
backendAppIndex 0 Index into containerAppsList for the backend app.
frontendHostName Empty Public hostname used by the HTTPS listener. Required for live mode.
sslCertSecretId Empty Versionless Key Vault secret URI for the TLS certificate. Required for live mode.
allowedSourceAddressPrefixes [] CIDRs allowed to reach HTTPS on 443. Empty keeps the gateway closed.
wafMode Prevention WAF mode.
wafCustomRules [] Optional custom WAF rules.
capacity { minCapacity: 0, maxCapacity: 2 } Application Gateway autoscale capacity.
sslPolicy {} Optional Application Gateway SSL policy block.

Useful outputs

Output Description
PUBLIC_INGRESS_ENABLED Whether Public Ingress was deployed.
PUBLIC_INGRESS_PUBLIC_IP Public IPv4 address for the gateway.
PUBLIC_INGRESS_GATEWAY_RESOURCE_ID Application Gateway resource ID.
PUBLIC_INGRESS_NSG_RESOURCE_ID NSG attached to AppGatewaySubnet.
PUBLIC_INGRESS_WAF_POLICY_RESOURCE_ID WAF policy resource ID.
PUBLIC_INGRESS_IDENTITY_PRINCIPAL_ID Gateway identity principal ID. Use this if an external Key Vault must grant certificate access.
PUBLIC_INGRESS_LIVE true when live mode is active.

Teardown

For full teardown use safe environment removal. If the rest of the landing zone must remain, obtain approval to retire only the gateway resources and dependencies: Application Gateway, Public IP, WAF policy, NSG and gateway identity. Confirm none are shared before deletion.

© 2026 Azure AI Landing Zones