Create an initial ALZ config
Clone the repo locally and add an initial Azure Landing Zone config based on the examples in the Terraform Registry.
Table of Contents
Overview
On this page you will:
-
Locally clone the repo generated by the Azure Landing Zone accelerator
-
Add the alz provider
Use the alz Terraform provider to pull the library definitions from the ALZ Library repo. You will learn plenty more about the alz provider and libraries throughout these labs, but for now we’ll just pull the most recent release of default definitions.
-
Update the variables.tf and add a main.tf to your Terraform config
Add a config based on the examples provided for the Azure Verified Modules in the Terraform registry.
Clone the repo
-
Variables
github_repo="alz-mgmt" github_org="richeney-org"⚠️ Set to the correct values for your repo and org names.
-
Clone the repo
You may wish to switch to your standard directory for your git repos, if you have one.
git clone https://github.com/${github_org}/${github_repo} -
Change directory
cd $github_repo -
Open Visual Studio Code
code .
What is the ALZ Library repo?
We will be looking at libraries in greater detail in another series, but for the moment here is a brief introduction. You can read the documentation for the Azure Landing Zone libraries at https://azure.github.io/Azure-Landing-Zones-Library.
Libraries contain definitions for core compliancy guardrails. They define archetypes, collections of Azure Policy policies, initiatives, and assignments, plus custom role definitions. The archetypes. The architecture definitions then define the set of management groups, including their name, cosmetic display names, and the array of archetypes assigned to them.
The Azure Landing Zones Terraform provider can pull library definitions from different sources. These are then referenced by the ALZ Terraform module which specifies the architecture_name as well as any additional modifications, default values, etc. The two are closely related and these labs will help you to understand both.
The provider can pull from more than one source, and those sources can have dependencies on other libraries, which provides great scope for extensibility and customisation. We will explore this from a Microsoft partner perspective, extending the Azure Landing Zone and Sovereign Landing Zone baselines with reusable partner libraries, including country and industry packs for the sovereignty context. In addition, we will explore using archetype overrides to allow individual customers to customise their deployments.
The most common library source is the ALZ Library repo which is actively maintained by the Microsoft Customer Architecture and Engineering team (CAE). The repo contains library definitions for Azure Landing Zones, Sovereign Landing Zones, and Azure Monitoring Baseline Alerts. All are semantically versioned and you can view the releases.
Azure Landing Zone
Provider
Add the alz provider and specify the most recent Azure Landing Zone library release.
-
Check the releases page for the most recent platform/alz release.
At the time of writing this is 2025.09.3.
-
Add to the terraform.tf
provider "alz" { library_overwrite_enabled = true library_references = [ { path = "platform/alz" ref = "2025.09.3" } ] }The alz provider will pull in that version of the library definition from
https://github.com/Azure/Azure-Landing-Zones-Library/tree/{tag}/{path}where{tag}is{path}/{ref}.For example, https://github.com/Azure/Azure-Landing-Zones-Library/tree/platform/alz/2025.09.3/platform/alz for the core Azure Landing Zones library.
Variables
-
Add this code block to the variables.tf
variable "location" { type = string default = "uksouth" description = "Location for the resources" } variable "email_security_contact" { type = string default = "" description = "Email address for security alerts" }
Main
We will cover how the AVM modules work with the library as we progress through the labs. For the moment we will just get an example up and running,
-
Create a main.tf
data "azapi_client_config" "current" {} locals { management_resource_group_name = "rg-management-${var.location}" management_resource_group_id = "/subscriptions/${var.subscription_ids["management"]}/resourcegroups/${local.management_resource_group_name}" automation_account_name = "aa-management-${var.location}" log_analytics_workspace_name = "law-management-${var.location}" ama_user_assigned_managed_identity_name = "uami-management-ama-${var.location}" dcr_change_tracking_name = "dcr-change-tracking" dcr_defender_sql_name = "dcr-defender-sql" dcr_vm_insights_name = "dcr-vm-insights" ama_user_assigned_managed_identity_id = "${local.management_resource_group_id}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/${local.ama_user_assigned_managed_identity_name}" ama_change_tracking_data_collection_rule_id = "${local.management_resource_group_id}/providers/Microsoft.Insights/dataCollectionRules/${local.dcr_change_tracking_name}" ama_mdfc_sql_data_collection_rule_id = "${local.management_resource_group_id}/providers/Microsoft.Insights/dataCollectionRules/${local.dcr_defender_sql_name}" ama_vm_insights_data_collection_rule_id = "${local.management_resource_group_id}/providers/Microsoft.Insights/dataCollectionRules/${local.dcr_vm_insights_name}" log_analytics_workspace_id = "${local.management_resource_group_id}/providers/Microsoft.OperationalInsights/workspaces/${local.log_analytics_workspace_name}" } module "management_resources" { # <https://registry.terraform.io/modules/Azure/avm-ptn-alz-management/azurerm/latest> source = "Azure/avm-ptn-alz-management/azurerm" version = "0.9.0" location = var.location resource_group_name = local.management_resource_group_name automation_account_name = local.automation_account_name log_analytics_workspace_name = local.log_analytics_workspace_name data_collection_rules = { "change_tracking" = { "name" = local.dcr_change_tracking_name } "defender_sql" = { "name" = local.dcr_defender_sql_name } "vm_insights" = { "name" = local.dcr_vm_insights_name } } user_assigned_managed_identities = { ama = { name = local.ama_user_assigned_managed_identity_name } } } module "management_groups" { # <https://registry.terraform.io/modules/Azure/avm-ptn-alz/azurerm/latest> source = "Azure/avm-ptn-alz/azurerm" version = "0.14.0" architecture_name = "alz" location = var.location parent_resource_id = data.azapi_client_config.current.tenant_id # Tenant root group # retries = local.default_retries # timeouts = local.default_timeouts dependencies = { policy_assignments = [ module.management_resources.data_collection_rule_ids, module.management_resources.resource_id, module.management_resources.user_assigned_identity_ids, ] } policy_assignments_to_modify = { "alz" = { "policy_assignments" = { "Deploy-MDFC-Config-H224" = { "parameters" = { "ascExportResourceGroupLocation" = jsonencode({ value = var.location }) "ascExportResourceGroupName" = jsonencode({ value = "rg-asc-export-${var.location}" }) "emailSecurityContact" = jsonencode({ value = var.email_security_contact }) "enableAscForAppServices" = jsonencode({ value = "Disabled" }) "enableAscForArm" = jsonencode({ value = "Disabled" }) "enableAscForContainers" = jsonencode({ value = "Disabled" }) "enableAscForCosmosDbs" = jsonencode({ value = "Disabled" }) "enableAscForCspm" = jsonencode({ value = "Disabled" }) "enableAscForKeyVault" = jsonencode({ value = "Disabled" }) "enableAscForOssDb" = jsonencode({ value = "Disabled" }) "enableAscForServers" = jsonencode({ value = "Disabled" }) "enableAscForServersVulnerabilityAssessments" = jsonencode({ value = "Disabled" }) "enableAscForSql" = jsonencode({ value = "Disabled" }) "enableAscForSqlOnVm" = jsonencode({ value = "Disabled" }) "enableAscForStorage" = jsonencode({ value = "Disabled" }) } } } } "connectivity" = { "policy_assignments" = { "Enable-DDoS-VNET" = { "enforcement_mode" = "DoNotEnforce" } } } "corp" = { "policy_assignments" = { "Deploy-Private-DNS-Zones" = { "enforcement_mode" = "DoNotEnforce" } } } "landingzones" = { "policy_assignments" = { "Enable-DDoS-VNET" = { "enforcement_mode" = "DoNotEnforce" } } } } policy_default_values = { "ama_user_assigned_managed_identity_name" = jsonencode({ value = local.ama_user_assigned_managed_identity_name }) "ama_user_assigned_managed_identity_id" = jsonencode({ value = local.ama_user_assigned_managed_identity_id }) "ama_change_tracking_data_collection_rule_id" = jsonencode({ value = local.ama_change_tracking_data_collection_rule_id }) "ama_mdfc_sql_data_collection_rule_id" = jsonencode({ value = local.ama_mdfc_sql_data_collection_rule_id }) "ama_vm_insights_data_collection_rule_id" = jsonencode({ value = local.ama_vm_insights_data_collection_rule_id }) "log_analytics_workspace_id" = jsonencode({ value = local.log_analytics_workspace_id }) } subscription_placement = { "connectivity" = { "management_group_name" = "connectivity" "subscription_id" = var.subscription_ids["connectivity"] } "identity" = { "management_group_name" = "identity" "subscription_id" = var.subscription_ids["identity"] } "management" = { "management_group_name" = "management" "subscription_id" = var.subscription_ids["management"] } # "security" = { # "management_group_name" = "security" # "subscription_id" = var.subscription_ids["security"] # } } }⚠️ Note the subscription placement object. Comment (CTR+K,CTRL+C) and uncomment (CTRL+K,CTRL+U) as needed depending on how many subscriptions you are specifying.
Sovereign Landing Zone
Provider
Add the alz provider and specify the most recent Sovereign Landing Zone library release.
-
Check the releases page for the most recent platform/slz release.
At the time of writing this is 2025.10.1.
-
Add to the terraform.tf
provider "alz" { library_overwrite_enabled = true library_references = [ { path = "platform/slz" ref = "2025.10.1" } ] }The alz provider will pull in that version of the library definition from
https://github.com/Azure/Azure-Landing-Zones-Library/tree/{tag}/{path}where{tag}is{path}/{ref}.For example, https://github.com/Azure/Azure-Landing-Zones-Library/tree/platform/slz/2025.10.1/platform/slz for the Sovereign Landing Zone library.
Variables
-
Add this code block to the variables.tf
variable "location" { type = string default = "uksouth" description = "Location for the resources" } variable "email_security_contact" { type = string default = "" description = "Email address for security alerts" }
Main
The Sovereign Landing Zone example differs from the Azure Landing Zone example in only a few ways, all related to the management_groups module:
- the architecture_name is now set to
slzrather thanalz - the policy_assignments_to_modify object also refers to the
slzarchitecture name - the policy_default_values now includes
"allowed_locations" = jsonencode({ value = [${var.location}]})as this array of region shortcodes is expected by the additional archetypes
We won’t cover those changes in any real detail on this page. For the moment let’s get it up and running.
There is a later deep dive on libraries and how the AVM modules work with those library definitions and we’ll circle back to these changes at that poit.
-
Create a main.tf
data "azapi_client_config" "current" {} locals { management_resource_group_name = "rg-management-${var.location}" management_resource_group_id = "/subscriptions/${var.subscription_ids["management"]}/resourcegroups/${local.management_resource_group_name}" automation_account_name = "aa-management-${var.location}" log_analytics_workspace_name = "law-management-${var.location}" ama_user_assigned_managed_identity_name = "uami-management-ama-${var.location}" dcr_change_tracking_name = "dcr-change-tracking" dcr_defender_sql_name = "dcr-defender-sql" dcr_vm_insights_name = "dcr-vm-insights" ama_user_assigned_managed_identity_id = "${local.management_resource_group_id}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/${local.ama_user_assigned_managed_identity_name}" ama_change_tracking_data_collection_rule_id = "${local.management_resource_group_id}/providers/Microsoft.Insights/dataCollectionRules/${local.dcr_change_tracking_name}" ama_mdfc_sql_data_collection_rule_id = "${local.management_resource_group_id}/providers/Microsoft.Insights/dataCollectionRules/${local.dcr_defender_sql_name}" ama_vm_insights_data_collection_rule_id = "${local.management_resource_group_id}/providers/Microsoft.Insights/dataCollectionRules/${local.dcr_vm_insights_name}" log_analytics_workspace_id = "${local.management_resource_group_id}/providers/Microsoft.OperationalInsights/workspaces/${local.log_analytics_workspace_name}" } module "management_resources" { # <https://registry.terraform.io/modules/Azure/avm-ptn-alz-management/azurerm/latest> source = "Azure/avm-ptn-alz-management/azurerm" version = "0.9.0" location = var.location resource_group_name = local.management_resource_group_name automation_account_name = local.automation_account_name log_analytics_workspace_name = local.log_analytics_workspace_name data_collection_rules = { "change_tracking" = { "name" = local.dcr_change_tracking_name } "defender_sql" = { "name" = local.dcr_defender_sql_name } "vm_insights" = { "name" = local.dcr_vm_insights_name } } user_assigned_managed_identities = { ama = { name = local.ama_user_assigned_managed_identity_name } } } module "management_groups" { # <https://registry.terraform.io/modules/Azure/avm-ptn-alz/azurerm/latest> source = "Azure/avm-ptn-alz/azurerm" version = "0.14.0" architecture_name = "slz" location = var.location parent_resource_id = data.azapi_client_config.current.tenant_id # Tenant root group # retries = local.default_retries # timeouts = local.default_timeouts dependencies = { policy_assignments = [ module.management_resources.data_collection_rule_ids, module.management_resources.resource_id, module.management_resources.user_assigned_identity_ids, ] } policy_assignments_to_modify = { "slz" = { "policy_assignments" = { "Deploy-MDFC-Config-H224" = { "parameters" = { "ascExportResourceGroupLocation" = jsonencode({ value = var.location }) "ascExportResourceGroupName" = jsonencode({ value = "rg-asc-export-${var.location}" }) "emailSecurityContact" = jsonencode({ value = var.email_security_contact }) "enableAscForAppServices" = jsonencode({ value = "Disabled" }) "enableAscForArm" = jsonencode({ value = "Disabled" }) "enableAscForContainers" = jsonencode({ value = "Disabled" }) "enableAscForCosmosDbs" = jsonencode({ value = "Disabled" }) "enableAscForCspm" = jsonencode({ value = "Disabled" }) "enableAscForKeyVault" = jsonencode({ value = "Disabled" }) "enableAscForOssDb" = jsonencode({ value = "Disabled" }) "enableAscForServers" = jsonencode({ value = "Disabled" }) "enableAscForServersVulnerabilityAssessments" = jsonencode({ value = "Disabled" }) "enableAscForSql" = jsonencode({ value = "Disabled" }) "enableAscForSqlOnVm" = jsonencode({ value = "Disabled" }) "enableAscForStorage" = jsonencode({ value = "Disabled" }) } } } } "connectivity" = { "policy_assignments" = { "Enable-DDoS-VNET" = { "enforcement_mode" = "DoNotEnforce" } } } "corp" = { "policy_assignments" = { "Deploy-Private-DNS-Zones" = { "enforcement_mode" = "DoNotEnforce" } } } "landingzones" = { "policy_assignments" = { "Enable-DDoS-VNET" = { "enforcement_mode" = "DoNotEnforce" } } } } policy_default_values = { "allowed_locations" = jsonencode({ value = [var.location] }) "ama_user_assigned_managed_identity_name" = jsonencode({ value = local.ama_user_assigned_managed_identity_name }) "ama_user_assigned_managed_identity_id" = jsonencode({ value = local.ama_user_assigned_managed_identity_id }) "ama_change_tracking_data_collection_rule_id" = jsonencode({ value = local.ama_change_tracking_data_collection_rule_id }) "ama_mdfc_sql_data_collection_rule_id" = jsonencode({ value = local.ama_mdfc_sql_data_collection_rule_id }) "ama_vm_insights_data_collection_rule_id" = jsonencode({ value = local.ama_vm_insights_data_collection_rule_id }) "log_analytics_workspace_id" = jsonencode({ value = local.log_analytics_workspace_id }) } subscription_placement = { "connectivity" = { "management_group_name" = "connectivity" "subscription_id" = var.subscription_ids["connectivity"] } "identity" = { "management_group_name" = "identity" "subscription_id" = var.subscription_ids["identity"] } "management" = { "management_group_name" = "management" "subscription_id" = var.subscription_ids["management"] } # "security" = { # "management_group_name" = "security" # "subscription_id" = var.subscription_ids["security"] # } } }⚠️ Note the subscription placement object. Comment (CTR+K,CTRL+C) and uncomment (CTRL+K,CTRL+U) as needed depending on how many subscriptions you are specifying