I am sure there is a better way to achieve it hence I thought to ask it here. Currently I am creating PIM role assignment (both active and eligible) in a different resource block for each of the default roles in Azure. e.g. Data Factory Contributor, Grafana Editor and many others.
I would like to compress the code for each resource creation block and also variables block if possible so that I am not duplicating same code again and again for each of the role assignment.
Can someone please help with their expertise on Terraform to achieve this? I don't want to over complicate it as well so if its simple, I would like to go for it.
//azurerm_role_definition code block
data "azurerm_role_definition" "roles" {
for_each = toset(["Data Factory Contributor", "Grafana Editor"])
name = each.value
}
variable "groupids_data_factory_contributor" {
type = list(string)
default = ["387400af-3a87-4ee6-ac9b-487283203ecb", "d5ad0c72-5c44-422a-bd2f-7261a1415ed1"]
}
variable "groupids_grafana_editor" {
type = list(string)
default = ["387400af-3a87-4ee6-ac9b-487283203ecb", "875a79c6-26dc-4402-a9f4-7a18e3fbde0e"]
}
resource "azurerm_pim_active_role_assignment" "data_factory_contributor" {
for_each = toset(var.groupids_data_factory_contributor)
scope = data.azurerm_subscription.primary.id
role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.roles["Data Factory Contributor"].id}"
principal_id = each.value
schedule {
start_date_time = time_static.example.rfc3339
expiration {
duration_hours = 8
}
}
ticket {
number = "1"
system = "blank"
}
justification = "Expiration Duration Set"
}
resource "azurerm_pim_active_role_assignment" "grafana_editor" {
for_each = toset(var.groupids_grafana_editor)
scope = data.azurerm_subscription.primary.id
role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.roles["Grafana Editor"].id}"
principal_id = each.value
schedule {
start_date_time = time_static.example.rfc3339
expiration {
duration_hours = 8
}
}
ticket {
number = "1"
system = "blank"
}
justification = "Expiration Duration Set"
}
I am expecting the code to be compressed into single resource creation block so that I am not duplicating it for each role assignment.
Using same resource creation code block for multiple role assignments using terraform.
Here to achieve this we can use 'for_each' and 'locals' to avoid duplication for each role assignment.
As Lorenzo Felletti suggested we can use role_definition_id in the new field. Define the roles you want to assign in the local map and by using dynamic modules in azurerm_pim_active_role_assignment
The code which I shared below uses the single resource block for multiple role assignments.
Terraform code :
provider "azurerm" {
features {}
}
data "azurerm_subscription" "primary" {}
data "azurerm_role_definition" "roles" {
for_each = toset(["Data Factory Contributor", "Grafana Editor"])
name = each.value
}
variable "role_assignments" {
type = map(list(string))
default = {
"Data Factory Contributor" = ["733f2806-xxx-b59af3b21126", "ea5ab011-xxx-ed2350d96cc4"]
"Grafana Editor" = ["733f2806-xxx-b59af3b21126", "ea5ab011-xxx-ed2350d96cc4"]
}
}
resource "time_static" "example" {
rfc3339 = "2023-06-18T00:00:00Z"
}
locals {
combined_assignments = flatten([
for role, ids in var.role_assignments : [
for id in ids : {
role_definition_id = data.azurerm_role_definition.roles[role].id
principal_id = id
role = role
}
]
])
}
resource "azurerm_role_assignment" "existing" {
for_each = { for idx, val in local.combined_assignments : idx => val }
scope = data.azurerm_subscription.primary.id
role_definition_name = each.value.role
principal_id = each.value.principal_id
skip_service_principal_aad_check = true
depends_on = [
data.azurerm_subscription.primary
]
}
resource "azurerm_pim_active_role_assignment" "assignments" {
for_each = { for idx, val in local.combined_assignments : idx => val }
scope = data.azurerm_subscription.primary.id
role_definition_id = each.value.role_definition_id
principal_id = each.value.principal_id
schedule {
start_date_time = time_static.example.rfc3339
expiration {
duration_hours = 8
}
}
ticket {
number = "1"
system = "blank"
}
justification = "Expiration Duration Set"
lifecycle {
create_before_destroy = true
ignore_changes = [justification]
}
timeouts {
create = "10m"
delete = "10m"
}
depends_on = [
azurerm_role_assignment.existing
]
}
Deployment succeeded: