Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/modules/role_assignments/subscription/_outputs.tf
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
output "subscription_assignments" {
description = "Mapping of users to built-in role assignments at the subscription scope"
description = "Resolved subscription-level role assignments"

value = {
for key, assignment in azurerm_role_assignment.assignments :
key => {
user_principal_name = assignment.principal_id != "" ? data.azuread_user.users[local.flat_assignments[key].user].user_principal_name : null
role = local.flat_assignments[key].role
role_assignment_id = assignment.id
scope = assignment.scope
role = local.flat_assignments[key].role
principal_id = assignment.principal_id

# UPN only when principal is a user (non-GUID)
user_principal_name = (
contains(keys(data.azuread_user.users), local.flat_assignments[key].principal)
? data.azuread_user.users[local.flat_assignments[key].principal].user_principal_name
: null
)
}
}
}
35 changes: 27 additions & 8 deletions src/modules/role_assignments/subscription/main.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
variable "subscription_assignments" {
description = "Map of built-in role name to list of user UPNs"
description = "Map of built-in role name to list of user UPNs or service principal object IDs"
type = map(list(string))
}

Expand All @@ -10,29 +10,48 @@ variable "global_settings" {
data "azurerm_client_config" "current" {}

locals {
# Build a flat list: "<role>_<principal>" => { role = "...", principal = "..." }
flat_assignments = merge([
for role, users in var.subscription_assignments : {
for user in users : "${role}_${user}" => {
role = role
user = user
for role, principals in var.subscription_assignments : {
for principal in principals :
"${role}_${principal}" => {
role = role
principal = principal
}
}
]...)
}

# Lookup Azure AD user by UPN
# Lookup Azure AD users (UPNs)
data "azuread_user" "users" {
for_each = {
for assignment in local.flat_assignments : assignment.user => assignment.user
for _, assignment in local.flat_assignments :
assignment.principal => assignment.principal
if !can(regex("^[0-9a-fA-F-]{36}$", assignment.principal))
}

user_principal_name = each.value
}

# Lookup service principals (GUIDs)
data "azuread_service_principal" "sps" {
for_each = {
for _, assignment in local.flat_assignments :
assignment.principal => assignment.principal
if can(regex("^[0-9a-fA-F-]{36}$", assignment.principal))
}

object_id = each.value
}

resource "azurerm_role_assignment" "assignments" {
for_each = local.flat_assignments

principal_id = data.azuread_user.users[each.value.user].object_id
principal_id = try(
data.azuread_user.users[each.value.principal].object_id,
data.azuread_service_principal.sps[each.value.principal].object_id
)

role_definition_name = each.value.role
scope = "/subscriptions/${data.azurerm_client_config.current.subscription_id}"
}
3 changes: 2 additions & 1 deletion src/role_assignments.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module "role_assignments" {
role_definitions = module.role_definitions
disk_encryption_sets = module.disk_encryption_sets
container_registries = module.container_registries
application_gateways = module.application_gateways
linux_virtual_machines = {
for key, vm in module.virtual_machines :
key => vm.linux_virtual_machines[0]
Expand All @@ -42,7 +43,7 @@ module "role_assignments" {
module "subscription_assignments" {
source = "./modules/role_assignments/subscription"
count = length(
try(var.subscription_assignments.built_in_roles, [])
try(var.subscription_assignments, [])
) > 0 ? 1 : 0

subscription_assignments = var.subscription_assignments.built_in_roles
Expand Down
Loading