Added support for ABAC restricted roles.

This commit is contained in:
2026-02-27 16:15:23 +01:00
parent 04de6345d8
commit 6b6615b7d3
2 changed files with 46 additions and 7 deletions

40
main.tf
View File

@@ -4,14 +4,35 @@ locals {
basename(data.azurerm_role_definition.delegable[name].id) basename(data.azurerm_role_definition.delegable[name].id)
]) ])
restricted_role_definition_ids_list = join(", ", [
for name in var.restricted_roles :
basename(data.azurerm_role_definition.restricted[name].id)
])
rbac_admin_write_constraint_principal_type = "@Request[Microsoft.Authorization/roleAssignments:PrincipalType] ForAnyOfAnyValues:StringEquals {'ServicePrincipal'}" rbac_admin_write_constraint_principal_type = "@Request[Microsoft.Authorization/roleAssignments:PrincipalType] ForAnyOfAnyValues:StringEquals {'ServicePrincipal'}"
rbac_admin_delete_constraint_principal_type = "@Resource[Microsoft.Authorization/roleAssignments:PrincipalType] ForAnyOfAnyValues:StringEquals {'ServicePrincipal'}" rbac_admin_delete_constraint_principal_type = "@Resource[Microsoft.Authorization/roleAssignments:PrincipalType] ForAnyOfAnyValues:StringEquals {'ServicePrincipal'}"
rbac_admin_write_clause_roles = join(
"\nAND\n",
compact([
length(var.delegable_roles) > 0 ? "@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${local.allowed_role_definition_ids_list}}" : "",
length(var.restricted_roles) > 0 ? "@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidNotEquals {${local.restricted_role_definition_ids_list}}" : "",
])
)
rbac_admin_delete_clause_roles = join(
"\nAND\n",
compact([
length(var.delegable_roles) > 0 ? "@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${local.allowed_role_definition_ids_list}}" : "",
length(var.restricted_roles) > 0 ? "@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidNotEquals {${local.restricted_role_definition_ids_list}}" : "",
])
)
rbac_admin_write_clause = ( rbac_admin_write_clause = (
var.delegable_roles_to_sp_only ? var.delegable_roles_to_sp_only ?
<<-EOT <<-EOT
( (
@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${local.allowed_role_definition_ids_list}} ${local.rbac_admin_write_clause_roles}
) )
AND AND
( (
@@ -19,14 +40,14 @@ locals {
) )
EOT EOT
: :
"@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${local.allowed_role_definition_ids_list}}" local.rbac_admin_write_clause_roles
) )
rbac_admin_delete_clause = ( rbac_admin_delete_clause = (
var.delegable_roles_to_sp_only ? var.delegable_roles_to_sp_only ?
<<-EOT <<-EOT
( (
@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${local.allowed_role_definition_ids_list}} ${local.rbac_admin_delete_clause_roles}
) )
AND AND
( (
@@ -34,7 +55,7 @@ locals {
) )
EOT EOT
: :
"@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${local.allowed_role_definition_ids_list}}" local.rbac_admin_delete_clause_roles
) )
rbac_admin_condition = <<-EOT rbac_admin_condition = <<-EOT
@@ -61,7 +82,7 @@ locals {
} }
data "azurerm_role_definition" "rbac_admin" { data "azurerm_role_definition" "rbac_admin" {
for_each = length(var.delegable_roles) > 0 ? { this = true } : {} for_each = length(var.delegable_roles) > 0 || length(var.restricted_roles) > 0 ? { this = true } : {}
name = "Role Based Access Control Administrator" name = "Role Based Access Control Administrator"
scope = var.scope scope = var.scope
@@ -74,6 +95,13 @@ data "azurerm_role_definition" "delegable" {
scope = var.scope scope = var.scope
} }
data "azurerm_role_definition" "restricted" {
for_each = toset(var.restricted_roles)
name = each.value
scope = var.scope
}
resource "azurerm_role_assignment" "role" { resource "azurerm_role_assignment" "role" {
for_each = toset(var.roles) for_each = toset(var.roles)
@@ -87,7 +115,7 @@ resource "azurerm_role_assignment" "role" {
resource "azurerm_role_assignment" "rbac_admin" { resource "azurerm_role_assignment" "rbac_admin" {
for_each = length(var.delegable_roles) > 0 ? { this = true } : {} for_each = length(var.delegable_roles) > 0 || length(var.restricted_roles) > 0 ? { this = true } : {}
scope = var.scope scope = var.scope
role_definition_id = data.azurerm_role_definition.rbac_admin["this"].id # Role Based Access Control Administrator role_definition_id = data.azurerm_role_definition.rbac_admin["this"].id # Role Based Access Control Administrator

View File

@@ -27,7 +27,7 @@ variable "roles" {
variable "delegable_roles" { variable "delegable_roles" {
type = list(string) type = list(string)
default = [] default = []
description = "Role definition names that RBAC Administrator is allowed to assign/delete via ABAC condition. When empty, RBAC Administrator assignment is not created." description = "Role definition names that RBAC Administrator is allowed to assign/delete via ABAC condition."
validation { validation {
condition = length(distinct(var.delegable_roles)) == length(var.delegable_roles) condition = length(distinct(var.delegable_roles)) == length(var.delegable_roles)
@@ -35,6 +35,17 @@ variable "delegable_roles" {
} }
} }
variable "restricted_roles" {
type = list(string)
default = []
description = "Role definitions names that RBAC Administrator is not allowed to assign/delete via ABAC condition."
validation {
condition = length(distinct(var.restricted_roles)) == length(var.restricted_roles)
error_message = "restricted_roles must not contain duplicates."
}
}
variable "principal_type" { variable "principal_type" {
type = string type = string
default = "ServicePrincipal" default = "ServicePrincipal"