Copied to Clipboard
Inside the module code, do not define a provider block. Just use the standard azurerm resource blocks; the mapping happens at the root level. This ensures your modules remain reusable across different environments. I have seen this fail in clusters with >50 nodes where a missed provider mapping caused a production workload to be deployed into a development subscription, leading to significant security audit failures. To maintain high reliability, consider testing your infrastructure as code.
Best Practices for Naming and Scale
Avoid generic names like azurerm.sub1 or azurerm.secondary. In a production environment with dozens of subscriptions, these names provide zero context and lead to configuration errors. Use functional names that describe the role of the subscription:
azurerm.hub
azurerm.shared_services
azurerm.prod_workload
azurerm.identity_mgmt
In environments with more than 50 subscriptions, managing these aliases in a single providers.tf file becomes brittle. At that scale, I recommend splitting your state files by subscription or using a wrapper tool. This reduces the blast radius of a single terraform apply and decreases the time spent in the "refreshing state" phase, which can otherwise take several minutes.
FAQ
Can I use the same Service Principal for multiple subscriptions?
Yes, as long as that Service Principal has the required RBAC roles (for example, Contributor) across all targeted subscriptions. Terraform handles the switching via the subscription_id field in the provider block.
Do I need to run az account set before running Terraform?
No. When you explicitly define subscription_id in the provider block, Terraform ignores the current active subscription in your Azure CLI session and targets the ID specified in the code.
Does using aliases increase the plan time?
Slightly. Terraform must establish separate API sessions for each provider instance. In very large environments, this can add 10 to 30 seconds to the refresh phase.
Conclusion
Using provider aliases is the only professional way to handle multi-subscription Azure deployments. By separating your Hub and Spoke configurations and explicitly passing providers to your modules, you eliminate the risk of deploying resources to the wrong environment.
Your next steps should be to:
- Audit your current
providers.tf and rename any generic aliases to functional names.
- Check your module calls to ensure
providers = { ... } is being used for all non-default subscriptions.
- Implement data blocks to automate the linkage between Hub and Spoke resources.