terraform-provider-azurerm: Error when adding azurerm_app_service.identity and azurerm_role_assignment to existing infrastructure

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 (and AzureRM Provider) Version

Terraform 1.12 azurerm 1.29.0

Affected Resource(s)

  • azurerm_app_service
  • azurerm_role_assignment

Terraform Configuration Files

This is a problem of a transition between two states, (a) and (b). The initial state (a) is a app_service without managed identity. The second state (b) is adding the managed identity and a role assignment to a storage account. During such transition, the creation of the role fails.

State (a) is reproduced as follows (assumes that some resources already exist):


resource "azurerm_app_service" "main" {
  name = "blablabla11-appservice"
  location = "WestEurope"
  resource_group_name = "rg"
  app_service_plan_id = "blala"
  https_only = true

  site_config {
    app_command_line = "python -c 'Hello world'"
    python_version = "3.4"
    linux_fx_version = "PYTHON|3.7"
    ftps_state = "FtpsOnly"
    always_on = "false"
    use_32_bit_worker_process = "true"
  }
}

State (b) is reproduced as follows (assumes that some resources already exist):

identity {
    type = "SystemAssigned"
  }

added to the azurerm_app_service.main, and

data "azurerm_storage_account" "main" {
  name = 'blabla'
  resource_group_name = "rg"
}

resource "azurerm_role_assignment" "main" {
  principal_id = azurerm_app_service.main.identity.0.principal_id
  role_definition_name = "Reader"
  scope = data.azurerm_storage_account.main.id
}

added as new resources.

Expected Behavior

After apply (a), apply (b) should transition the state from (a) to (b).

Actual Behavior

When applying to state (b), It raises an error:

Error: Invalid index

  on main.tf line 67, in resource "azurerm_role_assignment" "main":
  67:   principal_id = azurerm_app_service.main.identity.0.principal_id
    |----------------
    | azurerm_app_service.main.identity is empty list of object

The given key does not identify an element in this collection value.

Important Factoids

A temporary fix to this is to create an intermediary state, ©, on which the identity is added to the app_service but the role assignment is not added, terraform apply ©, and then terraform apply state (b) (i.e. add the role assignment to the code). In other words, it seems that when the app_service exists without identity, the role_assignment tries to pick the identity from app_service before it realizes that an identity was added to the app_service.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 62
  • Comments: 24 (7 by maintainers)

Most upvoted comments

Weighing in again because this has caused me much frustration. This bug affects pretty much everything that has an identity block - storage accounts, virtual machines, function apps, SQL Server, etc. Transitioning from no identity to SystemManaged identity on these resources is extremely tedious as a result.

This almost seems like an issue with Terraform core itself and how it evaluates references to attributes of TypeList with nested schema like our identity is here. It seems like it should be able to see that identity[0] is being added to the resource (since it’s in the configuration code) and consequently that identity[0].principal_id should be calculated. But instead, it’s immediately trying to evaluate the expression and failing because it doesn’t exist.

Would love to get more insight from the Hashicorp / Azure provider team as to what exactly is going on here @tombuildsstuff

I’m posting again partially to bump the issue to make sure it doesn’t get closed, and also as another attempt to get some attention on this issue. Even if the solution may take a while or has upstream dependencies on Terraform Core, it would be nice to hear from one of the maintainers to know that they are aware that this is a problem at the very least.

I’ve confirmed that this issue affects the following resources:

  • azurerm_virtual_machine
  • azurerm_linux_virtual_machine
  • azurerm_windows_virtual_machine
  • azurerm_storage_account
  • azurerm_sql_server

Those are just the resources I’ve personally experienced this error with in the course of using Terraform with Azure. I’m sure it’s not an exhaustive list of all the resources that are affected by this bug.

I wonder if the tags on this issue should be updated to reflect it’s not merely an issue with App Service - it affects ALL resources that have an identity block (which is a lot). I also feel it would be appropriate to update the title. I think something like “Error referencing SystemAssigned identity when adding to existing resources” would be more in line with the actual bug discussed here, and would make this GitHub issue a bit more discoverable.

Just confirmed that this is still an issue on Terraform 0.13.0 and AzureRM 2.24.0

Using azurerm_app_service.main.identity[0].principal_id instead of azurerm_app_service.main.identity.0.principal_id solved the issue for me.

I don’t think that the last syntax should be used. The documentation is probably wrong. Maybe it wasn’t updated with the changes of HCL ?

Eg for storage account https://www.terraform.io/docs/providers/azurerm/r/storage_account.html

You can access the Principal ID via ${azurerm_storage_account.example.identity.0.principal_id} and the Tenant ID via ${azurerm_storage_account.example.identity.0.tenant_id}

Workaround I am using is to lookup the service principal with azuread_service_principal after the app service (or other resource) is created using the display name. The lookup must depend on the app service resource. I don’t know how guaranteed the display name is, but its working so far.

Example:

resource "azurerm_app_service" "app_service_name" {
  name = "app_service_name"
  <SNIP>
  identity {
    type = "SystemAssigned"
  }
}

data "azuread_service_principal" "app-system-id" {
  display_name = "app_service_name"
  depends_on   = [azurerm_app_service.app_service_name]
}

resource "azurerm_key_vault_access_policy" "kvlt-access-appservice" {
  key_vault_id = azurerm_key_vault.keyvault.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = data.azuread_service_principal.app-system-id.id
  <SNIP>
}