Skip to content
Open
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
31 changes: 31 additions & 0 deletions modules/azure/resource-group/backplane/documentation.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
output "documentation_md" {
value = <<EOF
# Azure Resource Group Building Block

The Resource Group Building Block creates an empty Azure Resource Group for a meshStack project.
The resource group name is automatically generated following the schema `rg-<workspaceId>-<projectId>`,
ensuring consistent naming across all landing zones.

# Azure Resource Group Building Block Backplane

This module automates the IAM setup required for the Resource Group building block within Azure.

## Role Definition

| Name | ID |
| --- | --- |
| ${azurerm_role_definition.buildingblock_deploy.name} | ${azurerm_role_definition.buildingblock_deploy.id} |

## Role Assignments

| Principal ID |
| --- |
| ${join("\n", concat([for assignment in azurerm_role_assignment.existing_principals : assignment.principal_id], var.create_service_principal_name != null ? [azurerm_role_assignment.created_principal[0].principal_id] : []))} |

## Scope

- **Scope**: `${var.scope}`

EOF
description = "Markdown documentation with information about the Resource Group building block backplane."
}
82 changes: 82 additions & 0 deletions modules/azure/resource-group/backplane/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
data "azurerm_subscription" "current" {}

resource "azuread_application" "buildingblock_deploy" {
count = var.create_service_principal_name != null ? 1 : 0

display_name = "${var.name}-${var.create_service_principal_name}"
}

resource "azuread_service_principal" "buildingblock_deploy" {
count = var.create_service_principal_name != null ? 1 : 0

client_id = azuread_application.buildingblock_deploy[0].client_id
app_role_assignment_required = false
}

resource "azuread_application_federated_identity_credential" "buildingblock_deploy" {
count = var.create_service_principal_name != null && var.workload_identity_federation != null ? 1 : 0

application_id = azuread_application.buildingblock_deploy[0].id
display_name = var.create_service_principal_name
audiences = ["api://AzureADTokenExchange"]
issuer = var.workload_identity_federation.issuer
subject = var.workload_identity_federation.subject
}

resource "azuread_application_password" "buildingblock_deploy" {
count = var.create_service_principal_name != null && var.workload_identity_federation == null ? 1 : 0

application_id = azuread_application.buildingblock_deploy[0].id
display_name = "${var.create_service_principal_name}-password"
}

resource "azurerm_role_definition" "buildingblock_deploy" {
name = "${var.name}-deploy"
description = "Enables deployment of the ${var.name} building block to subscriptions"
scope = var.scope

permissions {
actions = [
# Register resource providers in Azure Resource Manager
"*/register/action",

# Resource Groups - full lifecycle management
"Microsoft.Resources/subscriptions/resourceGroups/*",

# Read subscription providers
"Microsoft.Resources/subscriptions/providers/read",
]
}
}

resource "azurerm_role_assignment" "existing_principals" {
for_each = var.existing_principal_ids

role_definition_id = azurerm_role_definition.buildingblock_deploy.role_definition_resource_id
principal_id = each.value
scope = var.scope
}

resource "azurerm_role_assignment" "created_principal" {
count = var.create_service_principal_name != null ? 1 : 0

role_definition_id = azurerm_role_definition.buildingblock_deploy.role_definition_resource_id
principal_id = azuread_service_principal.buildingblock_deploy[0].object_id
scope = var.scope
}

resource "azuread_directory_role" "directory_readers" {
display_name = "Directory Readers"
}

resource "azuread_directory_role_assignment" "directory_readers_existing" {
for_each = var.existing_principal_ids
role_id = azuread_directory_role.directory_readers.template_id
principal_object_id = each.value
}

resource "azuread_directory_role_assignment" "directory_readers_created" {
count = var.create_service_principal_name != null ? 1 : 0
role_id = azuread_directory_role.directory_readers.template_id
principal_object_id = azuread_service_principal.buildingblock_deploy[0].object_id
}
69 changes: 69 additions & 0 deletions modules/azure/resource-group/backplane/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
output "role_definition_id" {
value = azurerm_role_definition.buildingblock_deploy.id
description = "The ID of the role definition that enables deployment of the building block."
}

output "role_definition_name" {
value = azurerm_role_definition.buildingblock_deploy.name
description = "The name of the role definition that enables deployment of the building block."
}

output "role_assignment_ids" {
value = concat(
[for id in azurerm_role_assignment.existing_principals : id.id],
var.create_service_principal_name != null ? [azurerm_role_assignment.created_principal[0].id] : []
)
description = "The IDs of the role assignments for all service principals."
}

output "role_assignment_principal_ids" {
value = concat(
[for id in azurerm_role_assignment.existing_principals : id.principal_id],
var.create_service_principal_name != null ? [azurerm_role_assignment.created_principal[0].principal_id] : []
)
description = "The principal IDs of all service principals that have been assigned the role."
}

output "created_service_principal" {
value = var.create_service_principal_name != null ? {
object_id = azuread_service_principal.buildingblock_deploy[0].object_id
client_id = azuread_service_principal.buildingblock_deploy[0].client_id
display_name = azuread_service_principal.buildingblock_deploy[0].display_name
name = var.create_service_principal_name
} : null
description = "Information about the created service principal."
}

output "created_application" {
value = var.create_service_principal_name != null ? {
object_id = azuread_application.buildingblock_deploy[0].object_id
client_id = azuread_application.buildingblock_deploy[0].client_id
display_name = azuread_application.buildingblock_deploy[0].display_name
} : null
description = "Information about the created Azure AD application."
}

output "workload_identity_federation" {
value = var.create_service_principal_name != null && var.workload_identity_federation != null ? {
credential_id = azuread_application_federated_identity_credential.buildingblock_deploy[0].credential_id
display_name = azuread_application_federated_identity_credential.buildingblock_deploy[0].display_name
issuer = azuread_application_federated_identity_credential.buildingblock_deploy[0].issuer
subject = azuread_application_federated_identity_credential.buildingblock_deploy[0].subject
audiences = azuread_application_federated_identity_credential.buildingblock_deploy[0].audiences
} : null
description = "Information about the created workload identity federation credential."
}

output "application_password" {
value = var.create_service_principal_name != null && var.workload_identity_federation == null ? {
key_id = azuread_application_password.buildingblock_deploy[0].key_id
display_name = azuread_application_password.buildingblock_deploy[0].display_name
} : null
description = "Information about the created application password (excludes the actual password value for security)."
sensitive = true
}

output "scope" {
value = var.scope
description = "The scope where the role definition and role assignments are applied."
}
3 changes: 3 additions & 0 deletions modules/azure/resource-group/backplane/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
provider "azurerm" {
features {}
}
40 changes: 40 additions & 0 deletions modules/azure/resource-group/backplane/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
variable "name" {
type = string
nullable = false
default = "resource-group"
description = "Name of the building block, used for naming Azure resources."
validation {
condition = can(regex("^[-a-z0-9]+$", var.name))
error_message = "Only alphanumeric lowercase characters and dashes are allowed."
}
}

variable "scope" {
type = string
nullable = false
description = "Scope where the building block should be deployable, typically the parent management group of all landing zones."
}

variable "existing_principal_ids" {
type = set(string)
nullable = false
default = []
description = "Set of existing principal IDs that will be granted permissions to deploy the building block."
}

variable "create_service_principal_name" {
type = string
nullable = true
default = null
description = "If set, creates a new service principal with the given name for deploying the building block."
}

variable "workload_identity_federation" {
type = object({
issuer = string
subject = string
})
nullable = true
default = null
description = "If set, configures workload identity federation for the created service principal."
}
14 changes: 14 additions & 0 deletions modules/azure/resource-group/backplane/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
terraform {
required_version = ">= 1.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.64"
}
azuread = {
source = "hashicorp/azuread"
version = "~> 3.8"
}
}
}
8 changes: 8 additions & 0 deletions modules/azure/resource-group/buildingblock/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
locals {
resource_group_name = "rg-${var.workspace_identifier}-${var.project_identifier}"
}

resource "azurerm_resource_group" "this" {
name = local.resource_group_name
location = var.location
}
9 changes: 9 additions & 0 deletions modules/azure/resource-group/buildingblock/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "resource_group_name" {
value = azurerm_resource_group.this.name
description = "The name of the created resource group (e.g. 'rg-myworkspace-myproject')."
}

output "resource_group_id" {
value = azurerm_resource_group.this.id
description = "The Azure resource ID of the created resource group."
}
4 changes: 4 additions & 0 deletions modules/azure/resource-group/buildingblock/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
provider "azurerm" {
subscription_id = var.subscription_id
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the ENV var pls and not adding vars in the provider. we dont need them there

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can also remove it from the the vars. We can use the tenant id.

features {}
}
20 changes: 20 additions & 0 deletions modules/azure/resource-group/buildingblock/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
variable "subscription_id" {
type = string
description = "The Azure subscription ID where the resource group will be created."
}

variable "workspace_identifier" {
type = string
description = "The meshStack workspace identifier. Used to generate the resource group name."
}

variable "project_identifier" {
type = string
description = "The meshStack project identifier. Used to generate the resource group name."
}

variable "location" {
type = string
description = "The Azure region where the resource group will be created (e.g. 'westeurope', 'eastus')."
default = "westeurope"
}
10 changes: 10 additions & 0 deletions modules/azure/resource-group/buildingblock/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.64"
}
}
}
Loading
Loading