Introduction
Azure Container Apps occupies a distinct position in the Azure container portfolio and the way organizations choose to automate its deployment with Terraform reflects that position. The service delivers container-based deployment without requiring the operational overhead of managing Kubernetes clusters, while still exposing features such as auto-scaling, traffic splitting, and Dapr integration. This middle ground between Azure App Service and Azure Kubernetes Service shapes how infrastructure as code is written, because the two primary resources that must be modeled are the Container Apps Environment and the Container App itself. The environment functions as the shared execution plane, analogous to a cluster, and provides networking, logging, and a shared Dapr configuration. The container app is the individual application running within that environment.
When Terraform is used to model this service, the practical reality is that the AzureRM provider historically lacked native support for Azure Container Apps. That gap forced practitioners to combine the well-known AzureRM provider with the recently released AzAPI provider. The AzAPI provider is described as a thin abstraction layer on top of the Azure ARM REST API. It allows the use of any API version provided by Azure’s ARM REST API, which means latest entities and their properties can be used, including entities in public and private previews. The AzAPI provider also supports the same authentication mechanisms as the AzureRM provider. The body property is what makes azapi_resource so special, because the body property is used to specify the entire resource configuration. On top of the properties shown in the snippet above, additional properties exist and the provider documentation can be consulted to explore them.
The Terraform module referenced in the reference material provides a way to deploy a container app in Azure with specific characteristics. The module allows the ability to specify all the parameters of log analytics workspace resource. The container app image can be specified using the image parameter in template block under container_apps variable. For multiple apps, the container parameters can be specified under containers. These capabilities directly affect how teams standardize observability and multi-app deployments without manual duplication.
Private networking adds another layer of complexity that is frequently encountered in enterprise and production scenarios. By default, Azure Container Apps are publicly accessible via the internet. In enterprise and production scenarios, however, apps are often required to be reachable only from within an Azure Virtual Network with zero exposure to the public internet. The full instruction guide for deploying a private Azure Container Apps environment using Terraform is presented as Azure Container Apps – Private Networking with Terraform. The full source code for that approach is located at github.com/azure-way/terraform-container-apps/containerappsprivate. The architecture described in that guide is deliberately simple. There is a virtual network with two subnets. The first subnet is for the Container Apps environment, and the second subnet is for a jump host VM.
Terraform Module for Container App Deployment
The module approach centralizes the definition of the Log Analytics workspace and the container app parameters.
The ability to specify all the parameters of log analytics workspace resource means that workspace retention, SKU, location, tags, and diagnostic settings can be declared in Terraform and reproduced consistently across environments. This control has a real-world consequence for compliance and cost management, because log retention policies can be enforced as code rather than through manual portal changes. It also connects to the broader pattern of using AzureRM for foundational resources such as resource group and log analytics workspace, while delegating the Container Apps specific resources to AzAPI.
The container app image is specified using the image parameter in template block under container_apps variable. This pattern allows a declarative mapping between a Terraform variable and the container image reference that will be deployed. For teams practicing GitOps, changing the image tag in variables is sufficient to trigger a new deployment without editing resource definitions. The impact is reduced drift and clearer audit trails.
For multiple apps, the container parameters are specified under containers. This structure supports foreach expressions and locals, enabling a single template to render multiple container apps from a list of definitions. The contextual connection to the AzAPI provider is that the body property of azapiresource can be built from locals and variables, making the multi-app scenario manageable in a single Terraform project.
Private Networking Architecture with Terraform
Private networking is a recurring requirement that the reference material treats as a dedicated guide.
The guide is presented as the full instruction guide for deploying a private Azure Container Apps environment using Terraform. The core problem it solves is that by default Azure Container Apps are publicly accessible via the internet. In enterprise and production scenarios, apps often need to be reachable only from within the Azure Virtual Network with zero exposure to the public internet.
The What You Will Learn list in the guide includes several specific capabilities. How to configure internalloadbalancer_enabled = true on a Container App Environment is presented as a core step. Why setting Azure Container App as private is not a way to go is highlighted as a common mistake from the beginning of the journey, and the guide explains how to do it properly. How to inject a Container Apps Environment into an Azure Virtual Network is covered. Why a Private DNS Zone is mandatory and how to set it up correctly with Terraform is explained. How to deploy a Windows jump host VM to validate private connectivity is included. The complete, production-ready Terraform code for all resources is provided.
The architecture overview reinforces the subnet split. There is a virtual network with two subnets. The first subnet is for the Container Apps environment, and the second subnet is for a jump host VM. The jump host VM provides a validation path for administrators to confirm that connectivity to the container apps is restricted to the virtual network. The Private DNS Zone is mandatory because Container Apps rely on internal DNS resolution within the virtual network, and without a correctly configured zone, name resolution fails even when network routing is correct.
AzAPI Provider and AzureRM Combination
The combination of providers is the central technical pattern for provisioning Azure Container Apps with Terraform.
The article demonstrates how to provision Azure Container Apps with Terraform utilizing a combination of the well-known AzureRM provider and the recently released AzAPI provider. The AzAPI provider is a thin abstraction layer on top of the Azure ARM REST API. It allows the use of any API version provided by Azure’s ARM REST API, which means the latest entities and their properties can be used, including entities in public and private previews. The AzAPI provider also supports the same authentication mechanisms as the AzureRM provider.
The recently released AzAPI provider brings support for all Azure ARM API entities. It is possible to finally provision Azure Container Apps with Terraform by using both providers. The AzAPI provider is used for way more use-cases than just ACA. It is super handy, and with the corresponding VS Code extension, it is super convenient to describe all parts of a bigger infrastructure.
Authentication is handled with a Service Principal. The project bootstrap step includes authenticating with Azure using a Service Principal. This choice has an impact on CI/CD pipelines, because service principal credentials can be stored as secrets and rotated without human interaction.
Locals and variables are created to describe infrastructure components. The guide covers creating locals and variables, specifying resource group and log analytics workspace with AzureRM, and hands-on use of the AzAPI provider.
The body property is central to the AzAPI approach. The body property makes azapi_resource so special. The body property is used to specify the entire resource configuration. The location property is described for Resource Group, Management Group, Subscription, or Extension as the desired Azure Region where the Azure resource should exist.
Project Bootstrap and File Structure
The practical steps for starting a Terraform project are documented explicitly.
Every folder is a valid Terraform project. All .tf files in the folder, non-recursive, are recognized by Terraform and will be considered for mutating the cloud environment.
The bootstrap steps are:
mkdir aca-terraform && cd aca-terraform
touch meta.tf deps.tf aca.tf variables.tf locals.tf
Next, the Terraform project is configured. Configuration instructions are typically placed in meta.tf.
The project folder name aca-terraform becomes the working directory for state and plan files. The file split between meta.tf, deps.tf, aca.tf, variables.tf, and locals.tf separates provider configuration, dependencies, resource definitions, input variables, and computed values. This separation improves readability and enables reuse.
Resource Group, Log Analytics Workspace, and Environment
Foundational resources are provisioned with AzureRM.
Specify Resource Group and Log Analytics Workspace with AzureRM. The Log Analytics workspace is the sink for Container Apps diagnostics. The ability to specify all the parameters of log analytics workspace resource from the module ensures that workspace configuration is versioned.
The Container Apps Environment is the shared execution plane. The environment provides networking, logging, and a shared Dapr configuration. For private networking scenarios, internalloadbalancer_enabled = true is configured on the Container App Environment. The environment is injected into an Azure Virtual Network, which requires the correct subnet delegation and service endpoint configuration.
Container App Provisioning and Ingress
Provisioning the workload uses AzAPI.
Having a basic understanding of the AzAPI provider, it is possible to explore how to deploy an actual workload to ACA using Terraform. The entire source code shown in the article is located in the Azure Container Apps samples repository on GitHub under 011-deploy-aca-with-terraform.
The container app image is specified using the image parameter in template block under containerapps variable. For multiple apps, container parameters are specified under containers. This allows foreach expressions to render many apps from a single definition.
Ingress setup is part of the guide that covers creating Azure Container Apps environments and apps with Terraform, setting up ingress, configuring auto-scaling, and handling secrets. The guide also covers configuring auto-scaling and traffic splitting, which are native Container Apps capabilities.
After provisioning, Terraform CLI will present the execution plan that outlines which resources will be created in Azure. Confirmation of the plan results in Terraform provisioning infrastructure in Azure.
Validation of the deployment is performed with Azure CLI:
az containerapp list -g rg-aca-terraform \
--query="[].{FQDN:properties.configuration.ingress.fqdn}" \
-otable
The output shows FQDN values such as herogopher.wonderfulbeach-762ce195.westeurope.azurecontainerapps.io and devilgopher.wonderfulbeach-762ce195.westeurope.azurecontainerapps.io. These FQDNs confirm that the ingress configuration and environment provisioning succeeded.
Private Networking Implementation Details
The private networking guide emphasizes correct DNS and validation.
Injecting the Container Apps Environment into an Azure Virtual Network is a core step. The environment must be created with the virtual network integration enabled and the appropriate subnet.
A Private DNS Zone is mandatory. The guide explains why a Private DNS Zone is mandatory and how to set it up correctly with Terraform. Without it, internal name resolution for the container apps fails.
A Windows jump host VM is deployed to validate private connectivity. The jump host resides in the second subnet and allows administrators to test connectivity to the container apps without exposing them to the internet.
The complete, production-ready Terraform code for all resources is provided in the reference repository.
Coverage Summary and Conclusion
What we’ve covered includes several distinct capabilities.
Understand what the AzAPI provider is and when it’s an excellent addition to the AzureRM provider. Authenticated with Azure using a Service Principal. Described all infrastructure components using Terraform and leveraged language features such as variables, locals, and expressions for each. Optionally used the VS Code extension for AzAPI to drive productivity and get precise code completion. Provisioned Azure Container Apps with Terraform.
The conclusion notes that it’s a bummer that AzureRM providers still lack support for Azure Container Apps. Luckily, the new AzAPI provider brings support for all Azure ARM API entities. This reality shapes current best practice, which is to use AzureRM for foundational resources like resource group and log analytics workspace, and AzAPI for Container Apps Environment and Container App resources defined via the body property.
Azure Container Apps sits in the sweet spot between Azure App Service and Azure Kubernetes Service. You get container-based deployment without managing Kubernetes clusters, along with features like auto-scaling, traffic splitting, and Dapr integration. If you want to run containers without the operational overhead of AKS, Container Apps is the best bet.
Conclusion
The combination of Terraform with Azure Container Apps is defined by the interplay between AzureRM and AzAPI, the structure of the Container Apps Environment and Container App resources, and the specific networking requirements for private deployments. The module approach provides centralized control over log analytics workspace parameters and container image specification, including multi-app scenarios via containers blocks. Private networking requires an internal load balancer enabled environment, injection into a virtual network with two subnets, a mandatory Private DNS Zone, and validation via a jump host VM. Project bootstrapping follows a clear file layout with meta.tf for configuration, variables.tf and locals.tf for parameterization, and AzAPI resource definitions that use the body property to specify the entire resource configuration. The AzAPI provider remains the enabling mechanism until native AzureRM support is added, and its thin abstraction over the ARM REST API allows use of the latest API versions and preview features. The result is a repeatable, production-ready path to deploy container apps with Terraform, with optional private connectivity and full observability through Log Analytics.