In most Terraform projects you’ll probably be deploying and managing Azure resources within a single Azure Subscription. However, it’s common to structure things across multiple Azure Subscriptions in certain cases. One of these cases in when deploying a Hub and Spoke networking model and separating DEV and PROD environments into separate Azure Subscriptions. This is a case where you may end up having a single Terraform project manage some of the Resource Groups, VNets, and other resources within a single Terraform project managing the Governance or Networking for your environments. There are of course other cases where you may need to manage Azure resources across multiple Azure Subscriptions.
Table of Contents
Define Multiple Azure Providers for Multiple Azure Subscriptions
At these times, you will need to support multiple instances of the azurerm Terraform Provider each targeting a different Azure Subscription. To do this, you can utilize the alias attribute on the provider block in Terraform to have multiple azurerm providers configured for different Azure Subscription and/or different Azure Service Principal credentials (client id / secret).
Deploy to Multiple Azure Subscriptions
When deploying to multiple Azure Subscriptions while using the same credentials, you will define the azurerm provider in the Terraform code by specifying the Azure Subscription ID using the subscription_id argument. This can be done to setup multiple Azure provider instances in the same Terraform project that each target different Azure Subscription. This also requires that the same credentials (either Use or Service Principal) used by multiple providers in the Terraform project has permissions to manage resources in each Azure Subscription as needed.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=3.0.0"
}
}
}
provider "azurerm" {
alias = "dev"
subscription_id = var.dev_sub_id
features {}
}
provider "azurerm" {
alias = "prod"
subscription_id = var.prod_sub_id
features {}
}
If you’re using a single Terraform project to manage Azure resources across multiple Azure Subscriptions, but need to set different credentials for each azurerm provider to use, then you’ll need to configure those credentials appropriately. The next section shows how to do this.
Deploy using Different Service Principals
When each Azure provider is required to use different credentials, you will need a separate Azure Service Principal (client id / secret) for each provider to use, with permissions to manage Azure resources each in only a single Azure Subscription. This helps increase the security of the Service Principals you use to setup your Infrastructure as Code (IaC) deployments.
Below is an example of 2 different provider blocks for the azurerm Terraform provider with the alias attribute set to differentiate them, as they each have different Azure Service Principals configured:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=3.0.0"
}
}
}
provider "azurerm" {
alias = "dev"
subscription_id = var.dev_sub_id
tenant_id = var.dev_tenant_id
client_id = var.dev_client_id
client_secret = var.dev_client_secret
features {}
}
provider "azurerm" {
alias = "prod"
subscription_id = var.prod_sub_id
tenant_id = var.prod_tenant_id
client_id = var.prod_client_id
client_secret = var.prod_client_secret
features {}
}
Keep in mind that the above example uses Input Variables passed to the Terraform Project to define the values that are used to configure the Azure Service Principals to use for each of the azurerm Provider instances authenticate with different Azure Subscriptions.
Deploy to Multiple Azure Subscriptions with Terraform
Once you have multiple azurerm Terraform Providers configured in your Terraform project with the alias attribute set for each, you can then use the provider attribute on resource blocks to tell that resource block to explicitly use a specific azurerm Terraform provider with the alias specified.
Below is an example of a single Terraform project with some code that manages a couple Azure resources across multiple Azure Subscriptions utilizing the azurerm Terraform providers defined in the code example above:
resource azurerm_resource_group "prod_rg" {
provider = azurerm.prod
name = "E1-PROD-RG"
location = "eastus"
}
resource azurerm_virtual_network "prod_vnet" {
provider = azurerm.prod
name = "E1-PROD-VNET"
location = azurerm_resource_group.prod_rg.location
location = azurerm_resource_group.prod_rg.name
# Other attributes defined here...
}
resource azurerm_resource_group "dev_rg" {
provider = azurerm.dev
name = "C1-DEV-RG"
location = "centralus"
}
resource azurerm_virtual_network "dev_vnet" {
provider = azurerm.dev
name = "C1-DEV-VNET"
location = azurerm_resource_group.prod_rg.location
location = azurerm_resource_group.prod_rg.name
# Other attributes defined here...
}
With the resource.provider attribute you’re telling your Terraform code which specific Terraform Provider to use for that resource. By defining multiple azurerm providers with the alias attribute, you are able to setup multiple instances of the azurerm provider to be used within a single Terraform project. This can be done with the azurerm provider or any other Terraform provider as well.
Passing Terraform Provider Alias to Modules
When you write modular and reusable Terraform code with Terraform Modules, the code within the module will likely just be referencing the azurerm Terraform Provider without the use of the provider.alias specifed. Be default, this will cause the Terraform Module to utilize the single default azurerm provider defined. If you have multiple azurerm providers defined using the alias attribute, you can use the providers attribute to configure the Terraform Module being used to target a specific provider instance.
Using the providers attribute on a module block can enable you to still utilize multiple azurerm Terraform Providers in a project that is developed using Terraform Modules.
Below is an example of defining multiple module blocks, each with a different azurerm provider instance specified for it to use:
module "sample-dev" {
source = "./sample-module"
providers = {
azurerm = azurerm.dev
}
}
module "sample-prod" {
source = "./sample-module"
providers = {
azurerm = azurerm.prod
}
}
When using the module.providers attribute to tell the Module which Terraform Provider instance to use, you define it using an object with syntax that allows for multiple providers to be specified for the module. The reason for this is that a single Terraform module could have code in it that manages multiple resources that are a part of multiple different Terraform providers. This enables you to explicitly specify all the different Terraform providers for that module to use in case you have multiple instances of multiple different types of Terraform Providers used in your single Terraform project.
Deploy to Multiple Azure Subscriptions with a “Default” azurerm Provider
The previous examples shows how to define multiple azurerm Terraform Providers using the alias attribute and then explicitly tell a resource or module which Terraform Provider instance to use. However, what if you need to define a “Default” azurerm Terraform Provider you want Terraform to automatically use first, unless you explicitly tell it which provider to use for specific resources or modules? Well, you can easily do this by defining a azurerm Terraform Provider without the alias attribute set and this will be the “Default” provider.
Below is an example of this used:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=3.0.0"
}
}
}
# This is the "Default" provider
provider "azurerm" {
subscription_id = var.dev_sub_id
tenant_id = var.dev_tenant_id
client_id = var.dev_client_id
client_secret = var.dev_client_secret
features {}
}
# This provider uses the "prod" alias
provider "azurerm" {
alias = "prod"
subscription_id = var.prod_sub_id
tenant_id = var.prod_tenant_id
client_id = var.prod_client_id
client_secret = var.prod_client_secret
features {}
}
# Use the "Default" azurerm provider
resource azurerm_resource_group "dev_rg" {
name = "C1-DEV-RG"
location = "centralus"
}
module "sample-dev" {
source = "./sample-module"
}
# Use the azurerm provider with the "prod" alias
resource azurerm_resource_group "prod_rg" {
provider = azurerm.prod
name = "E1-PROD-RG"
location = "eastus"
}
module "sample-prod" {
source = "./sample-module"
providers = {
azurerm = azurerm.prod
}
}
Securely Pass Credentials to Terraform
All the Terraform examples in this article use variables (via var usage) to pass the Azure credentials to the multiple configured Azure providers. This is the best practice when setting up Terraform deployments when it comes to security. Hard coding the client_id and client_secret for the Azure Service Principals in the Terraform code will mean those credentials will get committed to source control and become vulnerable to malicious abuse.
NEVER store Azure Service Principal credentials as plain text in the Terraform code or source control repository!
If you have questions about using input variables in Terraform, please refer to my article titled “Use Terraform Input Variables to Parameterize Infrastructure Deployments“. That article covers what you need to start parameterizing your Terraform code, so you can pass these sensitive Azure Service Principal credentials to the Terraform deployments in a secure fashion.
Happy deploying!
Original Article Source: Terraform: Deploy to Multiple Azure Subscriptions in Single Project written by Chris Pietschmann (If you're reading this somewhere other than Build5Nines.com, it was republished without permission.)

Microsoft Azure Regions: Interactive Map of Global Datacenters
Create Azure Architecture Diagrams with Microsoft Visio
Unlock GitHub Copilot’s Full Potential: Why Every Repo Needs an AGENTS.md File
Azure CLI: List and Set Azure Subscription
IPv4 Address CIDR Range Reference and Calculator






Hi
My module needs to get data from 2 subscriptions. how do you pass 2 azure providers to module?
Use the `providers = { }` method shown in the article to pass the AzureRM provider named `azurerm` to the `module` and add another one with a different name for the second Azure Subscription.
Hello Chris,
Have you tested it? I got the following error:
There is no explicit declaration for local provider name “azurerm” in module…..then Terraform will not apply the plan
Ensure you have the ‘provider’ block configured correctly. And, yes, I have code running in production using this.
resource “azurerm_app_service_virtual_network_swift_connection” “vnet-integration” {
app_service_id = data.azurerm_windows_web_app.app.id
subnet_id = data.azurerm_subnet.vnet-integration.id
}
If I use the default provider it can see the app, but not the subnet. If I use provider with the subnet subscription it can see the subnet, but not the app. The two resources are in seperate subscriptions.
The data calls are using the appropriate providers.
How to make this work?
You need to use the “provider” property on the ‘data’ block for the individual resource to tell it the alias of the Terraform ‘azurerm’ provider instance to use for that specific resource. I hope this helps.
Hello Chris, what would be the right way to use multiple subscriptions with shared external modules where I can add the “provider” variable to the resource.
You would need to build the module to accept and expect multiple providers and their alias when used.