hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.51k stars 4.6k forks source link

Breaking change introduced on `azurerm_api_management_subscription` in v3.89.0 related to `azurerm_api_management_api` #25020

Open PrestonR opened 6 months ago

PrestonR commented 6 months ago

Is there an existing issue for this?

Community Note

Terraform Version

1.5.5

AzureRM Provider Version

3.89.0

Affected Resource(s)/Data Source(s)

azurerm_api_management_subscription

Terraform Configuration Files

resource "azurerm_api_management_api" "status" {
  api_management_name   = azurerm_api_management.apim.name
  resource_group_name   = var.resource_group_name
  display_name          = "Status"
  name                  = "status"
  path                  = "status"
  revision              = "1"
  protocols             = ["https"]
  subscription_required = false
}

resource "azurerm_api_management_api" "internal_api" {
  for_each              = var.enable_internal_apis ? toset(keys(local.internal_api)) : []
  api_management_name   = azurerm_api_management.apim.name
  resource_group_name   = var.resource_group_name
  display_name          = title(replace(each.key, "_", " "))
  name                  = lower(replace(each.key, "_", "-"))
  path                  = each.key == "global_platform" ? "" : lower(replace(each.key, "_", "-"))
  revision              = "1"
  protocols             = ["https"]
  subscription_required = false
}

resource "azurerm_api_management_api" "external_api" {
  for_each              = toset(keys(local.external_api))
  api_management_name   = azurerm_api_management.apim.name
  resource_group_name   = var.resource_group_name
  display_name          = title(replace(each.key, "_", " "))
  name                  = lower(replace(each.key, "_", "-"))
  path                  = lower(replace(each.key, "_", "-"))
  revision              = "1"
  protocols             = ["https"]
  subscription_required = true

  subscription_key_parameter_names {
    header = "X-API-Key"
    query  = "api_key"
  }
}

resource "azurerm_api_management_subscription" "external" {
  for_each            = toset(keys(local.external_api))
  api_management_name = azurerm_api_management.apim.name
  resource_group_name = var.resource_group_name
  api_id              = azurerm_api_management_api.external_api[each.key].id
  display_name        = title(replace(each.key, "_", " "))
  state               = "active"
  allow_tracing       = false
}

Debug Output/Panic Output

There is no visible error. Plan and apply succeed.

Expected Behaviour

Subscription keys should work for the API as generated.

Actual Behaviour

The API keys throw this error:

{ "statusCode": 401, "message": "Access denied due to invalid subscription key. Make sure to provide a valid key for an active subscription." }

Steps to Reproduce

terraform apply

Important Factoids

No response

References

Probably worth noting that we don't use revisions, so this works as a workaround:

resource "azurerm_api_management_subscription" "external" {
  for_each            = toset(keys(local.external_api))
  api_management_name = azurerm_api_management.apim.name
  resource_group_name = var.resource_group_name
  api_id              = replace(azurerm_api_management_api.external_api[each.key].id, ";rev=1", "")
  display_name        = title(replace(each.key, "_", " "))
  state               = "active"
  allow_tracing       = false
}
sinbai commented 6 months ago

Hi @PrestonR thanks for opening this issue. Could you please explain the specific symptoms of Actual Behaviour and steps to help reproduce/troubleshoot?

PrestonR commented 6 months ago

Hi Sinbai,

From a Terraform Plan and Apply point of view everything works fine. The actual behavior is how these recent changes broke interaction between resources in Azure. So, here's the detail:

  1. Create a azurerm_api_management_api resource and link it to a azurerm_api_management_subscription resource via api_id on a version prior to v3.89.0
  2. Plan and Apply
  3. Test the API Keys created for your API - they work without throwing a 401
  4. Upgrade the provider to v3.89.0 or later
  5. Plan and Apply
    • you'll see that because of the new inclusion of the revision on the azurerm_api_management_api id export, it forces the azurerm_api_management_subscription to recreate - as expected
  6. but the newly created subscription keys, when used, throw a 401

So, it appears that when the azurerm_api_management_api is linked to the azurerm_api_management_subscription when it includes the revision, API keys don't work. I confirmed this by using the workaround above, and the API keys continue to work fine.

This line:

api_id = replace(azurerm_api_management_api.external_api[each.key].id, ";rev=1", "")

Please let me know if you need anymore detail.

alexwiese commented 6 months ago

Looks like another issue related to #23031

@tombuildsstuff @mbfrahry should that change be rolled back until all of the issues related to the API ID format can be resolved?