terraform-provider-azurerm: Inconsistent behaviour when specifying `subscription_id` attribute in provider block for new Subscriptions
Is there an existing issue for this?
- I have searched the existing issues
Community Note
- Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
- Please do not leave “+1” or “me too” comments, they generate extra noise for issue followers and do not help prioritize the request
- If you are interested in working on this issue or have submitted a pull request, please leave a comment
Terraform Version
1.2.7
AzureRM Provider Version
3.18.0
Affected Resource(s)/Data Source(s)
azurerm_subscription
Terraform Configuration Files
# Base provider, used to read the billing account and create the new Subscription
provider "azurerm" {
features {}
}
# Data resource to get the billing_scope value
data "azurerm_billing_enrollment_account_scope" "example" {
billing_account_name = local.billing_account_name
enrollment_account_name = local.enrollment_account_name
}
# Create the new Subscription (uses the Microsoft.Subscription/Aliases provider)
resource "azurerm_subscription" "example" {
subscription_name = "My Test Subscription"
alias = "new-sub-test-001"
billing_scope_id = data.azurerm_billing_enrollment_account_scope.example.id
}
# Define a secondary provider with an alias, configured to target the newly created Subscription
provider "azurerm" {
alias = "new_sub"
subscription_id = azurerm_subscription.example.subscription_id
features {}
}
# Create a Resource Group in the newly created Subscription
resource "azurerm_resource_group" "example" {
provider = azurerm.new_sub
name = "new-sub-test"
location = "West Europe"
}
Debug Output/Panic Output
# see below
Expected Behaviour
When trying to create a new Azure Subscription and then cross-referencing the Subscription ID of the new Subscription into a provider
block we expect to see consistent behaviour regardless of the authentication method used.
Actual Behaviour
When authenticating with a Service Principal the initial terraform plan
throws the following error:
â•·
│ Error: building AzureRM Client: 1 error occurred:
│ * A Subscription ID must be configured when authenticating as a Service Principal using a Client Secret.
│
│
│
│ with provider["registry.terraform.io/hashicorp/azurerm"].new_sub,
│ on main.tf line 20, in provider "azurerm":
│ 20: provider "azurerm" {
│
╵
We believe this to be correct, as at this point the new Subscription ID is unknown and therefore cannot be correctly set on the provider.
When we authenticate using the Azure CLI the initial terraform plan
is successful, but we get the following error during terraform apply
:
â•·
│ Error: building AzureRM Client: obtain subscription(00e960fd-76a5-410b-9391-877383a5974f) from Azure CLI: parsing json result from the Azure CLI: waiting for the Azure CLI: exit status 1: ERROR: Subscription '00e960fd-76a5-410b-9391-877383a5974f' not found. Check the spelling and casing and try again.
│
│ with provider["registry.terraform.io/hashicorp/azurerm"].new_sub,
│ on main.tf line 20, in provider "azurerm":
│ 20: provider "azurerm" {
│
╵
We believe in this case that the provider is incorrectly accepting a null or empty string input on the subscription_id
attribute of the provider block and instead defaulting to the current default
Subscription associated with the Azure CLI authenticated user.
This is incorrectly giving customers the illusion that they can create a new Subscription and then deploy resources straight into it within a single apply of a single root module.
Steps to Reproduce
- Create a configuration matching the example, providing valid values for access to the billing account for Subscription create
- Authenticate using a Service Principal with suitable permissions
terraform init
(should work)terraform plan
(should throw error)- Authenticate using Azure CLI with suitable permissions
terraform init
(should work)terraform plan
(should work)terraform apply
(should create new Subscription and then throw error)terraform apply
(should throw the following error)az account list --refresh
(to refresh the list of available Subscriptions)- May need to run
az account set
to select a subscription terraform apply
(should work the second time as the Subscription now exists!)
Important Factoids
n/a
References
I believe this issue identifies the underlying reason why customers are trying to create a new Subscription and then deploy resources to it, only to face issues which surface as issues such as:
We have successfully worked around this situation with our lz-vending module, but this was only made possible as the new AzAPI provider has an option to set the parent_id
for any resource being created,
We believe the addition of a new optional parent_id
argument for all resources in the azurerm provider would allow customers to deploy resources across multiple Subscriptions without hitting this issue (or the need to provide multiple aliased providers).
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 5
- Comments: 17 (9 by maintainers)
@manicminer yeah agreed, I think we should probably look to make
subscription_id
required in 4.0 to alleviate the confusion.There’s been a number of issues where folks have been confused about this behaviour (by having resources provisioned in the wrong subscription or otherwise) - and whilst this behaviour made sense within CloudShell (for learning purposes) - it doesn’t really make sense outside of that environment, so I think it’s worth making this field required going forward.
@manicminer I think you’ve made it clear, I will happily admit I don’t understand all the interactions you describe - they sound like technical debt, and perhaps you could consider this something to address in some future major version bump. It would be fantastic to bring the azure provider up to parity with e.g. the google provider, or the kubernetes provider, in this regard.
Re this bit though:
This is an XY problem I think: out of state subscriptions should be imported; there are existing facilities (now much better since 1.5) for doing declarative imports, and indeed an imported subscription would not show as having an Unknown ID, so should plan and operate entirely fine today. It is only the wholly new case that any putative change would need to solve.
@manicminer, Thank you for your response. This might not be recommended, and yes, we can split the deployment into separate deployments even if that would complicate our use case. Having a single deployment is really something we would like to be supported, a single deployment make sense, and will ease deployments and our use case! Hopefully this is functionality that will have greater support in coming versions, and not less.
As stated above, the deployment runs successfully even with service principal authentication, as long as you run without a remote backend. If I run with local backend, the plan and apply stage runs successfully. If I specify a remote backend, it fails.
I have done some additional testing, it seems that the plan is not checking against the current/default subscription, there is no signs for this in the output (or in the trace log):
Just as an additional verification, I have tried to add the resource group (test) into the default subscription just to see if that changed this behaviour, it did not – this is as expected since I can’t see any trace towards the default subscription that terraform is checking if that resource exists.
So, based on this testing, it seems like the verification of the resource group is not happening towards the default subscription. The issue only occurs if I specify a remote backend in combination with service principal authentication, so I assume there must be an issue related to this combination.
For your reference, I’m using this code to illustrate the issue:
Thanks for raising this @krowlandson and thanks both for the nuanced conversation. I think there’s merit in the idea of requiring a
subscription_id
to always be set regardless of the authentication method. If this were to be considered, it would naturally be considered a breaking change and could only reasonably be enforced in the next major version of the provider.That aside, I’m not sure we can reliably compare between an unset subscription ID and a blank subscription ID - mainly because we also source this from an environment variable and so the unset value is nearly always an empty string AFAICT.
As mentioned above, given an empty
subscription_id
the provider will hit error when authenticated using SP during the plan stage, but not when using the CLI auth (as it will use the default subscription in this case). Ideally, either case should work in @krowlandson’s config, as the second provider is referencing a known-after-apply attribute, which Terraform is able to handle it correctly:The behavior about how provider behaves when referencing such attribute is explained here (though this is for the plugin framework, but it should also apply to the plugin sdk v2). As is stated in the document:
For this provider, IMO it should behave correctly without a subscription id during the plan stage: For existing resources, the subscription id can already be deduced by the resource id; For new resources, there is nothing to be done during plan stage.
Unfortunately, it is a non-trivial work to make the unknown value work for the azurerm provider at this moment. That is because:
For the point 1, I think after we totally migrate to the hashicorp/go-azure-sdk, it should be resolved. For the point 2, I think we can further balance whether we want the dynamic provider config more than those additional features during provider configuration phase.