I have a configuration that creates 6 resource groups in azure and then loops over them to assign the contributor access to these resource groups for a certain service principal. The code is this:
auto generated before terraform is run:
locals {
pod_rg_key_list = ["non_regional_web_rg","regional_data_rg['centralus']","regional_data_rg['eastus2']","regional_web_rg['centralus']","regional_web_rg['eastus2']"]
pod_rg_list = [azurerm_resource_group.non_regional_web_rg,azurerm_resource_group.regional_data_rg["centralus"],azurerm_resource_group.regional_data_rg["eastus2"],azurerm_resource_group.regional_web_rg["centralus"],azurerm_resource_group.regional_web_rg["eastus2"]]
}
main.tf:
...
locals {
injected_rg_key_list = ["cfg"]
injected_rg_list = [azurerm_resource_group.cfg]
all_rg_key_list = concat(local.pod_rg_key_list, local.injected_rg_key_list)
all_rg_list = concat(local.pod_rg_list, local.injected_rg_list)
}
resource "azurerm_role_assignment" "pod_sp_contributor_to_pod_rgs" {
for_each = toset(local.all_rg_key_list)
scope = local.all_rg_list[index(local.all_rg_key_list, each.value)].id
role_definition_id = data.azurerm_role_definition.contributor.id
principal_id = azuread_service_principal.sp.id
}
...
This is the only way I found to make terraform create the role assignments without complaining about for_each being unable to resolve due to dynamic bla-bla-bla and suggesting to run terraform apply with -target.
So, it creates the role assignments just fine. However, when I run destroy, terraform first destroys the resource groups and then proceeds to destroy the role assignments, which is wrong and of course, it fails.
More Context
In general my code is part of an automated build that takes in a basic configuration, identifies all the resource groups, appends another terraform file and then runs the terraform on the whole shebang.
So, the way it identifies the resource groups is by running terraform plan -out main.tfplan with variables that guarantee a from scratch deployment. Then the plan is converted to json and the resource group addresses are extracted. Then they can be injected into the additional terraform code that gets added by the build before running terraform plan again and finally terraform apply.
So I cannot hard code the depends_on statement, because the list of actual resource groups is deduced by the build at run-time. I would have to also auto generate the depends_on statement, which I am trying to avoid. My reasons - currently all the auto generated stuff is just local variables all found in a separate file. If I am forced to auto generate the depends_on statement, I will have to break this nice separation.
I feel there must be a better way to achieve what I am doing.
EDIT
So, I changed the code - I moved the role assignment resource to the file where I do substitutions. This allowed me to auto generate the depends_on statement. Here is the new file:
locals {
pod_rg_key_list = ["non_regional_web_rg", "regional_data_rg['centralus']", "regional_data_rg['eastus2']", "regional_web_rg['centralus']", "regional_web_rg['eastus2']", "cfg"]
pod_rg_list = [azurerm_resource_group.non_regional_web_rg, azurerm_resource_group.regional_data_rg["centralus"], azurerm_resource_group.regional_data_rg["eastus2"], azurerm_resource_group.regional_web_rg["centralus"], azurerm_resource_group.regional_web_rg["eastus2"], azurerm_resource_group.cfg]
}
### Grant Contributor access to the resource groups
data "azurerm_role_definition" "contributor" {
name = "Contributor"
scope = "/subscriptions/${data.azurerm_subscriptions.sub.subscriptions.0.subscription_id}"
}
resource "azurerm_role_assignment" "pod_sp_contributor_to_pod_rgs" {
for_each = toset(local.pod_rg_key_list)
depends_on = [azurerm_resource_group.non_regional_web_rg, azurerm_resource_group.regional_data_rg["centralus"], azurerm_resource_group.regional_data_rg["eastus2"], azurerm_resource_group.regional_web_rg["centralus"], azurerm_resource_group.regional_web_rg["eastus2"], azurerm_resource_group.cfg]
scope = local.pod_rg_list[index(local.pod_rg_key_list, each.value)].id
role_definition_id = data.azurerm_role_definition.contributor.id
principal_id = azuread_service_principal.sp.id
}
But it still does not work:
Error: Invalid index
on ..\..\modules\bootstrap\powershell.tf line 5, in locals:
5: pod_rg_list = [azurerm_resource_group.non_regional_web_rg, azurerm_resource_group.regional_data_rg["centralus"], azurerm_resource_group.regional_data_rg["eastus2"], azurerm_resource_group.regional_web_rg["centralus"], azurerm_resource_group.regional_web_rg["eastus2"], azurerm_resource_group.cfg]
|----------------
| azurerm_resource_group.regional_data_rg is object with no attributes
The given key does not identify an element in this collection value.
Error: Invalid index
on ..\..\modules\bootstrap\powershell.tf line 5, in locals:
5: pod_rg_list = [azurerm_resource_group.non_regional_web_rg, azurerm_resource_group.regional_data_rg["centralus"], azurerm_resource_group.regional_data_rg["eastus2"], azurerm_resource_group.regional_web_rg["centralus"], azurerm_resource_group.regional_web_rg["eastus2"], azurerm_resource_group.cfg]
|----------------
| azurerm_resource_group.regional_data_rg is object with no attributes
The given key does not identify an element in this collection value.
Error: Invalid index
on ..\..\modules\bootstrap\powershell.tf line 5, in locals:
5: pod_rg_list = [azurerm_resource_group.non_regional_web_rg, azurerm_resource_group.regional_data_rg["centralus"], azurerm_resource_group.regional_data_rg["eastus2"], azurerm_resource_group.regional_web_rg["centralus"], azurerm_resource_group.regional_web_rg["eastus2"], azurerm_resource_group.cfg]
|----------------
| azurerm_resource_group.regional_web_rg is object with no attributes
The given key does not identify an element in this collection value.
Error: Invalid index
on ..\..\modules\bootstrap\powershell.tf line 5, in locals:
5: pod_rg_list = [azurerm_resource_group.non_regional_web_rg, azurerm_resource_group.regional_data_rg["centralus"], azurerm_resource_group.regional_data_rg["eastus2"], azurerm_resource_group.regional_web_rg["centralus"], azurerm_resource_group.regional_web_rg["eastus2"], azurerm_resource_group.cfg]
|----------------
| azurerm_resource_group.regional_web_rg is object with no attributes
The given key does not identify an element in this collection value.
Note, that it only breaks when destroying the environment.
EDIT 2
The actual role assignments are destroyed with the respective resource groups, but I do not get it why terraform attempts to destroy them AFTER the resource groups despite the clear message from the depends_on.
depends_onsince it is within an iterator scope? - Matt Schuchard