Added AI created module implementation.
This commit is contained in:
46
README.md
46
README.md
@@ -1,3 +1,47 @@
|
|||||||
# Azure RM Simple IAM module
|
# Azure RM Simple IAM module
|
||||||
|
|
||||||
This module create IAM role assignments for a given scope and principal. It can also assign RBAC Admininator role with conditions to assignable roles.
|
This module creates Azure RBAC role assignments for a given scope and principal.
|
||||||
|
|
||||||
|
It also optionally assigns the **Role Based Access Control Administrator** role with an ABAC condition that limits roleAssignments write/delete to a selected set of delegable roles.
|
||||||
|
|
||||||
|
The constrained RBAC Administrator assignment is created only when `delegable_roles` is non-empty.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
module "iam" {
|
||||||
|
source = "../modules/simple-iam"
|
||||||
|
|
||||||
|
scope = data.azurerm_subscription.current.id
|
||||||
|
principal_id = azuread_service_principal.sp.object_id
|
||||||
|
|
||||||
|
roles = [
|
||||||
|
"Contributor",
|
||||||
|
]
|
||||||
|
|
||||||
|
delegable_roles = [
|
||||||
|
"Storage Blob Data Contributor",
|
||||||
|
"Key Vault Secrets Officer",
|
||||||
|
"Key Vault Certificates Officer",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Optional
|
||||||
|
principal_type = "ServicePrincipal"
|
||||||
|
skip_service_principal_aad_check = true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- `scope` (string): Scope ID at which to assign roles.
|
||||||
|
- `principal_id` (string): Object ID of the principal.
|
||||||
|
- `roles` (list(string)): Unconditional role definition names to assign.
|
||||||
|
- `delegable_roles` (list(string)): Role definition names allowed by the constrained RBAC Admin condition. When empty, RBAC Admin is not assigned.
|
||||||
|
- `principal_type` (string): Passed to `azurerm_role_assignment.principal_type`.
|
||||||
|
- `skip_service_principal_aad_check` (bool): Passed to `azurerm_role_assignment.skip_service_principal_aad_check`.
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
- `role_assignment_ids` (map(string))
|
||||||
|
- `rbac_admin_role_assignment_id` (string|null)
|
||||||
|
- `rbac_admin_condition` (string|null)
|
||||||
|
|||||||
63
main.tf
63
main.tf
@@ -1 +1,62 @@
|
|||||||
data "azurerm_client_config" "current" {}
|
locals {
|
||||||
|
|
||||||
|
allowed_role_definition_ids_list = join(", ", [
|
||||||
|
for name in var.delegable_roles :
|
||||||
|
basename(data.azurerm_role_definition.allowed_for_rbac_admin_condition[name].id)
|
||||||
|
])
|
||||||
|
|
||||||
|
rbac_admin_condition = <<-EOT
|
||||||
|
(
|
||||||
|
(
|
||||||
|
!(ActionMatches{'Microsoft.Authorization/roleAssignments/write'})
|
||||||
|
)
|
||||||
|
OR
|
||||||
|
(
|
||||||
|
@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${local.allowed_role_definition_ids_list}}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
(
|
||||||
|
(
|
||||||
|
!(ActionMatches{'Microsoft.Authorization/roleAssignments/delete'})
|
||||||
|
)
|
||||||
|
OR
|
||||||
|
(
|
||||||
|
@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${local.allowed_role_definition_ids_list}}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
EOT
|
||||||
|
}
|
||||||
|
|
||||||
|
data "azurerm_role_definition" "allowed_for_rbac_admin_condition" {
|
||||||
|
|
||||||
|
for_each = toset(var.delegable_roles)
|
||||||
|
|
||||||
|
name = each.value
|
||||||
|
scope = var.scope
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "azurerm_role_assignment" "role" {
|
||||||
|
|
||||||
|
for_each = toset(var.roles)
|
||||||
|
|
||||||
|
scope = var.scope
|
||||||
|
role_definition_name = each.value
|
||||||
|
principal_id = var.principal_id
|
||||||
|
principal_type = var.principal_type
|
||||||
|
skip_service_principal_aad_check = var.skip_service_principal_aad_check
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "azurerm_role_assignment" "rbac_admin" {
|
||||||
|
|
||||||
|
count = length(var.delegable_roles) > 0 ? 1 : 0
|
||||||
|
|
||||||
|
scope = var.scope
|
||||||
|
role_definition_name = "Role Based Access Control Administrator"
|
||||||
|
principal_id = var.principal_id
|
||||||
|
principal_type = var.principal_type
|
||||||
|
skip_service_principal_aad_check = var.skip_service_principal_aad_check
|
||||||
|
|
||||||
|
condition_version = "2.0"
|
||||||
|
condition = local.rbac_admin_condition
|
||||||
|
}
|
||||||
|
|||||||
14
outputs.tf
Normal file
14
outputs.tf
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
output "role_assignment_ids" {
|
||||||
|
value = { for role, ra in azurerm_role_assignment.role : role => ra.id }
|
||||||
|
description = "IDs of unconditional role assignments, keyed by role definition name."
|
||||||
|
}
|
||||||
|
|
||||||
|
output "rbac_admin_role_assignment_id" {
|
||||||
|
value = length(azurerm_role_assignment.rbac_admin) > 0 ? azurerm_role_assignment.rbac_admin[0].id : null
|
||||||
|
description = "ID of the constrained RBAC Administrator role assignment, or null when delegable_roles is empty."
|
||||||
|
}
|
||||||
|
|
||||||
|
output "rbac_admin_condition" {
|
||||||
|
value = length(azurerm_role_assignment.rbac_admin) > 0 ? local.rbac_admin_condition : null
|
||||||
|
description = "Rendered condition used for the constrained RBAC Administrator assignment, or null when not created."
|
||||||
|
}
|
||||||
43
variables.tf
Normal file
43
variables.tf
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
variable "scope" {
|
||||||
|
type = string
|
||||||
|
description = "Scope ID at which to assign roles (subscription, resource group, resource, etc.)."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "principal_id" {
|
||||||
|
type = string
|
||||||
|
description = "Object ID of the principal (service principal, user, group, managed identity)."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "roles" {
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
description = "Unconditional role definition names to assign to principal_id at scope."
|
||||||
|
|
||||||
|
validation {
|
||||||
|
condition = length(distinct(var.roles)) == length(var.roles)
|
||||||
|
error_message = "roles must not contain duplicates."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "delegable_roles" {
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
description = "Role definition names that RBAC Administrator is allowed to assign/delete via ABAC condition. When empty, RBAC Administrator assignment is not created."
|
||||||
|
|
||||||
|
validation {
|
||||||
|
condition = length(distinct(var.delegable_roles)) == length(var.delegable_roles)
|
||||||
|
error_message = "delegable_roles must not contain duplicates."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "principal_type" {
|
||||||
|
type = string
|
||||||
|
default = "ServicePrincipal"
|
||||||
|
description = "Value for azurerm_role_assignment.principal_type (e.g., ServicePrincipal, User, Group)."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "skip_service_principal_aad_check" {
|
||||||
|
type = bool
|
||||||
|
default = true
|
||||||
|
description = "Whether to skip the Azure AD check for service principals."
|
||||||
|
}
|
||||||
10
versions.tf
10
versions.tf
@@ -0,0 +1,10 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
azurerm = {
|
||||||
|
source = "hashicorp/azurerm"
|
||||||
|
version = ">= 4.0.0, < 5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required_version = ">= 1.0.0"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user