2
votes

Using: Terraform v0.12.6 + provider.azurerm v1.37.0

I am creating multiple Azure App Services through Terraform and added identity block to make the app as an AD App.

resource "azurerm_app_service" "apiApp" {
  count               = "${length(var.apiName)}"
  name                = "${var.apiName[count.index]}-${var.environment}"
  .
  .
  .

  identity  {
    type  = "SystemAssigned"
  }
}

As per Terraform documentation, https://www.terraform.io/docs/providers/azurerm/r/app_service.html#principal_id we can export Principal ID of the App in the output.tf file by:

${azurerm_app_service.apiApp.identity.0.principal_id}

As we have multiple App Services in this case, so I wrote this in the output.tf file:

output "ApiAppPrincipalId" {
  value = "${azurerm_app_service.apiApp.*.identity.0.principal_id}"
}

When I execute terraform plan, I get this error:

Error: Invalid index

  on modules\app-service\output.tf line 10, in output "ApiAppPrincipalId":
  10:   value = "${azurerm_app_service.apiApp.*.identity.0.principal_id}"

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

Also I am not sure what does 0 refers to. Please help.

1
Your error message implies that var.apiName is an empty string.Matt Schuchard
You need to provide more Terraform code that you use. For example, the definition of the variable apiName.Charles Xu
Focus is not on var.apiName, you can put random values in it. I need help with the error message.Arijit Bardhan
With the test, the problem is not the settings of output or the app service.Charles Xu

1 Answers

2
votes

It looks like the Azure provider represents that identity block as a list when we refer to it in expressions. Knowing that, we can write an expression that produces a flat list of principle ids by visiting all of the identity blocks across all of the app service instances, which is two levels of list:

output "ApiAppPrincipalId" {
  value = flatten([
    for identity in azurerm_app_service.apiApp[*].identity : identity[*].principal_id
  ])
}

The above uses several different Terraform expression features, so I'll break it down into smaller parts to explain:

  • azurerm_app_service.apiApp[*].identity retrieves the identity attribute for each of the app service instances, producing a list of results. As noted above, the identity block seems to be represented as a list, so the result of this expression is a list of lists of objects describing the contents of each identity block.
  • The [ for ... : ... ] expression produces a new list by visiting each element of the given list (in this case, the result of the previous expression) and evaluating the expression after the : (the result expression) against it. Because this is a list of lists of objects, identity in the result expression is a list of objects.
  • identity[*].principal_id retrieves the principal_id attribute of each of the objects representing identity blocks, again producing a list of results. In this case, because principal_id is a string attribute, the result is a list of strings.
  • The flatten(...) function deals with the fact that our for .... expression alone would return a list of lists of strings. flatten transforms that result into a flat list of strings by discarding the intermediate list nesting. The result is all of the principal_id values across all of the identity across all of the app service instances.

This is not directly related to your question, but note that it's idiomatic style in Terraform to name objects using underscore-separated words, like api_app_principal_id rather than ApiAppPrincipalId. It's also conventional to use a plural name for a collection value, like api_app_principal_ids instead of api_app_principal_id.

The naming doesn't affect Terraform's functionality here, of course, but using consistent naming can be helpful if you mix your own Terraform modules with modules written by other people, and improve the usability of your modules for those who are already familiar with Terraform from using it elsewhere.

output "api_app_principal_ids" {
  value = flatten([
    for identity in azurerm_app_service.api_app[*].identity : identity[*].principal_id
  ])
}