Deploy Enterprise Scale Azure Management Groups using Terraform

I’ve been using Terraform to write all my code for AVD deployments. Because you also need a foundation to build AVD on, I also started writing code to deploy the foundation.

In this blogpost I’ll be talking about the deployment of the management groups for an enterprise scale environment using Terraform.

Why Management Groups?

If you have multiple subscriptions in your environment you need a way to manage access, policies and compliance for those subscripions. Management groups can help you do this in a structered way. For more info about them check the official doc’s page here

What kind of management groups will be deployed?

  • Company management group underneath the Tenant Root Group
  • The top management groups underneath the company management group
    • Decommisioned, Platform, Sandboxes and Landing Zones
  • The platform management groups underneath the platform management group
    • Identity, Connectivity and Management
  • The Landing Zones management groups underneath the Landing Zones management group
    • SAP, Online and Corp

Tenant Root Group

This Terraform script will deploy all the groups underneath the Tenant Root Group. I strongly advise to change the display name of this group. Check this blogpost from Wim Matthyssen to know how this is done. Azure Governance: How to change the display name of the Root management group – Wim Matthyssen (wmatthyssen.com)

Terraform variables for Management Groups

In my script I’ve created variables that can be changed to your own company needs.

variable "fullcompanyname" {
  default = "johanvanneuville"
}
variable "shortcompanyname" {
  default = "jvn"
}
variable "CompanyManagementGroupName" {
  default = "johanvanneuville"
}
variable "decomissioned" {
  default = "decommisioned"
}
variable "landingzones" {
  default = "landingzones"
}
variable "corp" {
  default = "corp"
}
variable "online" {
  default = "online"
}
 variable "sap" {
     default = "sap"
 } 
 variable "platform" {
     default = "platform"
 } 
  variable "connectivity" {
     default = "connectivity"
 } 
 variable "identity" {
    default = "identity"
 }
  variable "management" {
    default = "management"
 }
   variable "sandboxes" {
    default = "sandboxes"
 }

Main.tf for management groups

In the Terraform main.tf file we define all the management groups based on the variables. Some groups have the depends_on parameter. This means that they won’t be deployed until the parent management group is deployed.

provider "azurerm" {
  features {}
}

resource "azurerm_management_group" "parent-jvn" {
  display_name =  "mg-${var.CompanyManagementGroupName}"
}
resource "azurerm_management_group" "decom-mg" {
  display_name = "mg-${var.shortcompanyname}-${var.decomissioned}"
  parent_management_group_id = azurerm_management_group.parent-jvn.id
  depends_on = [
    azurerm_management_group.parent-jvn
  ]
}
resource "azurerm_management_group" "landingzones-mg" {
  display_name = "mg-${var.shortcompanyname}-${var.landingzones}"
  parent_management_group_id = azurerm_management_group.parent-jvn.id
  depends_on = [
    azurerm_management_group.parent-jvn
  ]
}
resource "azurerm_management_group" "corp" {
    display_name = "mg-${var.shortcompanyname}-${var.corp}"
    parent_management_group_id = azurerm_management_group.landingzones-mg.id
    depends_on = [
      azurerm_management_group.landingzones-mg
    ]
  
}
resource "azurerm_management_group" "online" {
    display_name = "mg-${var.shortcompanyname}-${var.online}"
    parent_management_group_id = azurerm_management_group.landingzones-mg.id
    depends_on = [
      azurerm_management_group.landingzones-mg
    ]
}
resource "azurerm_management_group" "sap" {
    display_name = "mg-${var.shortcompanyname}-${var.sap}"
    parent_management_group_id = azurerm_management_group.landingzones-mg.id
    depends_on = [
      azurerm_management_group.landingzones-mg
    ]
  
}
resource "azurerm_management_group" "platform" {
    display_name = "mg-${var.shortcompanyname}-${var.platform}"
    parent_management_group_id = azurerm_management_group.parent-jvn.id
    depends_on = [
      azurerm_management_group.parent-jvn
    ]
  
}
resource "azurerm_management_group" "connectivity" {
    display_name = "mg-${var.shortcompanyname}-${var.connectivity}"
    parent_management_group_id = azurerm_management_group.platform.id
    depends_on = [
      azurerm_management_group.platform
    ]
  
}
resource "azurerm_management_group" "identity" {
    display_name = "mg-${var.shortcompanyname}-${var.identity}"
    parent_management_group_id = azurerm_management_group.platform.id
    depends_on = [
      azurerm_management_group.platform
    ]
}
resource "azurerm_management_group" "management" {
    display_name = "mg-${var.shortcompanyname}-${var.management}"
    parent_management_group_id = azurerm_management_group.platform.id
    depends_on = [
      azurerm_management_group.platform
    ]
  
}
resource "azurerm_management_group" "sandboxes" {
    display_name = "mg-${var.shortcompanyname}-${var.sandboxes}"
    parent_management_group_id = azurerm_management_group.parent-jvn.id
    depends_on = [
      azurerm_management_group.parent-jvn
    ]
  
}

To deploy this you have to run through the normal Terraform commands

  • Terraform init
  • Terraform plan
  • Terraform Apply with optional parameter -auto-approve

When the deployment succeeded you will see the following management group structure in the Azure Portal. As you can see I renamed my Tenant Root Group.

I hope that this script can be helpful for you. If you have suggestions to optimize it or if you have some questions feel free to contact me on social media.

You can download the code from my Github repo here

Leave a Reply

Your email address will not be published. Required fields are marked *