terraform icon indicating copy to clipboard operation
terraform copied to clipboard

Backend/azure: `subscription_id` infer from Azure CLI & a way to skip *unnecessary* management plane API call

Open magodo opened this issue 10 months ago • 9 comments

This PR consists of two changes:

  1. Infer subscription_id from Azure CLI if not specified. The subscription_id is required since terraform-provider-azurerm v4 (see: https://github.com/hashicorp/terraform-provider-azurerm/pull/26621). My last PR https://github.com/hashicorp/terraform/pull/36258 aligns this with the azurerm provider, whilst causing breaking changes unfortunately.

    The commit https://github.com/hashicorp/terraform/commit/0c57798b9ab378fc9f4f03f8b8459697c6a4a774 chooses to fallback to the Azure CLI default subscription, only if the user is using CLI to authenticate.

    If the maintainer accepts breaking change and is fine to align with the azurerm behavior, I'll revert the above commit and mark subscription_id as required.

  2. Avoid management plane call if not necessary.

    There are four auth scenarios of the blob/container:

    1. User specifies the SAS token
    2. User specifies the shared access key
    3. User specified to use AAD auth (and credential provided)
    4. None of the above, management plane API call needed to list the shared access key and use it to auth

    For 1, 2 and 3, the management plane API can be skipped in most of the cases, except the target storage account is using ~private~ DNS zone endpoint. The blob/container data plane client requires the user to specify the base URI, which is not deterministic if the storage account opt in the ~private~ DNS zone endpoint. In this case, an additional management plane GET is required against the storage account, to retrieve the blob endpoint. While if ~private~ DNS zone endpoint is not used, the base URI can be composed in a fixed pattern, with the storage account name and container&blob name. Hence no management plane API call is needed.

    The user is expected to use the subscription_id and resource_group_name to indicate the above intent: Only if both are specified, the additional GET call will be invoked to get the accurate blob endpoint.

    (NOTE: the subscription_id can be inferred from the Azure CLI if unspecified)

Fixes #36596 Fixes #36595

Target Release

1.11.1

Test

Unit Test

$ TF_ACC=1 go test -timeout=20h -parallel=20 ./...
PASS
ok      github.com/hashicorp/terraform/internal/backend/remote-state/azure      217.074s

Scenario Test

The following test is done locally, with an empty terraform state stored in a storage blob. The goal is to test that the management plane APIs are called as expected.

SAS auth without resource_group_name specified

Expect no management plane API.

terraform {
  backend "azurerm" {
    storage_account_name = "acctesttfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    sas_token            = "****"
  }
}
💤  httptap -- ~/go/bin/terraform plan
╷
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI configuration:
│  - magodo/restful in /home/magodo/go/bin
│  - magodo/demo in /home/magodo/go/bin
│  - hashicorp/azurerm in /home/magodo/go/bin
│
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (181 bytes)
Acquiring state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 201 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (181 bytes)

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
Releasing state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)

SAS auth with resource_group_name specified

Expect management plane API.

terraform {
  backend "azurerm" {
    resource_group_name  = "acctest-tfstate"
    storage_account_name = "acctesttfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    sas_token            = "****"
  }
}
💤  httptap -- ~/go/bin/terraform plan
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> GET https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate?api-version=2023-01-01
<--- 200 https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate?api-version=2023-01-01 (1733 bytes)
╷
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI configuration:
│  - hashicorp/azurerm in /home/magodo/go/bin
│  - magodo/restful in /home/magodo/go/bin
│  - magodo/demo in /home/magodo/go/bin
│
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (181 bytes)
Acquiring state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 201 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (181 bytes)

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Releasing state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=****
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease&sv=2022-11-02&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-03-04T14:48:43Z&st=2025-03-04T06:48:43Z&spr=https&sig=**** (0 bytes)

Shared access key auth without resource_group_name specified

Expect no management plane API.

terraform {
  backend "azurerm" {
    storage_account_name = "acctesttfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    access_key           = "****"
  }
}
💤  httptap -- ~/go/bin/terraform plan
╷
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI configuration:
│  - hashicorp/azurerm in /home/magodo/go/bin
│  - magodo/restful in /home/magodo/go/bin
│  - magodo/demo in /home/magodo/go/bin
│
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
Acquiring state lock. This may take a few moments...
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 201 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Releasing state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)

Shared access key auth with resource_group_name specified

Expect management plane API.

terraform {
  backend "azurerm" {
    resource_group_name  = "acctest-tfstate"
    storage_account_name = "acctesttfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    access_key           = "****"
  }
}
💤  httptap -- ~/go/bin/terraform plan
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> GET https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate?api-version=2023-01-01
<--- 200 https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate?api-version=2023-01-01 (1733 bytes)
╷
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI configuration:
│  - hashicorp/azurerm in /home/magodo/go/bin
│  - magodo/restful in /home/magodo/go/bin
│  - magodo/demo in /home/magodo/go/bin
│
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
Acquiring state lock. This may take a few moments...
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 201 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Releasing state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)

AAD auth with CLI without resource_group_name specified

Expect no management plane API.

terraform {
  backend "azurerm" {
    storage_account_name = "acctesttfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    use_azuread_auth     = true
  }
}
$  httptap ~/go/bin/terraform plan
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)
Acquiring state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 201 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
Releasing state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)

AAD auth with CLI with resource_group_name specified

Expect management plane API.

terraform {
  backend "azurerm" {
    resource_group_name  = "acctest-tfstate"
    storage_account_name = "acctesttfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    use_azuread_auth     = true
  }
}
💤  httptap -- ~/go/bin/terraform plan
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> GET https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate?api-version=2023-01-01
<--- 200 https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate?api-version=2023-01-01 (1733 bytes)
╷
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI configuration:
│  - hashicorp/azurerm in /home/magodo/go/bin
│  - magodo/restful in /home/magodo/go/bin
│  - magodo/demo in /home/magodo/go/bin
│
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
Acquiring state lock. This may take a few moments...
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 201 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
Releasing state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)

No auth method specified, defaults to listing shared access key and use it

Expect management plane API call

terraform {
  backend "azurerm" {
    resource_group_name  = "acctest-tfstate"
    storage_account_name = "acctesttfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
  }
}
💤  httptap -- ~/go/bin/terraform plan
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> POST https://dc.services.visualstudio.com/v2/track
<--- 200 https://dc.services.visualstudio.com/v2/track (62 bytes)
---> GET https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate?api-version=2023-01-01
<--- 200 https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate?api-version=2023-01-01 (1733 bytes)
╷
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI configuration:
│  - magodo/restful in /home/magodo/go/bin
│  - magodo/demo in /home/magodo/go/bin
│  - hashicorp/azurerm in /home/magodo/go/bin
│
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
---> POST https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate/listKeys?%24expand=kerb&api-version=2023-01-01
<--- 200 https://management.azure.com/subscriptions/****/resourceGroups/acctest-tfstate/providers/Microsoft.Storage/storageAccounts/acctesttfstate/listKeys?%24expand=kerb&api-version=2023-01-01 (380 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
Acquiring state lock. This may take a few moments...
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 201 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> GET https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (181 bytes)

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Releasing state lock. This may take a few moments...
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> HEAD https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=metadata (0 bytes)
---> PUT https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease
<--- 200 https://acctesttfstate.blob.core.windows.net/tfstate/prod.terraform.tfstate?comp=lease (0 bytes)

CHANGELOG entry

  • [ ] This change is user-facing and I added a changelog entry.
  • [ ] This change is not user-facing.

magodo avatar Mar 04 '25 05:03 magodo

@magodo For clarity, where you mention private dns zone, this is the Azure DNS zone endpoints preview feature: https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview#azure-dns-zone-endpoints-preview? I believe these are public DNS zones? Just want to avoid confusion for anyone using private endpoints, which do require private dns zones, but don't require the management API call.

Further, this is still a breaking change for most users, since up until now supplying resource_group_name and subscription_id have been required.

An alternative solution here could be to have an explicit setting to look up the endpoint for those customers using the preview feature. Something like use_endpoint_lookup. That way we can avoid the breaking change altogether for now. I appreciate that resource_group_name and subscription_id are redundant in this scenario. We can update the docs to add clarity around this though and for new users, they can exclude them.

I'm only suggesting this to avoid impacting existing users when they move to 1.11. I feel that the smoother experience for them would be beneficial and the docs can help anyone using the preview feature.

I can help with the docs if you like, as I made the last major update to them.

UPDATE: To be clear, rightly or wrongly, the docs currently indicate that resource_group_name is required:

  • https://developer.hashicorp.com/terraform/language/backend/azurerm#backend-azure-ad-service-principal-or-user-assigned-managed-identity-via-oidc-workload-identity-federation
  • https://developer.hashicorp.com/terraform/language/backend/azurerm#resource_group_name

As such, the majority of people would have included that in their backend config (even if it isn't really required). The breaking change here would be that including resource_group_name now requires an elevated permission on the storage account.

If we can revert to the previous behaviour (where I am guessing it just ignores resource_group_name in this scenario), but add a new setting to enable users of Azure DNS zone endpoints, that would be preferential.

jaredfholgate avatar Mar 04 '25 07:03 jaredfholgate

The starting point for this PR should be the behaviour as per 1.10

i.e. Neither subscription id nor resource group are mandatory.

Managed Identity Principal mode (use_msi = true) does not require subscription id and does not require Azure CLI. It is not covered by your tests

terraform {
  backend "azurerm" {
    storage_account_name = "acctesttfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    use_azuread_auth     = true
    use_msi              = true
  }
}

OIDC auth can work in the same way (use_oidc = true)

We need a 1.11.1 that reverts the breaking change ASAP. Any new functionality can wait until a properly tested 1.12.

rlaveycal avatar Mar 04 '25 09:03 rlaveycal

@magodo For clarity, where you mention private dns zone, this is the Azure DNS zone endpoints preview feature: https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview#azure-dns-zone-endpoints-preview?

You are right, sorry for the wrong wording... I've updated the description of this PR.

Further, this is still a breaking change for most users, since up until now supplying resource_group_name and subscription_id have been required. ...

Unfortunately, the backend document seems not correct in some places. E.g. even When authenticating using a Managed Identity (MSI), the resource_group_name can be unspecified if the SA is authenticating via AAD. The cause of the confusion comes from the fact that there are two layers of authentication: AuthN for ARM/Storage access token, and AuthN for storage account data plane access (incl. access key, SAS and AAD auth).

Regarding the use_endpoint_lookup, I'm hesitate to compliate the matters as the resource_group_name in those cases are redundent to specify. This is more of a undefined/incorrectly defined behavior before, and is out of the scope for compatibility, IMO.

I'll try to summarize all the scenarios and test them out.

A basic illustration about what's going on:

image

(Again, the complexity comes from the fact that mixing AutN for different levels together)

magodo avatar Mar 05 '25 00:03 magodo

@magodo For clarity, where you mention private dns zone, this is the Azure DNS zone endpoints preview feature: https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview#azure-dns-zone-endpoints-preview?

You are right, sorry for the wrong wording... I've updated the description of this PR.

Further, this is still a breaking change for most users, since up until now supplying resource_group_name and subscription_id have been required. ...

Unfortunately, the backend document seems not correct in some places. E.g. even When authenticating using a Managed Identity (MSI), the resource_group_name can be unspecified if the SA is authenticating via AAD. The cause of the confusion comes from the fact that there are two layers of authentication: AuthN for ARM/Storage access token, and AuthN for storage account data plane access (incl. access key, SAS and AAD auth).

Regarding the use_endpoint_lookup, I'm hesitate to compliate the matters as the resource_group_name in those cases are redundent to specify. This is more of a undefined/incorrectly defined behavior before, and is out of the scope for compatibility, IMO.

I'll try to summarize all the scenarios and test them out.

A basic illustration about what's going on:

image

(Again, the complexity comes from the fact that mixing AutN for different levels together)

I understand the docs are incorrect, but if we move forward with this it will impact a lot of people. I appreciate they will just need to remove resource_group_name, but for some customers that could be a significant task. Prior to this, it worked as expected with the settings per the docs. If we move forward with this, we need some way to inform users moving to 1.11.x.

Could be we add a deprecation warning in 1.11.x and then make the breaking change in 1.12.x? My suggestion is:

  • Silently fail on the management plane auth attempt, but show a deprecation warning to users telling them it will start failing in 1.12.x if they don't remove resource_group_name from the config or add the storage account read permissions.
  • Then continue with the data plane auth with the derived URI.

Further suggestions:

I appreciate it is probably too late for this, but I am personally against the inclusion or exclusion of certain parameters to determine auth methods. I think it is confusing for end users and is not transparent. This is proven by the fact that the peer reviewed docs are incorrect, even the people writing it don't know how it works... It would be much better to explicitly specify the auth method they want to use and there is precedent for that already with use_cli, use_oidc, use_azuread_auth, use_msi, etc. Adding a new one for this scenario won't make the situation any worse than it already is.

In the future I think we should consider adding an auth_type variable that takes an input string for one of the auth methods listed in this table: https://developer.hashicorp.com/terraform/language/backend/azurerm#authentication. That way there is no confusion on user intent and the code can tell the user if they are missing a required input.

jaredfholgate avatar Mar 05 '25 09:03 jaredfholgate

@magodo I have created a docs PR that is aligned with the changes as you have proposed them and would work if you decide to use the deprecation approach. I am not 100% sure these are correct, but hoping you and others can review for correctness. Here is the PR: https://github.com/hashicorp/terraform/pull/36641

jaredfholgate avatar Mar 05 '25 12:03 jaredfholgate

@jaredfholgate I agree that nclusion or exclusion of certain parameters to determine different behavior is not a good choice! I'll update the code and flow to be as what it was before, especially for the SA endpoint lookup part, and silently ignore those redundent properties if users have specified.

Meanwhile, I'll add a new attribute to allow users to opt in the endpoint lookup.

magodo avatar Mar 05 '25 23:03 magodo

A new property is introduced: lookup_blob_endpoint. When this is set to true, a GET will be called to the SA to get the exact blob endpoint. Otherwise, the endpoint is constructed in a fixed pattern, hence no storageAccounts/read is needed.

Meanwhile, I've performed the following test.

index AAD Auth Setup 1 Storage Auth Method Lookup EP Succeed or Error storageAccounts/read Needed? storageAccounts/listkeys Needed?
1 N SAS N Y N N
2 N Access Key N Y N N
3 N AAD Auth (Storage) N unable to build authorizer for Storage API - -
4 N Unspecified N unable to build authorizer for Resource Manager API - -
5 N SAS Y unable to build authorizer for Resource Manager API - -
6 N Access Key Y unable to build authorizer for Resource Manager API - -
7 N AAD Auth (Storage) Y unable to build authorizer for Storage API - -
8 N Unspecified Y unable to build authorizer for Resource Manager API - -
9 Y SAS N Y N N
10 Y Access Key N Y N N
11 Y AAD Auth (Storage) N Y N N
12 Y Unspecified N Y Y2 Y
13 Y SAS Y Y Y N
14 Y Access Key Y Y Y N
15 Y AAD Auth (Storage) Y Y Y N
16 Y Unspecified Y Y Y Y
  1. All the AAD Auth is using Azure CLI. Not setup means Azure CLI has logged out.
  2. The storageAccounts/read operation can be avoided technically, whilst it is needed to accomodate the current implemnetation (not to make the code confusing). This should be fine as the higher priviledged operation storageAccounts/listkeys is required here.

Note, when either Storage Auth Method is unspecified, or Lookup EP is set, the resource_group_name and subscription_id are required, though the subscription_id can be inferred from Azure CLI in this test setup. Therefore, the corresponding test has the resource_group_name defined.

Lastly, I've only used Azure CLI for the AAD auth method here, as the other AAD auth method shall behave the same, except the subscription_id is not inferred and additional properties might need to specifiy.

Update

I've also verified with client ID + client secret for the AAD auth.

magodo avatar Mar 06 '25 03:03 magodo

@mbfrahry I've added the test and passed it:

$ TF_ACC=1 go test -v -timeout=20h -parallel=20 -run='TestAccBackendAzureADAuthBasicWithBlobEndpointLookup'
=== RUN   TestAccBackendAzureADAuthBasicWithBlobEndpointLookup
=== PAUSE TestAccBackendAzureADAuthBasicWithBlobEndpointLookup
=== CONT  TestAccBackendAzureADAuthBasicWithBlobEndpointLookup
...
--- PASS: TestAccBackendAzureADAuthBasicWithBlobEndpointLookup (166.12s)
PASS
ok      github.com/hashicorp/terraform/internal/backend/remote-state/azure      166.126s

magodo avatar Mar 07 '25 01:03 magodo

@mbfrahry Thank you for the review! I've merged the main branch now. The CI failure of Changelog is saying:

Error: Currently this PR would target a v1.12 release. Please add a changelog entry for in the .changes/v1.12 folder, or discuss which release you'd like to target with your reviewer. If you believe this change does not need a changelog entry, please add the 'no-changelog-needed' label.

As I'm targeting to v1.11.2, I've put a changelog under v1.11 folder.

magodo avatar Mar 11 '25 00:03 magodo

I am still facing this issue

patelamit06 avatar Mar 13 '25 08:03 patelamit06

I am still facing this issue

Can you confirm you are using version 1.11.2 of Terraform CLI? If so, share you backend config and the error message.

jaredfholgate avatar Mar 13 '25 08:03 jaredfholgate

required_version = "~> 1.10"

patelamit06 avatar Mar 13 '25 09:03 patelamit06

required_version = "~> 1.10"

That is not the installed version of the CLI, just the required version. Run terraform -v to see the installed version.

jaredfholgate avatar Mar 13 '25 12:03 jaredfholgate

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions. If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

github-actions[bot] avatar Apr 13 '25 02:04 github-actions[bot]