Skip to main content

Deploying Azure Landing Zones with the Terraform Accelerator

ยท 19 min read

As part of the Azure Spring Clean 2025 event for 2025, we are here to take a look at Azure Landing Zones, specifically Platform Landing Zones, and the deployment of the Platform Landing Zone, using an accelerator and Azure DevOps for the CI/CD.

Azure Spring Clean 2025

๐Ÿ—๏ธ Introduction to Azure Landing Zonesโ€‹

Azure Landing Zones provide a structured approach for designing and implementing cloud environments in Azure. They are essential for organizations looking to migrate, modernize, and innovate their applications at scale, mainly because of the considerations you make in designing and implementating them, considerations such as how your workloads are going to connect to the internet, how each service connects, and importantely, how your organisation will use Cloud - I saw a comment from someone the other day (Cloud is not WHERE you work, its HOW you work).

info

An Azure landing zone is an environment that follows key design principles across eight design areas. These design principles accommodate all application portfolios and enable application migration, modernization, and innovation at scale. An Azure landing zone uses subscriptions to isolate and scale application and platform resources. Subscriptions for application resources are called application landing zones, and subscriptions for platform resources are called platform landing zones.

An Azure landing zone architecture is scalable and modular to meet various deployment needs. The repeatable infrastructure allows you to consistently apply configurations and controls to every subscription. Modules make deploying and modifying specific Azure landing zone architecture components easy as your requirements evolve.

Azure Landing Zones

More information on Azure Landing Zones, can be found in the Microsoft Cloud Adoption Framework for Azure, Landing Zones specifically sits under the Ready phase.

๐Ÿš€ Understanding Azure Landing Zone Acceleratorsโ€‹

Azure Landing Zone Accelerators are automation frameworks designed to expedite the deployment of Azure Landing Zone architecture. They come in three flavors:

  • Bicep Accelerator
  • Terraform Accelerator
  • Portal Accelerator

These Accelerators, adopt a best-practice approach (but also opinionated) to deploy an Azure Landing Zone, from scratch, whether Brownfield (already existing) or Greenfield (new), and they have been going through a transformation, from previous accelerators (marked as vNext) to adopt a more moduler approach with both Bicep and Terraform deployments aligned to Azure Verified Modules. These Accelerators are what Microsoft would run in a VBD workshop (I believe they would use the Portal accelerator).

I want to make clear, these just like the Cloud Adoption Framework, are best pratices but also gernalized to support multiple types of organisations, so make sure you adjust them to suit your needs and organisations, or even mark it as a northstar to aim towards, but not necessary what you need in that moment, but also consider strategically where you want to go, ie platform engineering, de-centralized or centralized operations, all these decisions will determine how your Landing Zone structure is based and used (ie if you don't like the word Online, change it to Public, your business needs to understand where to put workloads and how they will work (not spending the time fighing over what something is named)).

With Landing Zones, theres the Platform Landing Zone and the Application Landing Zone, the Platform Landing Zone is the shared services like identity, connectivity, and management, where as the Application Landing Zone is specific environments for particular applications or workloads (consider Arc, maybe APIM, anything generazlied - this is really where your business logic and IP sits).

Azure Landing Zones - Customer Journey

For this article, we will be discussing the:

  • Bootstrap of our environment (into Azure DevOps)
  • Deployment of Azure platform Landing Zone components using Terraform

Azure Landing Zones - Customer Journey

๐Ÿ”„ Deploying Azure Landing Zones with Terraformโ€‹

๐Ÿ› ๏ธ Bootstrapโ€‹

It begins with a Bootstrap process, which is the initial setup of the Azure DevOps environment, including creating a new project, repository, and service connection. This process is automated using a mix of PowerShell and Terraform.

Azure Landing Zones - Customer Journey

To bootstrap, we will make use of the:ALZ-PowerShell-Module, this script will help bring together the different dependencies and Terraform bootstraping to setup our Azure DevOps environment, Terraform state storage account and bring in the necessary Platform Landing Zone library files for our deployment.

Azure Landing Zones - Customer Journey

The bootstrap for Azure DevOps includes self-hosted agents (Container Apps or Container Instances) as optional, and preconfigured pipelines, including validation and branch policies with approval steps, so a foundational platform to work towards.

ComponentDescriptionNotes
Azure Resources
Resource Group for StateContainer for Terraform state storage resourcesTerraform only
Storage Account and Container for StateStores Terraform state files securelyTerraform only
Resource Group for IdentityContainer for managed identity resources
User Assigned Managed Identities (UAMI) with Federated CredentialsIdentities for secure pipeline executionFor Plan and Apply
Permissions for the UAMIRBAC assignments needed for deploymentOn state storage container, subscriptions, and management groups
[Optional] Container Registry for Azure DevOps Agent ImageStores custom agent container imagesFor self-hosted agents
[Optional] Container Instances hosting Azure DevOps AgentsRuns pipeline jobs in your Azure environmentFor self-hosted agents
[Optional] Virtual network, subnets, private DNS zone, and private endpointNetwork resources for private connectivityFor enhanced security
Azure DevOps Resources
Project (can be supplied or created)Azure DevOps project for Landing Zone resourcesCan use existing or create new
Repository for the ModuleStores Landing Zone Terraform codeMain implementation repository
Repository for the Pipeline TemplatesStores CI/CD pipeline definitionsEnables template reuse
Starter Terraform module with tfvarsPre-configured Terraform configurationCustomizable baseline
Branch policyEnsures code quality and reviewsPrevents direct main branch changes
Pipeline for Continuous IntegrationValidates and plans Terraform changesNon-destructive verification
Pipeline for Continuous DeliveryImplements Terraform changes in AzureCreates/updates resources
Environment for PlanIsolated context for planning stageSeparates planning permissions
Environment for ApplyIsolated context for apply stageSeparates deployment permissions
Variable Group for BackendStores Terraform backend configurationUsed across pipelines
Service Connections with Workload identity federation for Plan and ApplySecurely connects Azure DevOps to AzureUses OIDC for enhanced security
Service Connection Approvals, Template Validation, and Concurrency ControlProvides governance for deploymentsEnsures controlled changes
Group and Members for Apply ApprovalTeam responsible for approving changesChange control mechanism
[Optional] Agent PoolCollection of build/release agentsFor self-hosted agents
tip

Make sure you check out the following resources for more information on the Azure Landing Zone Accelerator and Azure Landing Zone Library, these are your sources of truth:

If you have issues, you can also raise them on the ALZ-PowerShell-Module GitHub repository.

Before we get started, we need some pre-requisites

  • 3 Azure subscriptions (1 for Connectivity, 1 for Identity, and 1 for Connectivity) - (for this demo, I will be using a single subscription) we will also need the bootstrap and Terraform deployment IDs. Permissions Required for Management Group and Subscriptions:

  • Owner on your chosen parent management group:

The owner account will grant permissions to the identities running the management group deployment. Owner on each of your 3 Azure landing zone subscriptions.

  • A PAT token for the creation of a Service Connection in Azure DevOps (Agent Pools (Read & manage), Build (Read & execute), Code (Full), Environment (Read & manage), Graph (Read & manage), Pipeline Resources (Use & manage), Project and Team (Read, write & manage), Service Connections (Read, query & manage), and Variable Groups (Read, create & manage).)_ This token is only needed for the duration required to bootstrap the environment and can be revoked after.

Once we have those pre-requisites, we can proceed with the bootstrapping process.

tip

I recommend starting with the Azure Landing Zone Accelerator Checklist, this will help you understand the requirements and dependencies for the deployment, and ensure you have everything you need before you start the process.

Azure Landing Zones - Customer Journey

We will bootstrap the environment, to create our Azure DevOps environment, and then deploy the base components for a Platform Landing Zone and the associated archetypes for the fictional company of Contoso. To do this, we will be using the Terraform - Azure Verified Modules for Platform Landing Zone (ALZ) starter modules and configuration in the Australia East Azure region.

info

Before you start, make sure you request a parallelism grant for Azure DevOps, by default, Azure DevOps has a limit of 1 concurrent job, to request a free parallelism grant, please fill out the following form https://aka.ms/azpipelines-parallelism-request

๐Ÿ“‹ Bootstrap Processโ€‹

  1. First login to Azure 'az login' and then run the following commands:
  2. Next we need the ALZ PowerShell Module, so we will install that:
# Check if the ALZ module is installed
$module = Get-InstalledModule -Name ALZ -ErrorAction SilentlyContinue

if ($null -eq $module) {
# If the module is not installed, install it
Install-Module -Name ALZ -Force
Write-Output "ALZ module installed successfully."
} else {
# If the module is installed, update it
Update-Module -Name ALZ
Write-Output "ALZ module updated successfully."
}

Azure Landing Zones - Customer Journey

info

Three sets of configuration can be supplied to the accelerator to pre-configure it.

The available configuration inputs are:

We will start with th bootstrap configuration file, this will be used to create the Azure DevOps environment, and the Terraform state storage account and container, then we adjust the Platform Landing Zone configuration file to control what Azure resources we will need to deploy (ie Hub and Spoke, or Virtual WAN, Bastion etc) and the Platform Landing Zone library folder, which will contain the Archetype definitions and policy assignments for greater flexibility.

  1. Let's create the local configuration files for the bootstrap and Platform Landing Zone deployment:
New-Item -ItemType "file" c:\Code\accelerator\config\inputs.yaml -Force
New-Item -ItemType "file" c:\Code\accelerator\config\platform-landing-zone.tfvars -Force # Exclude this line if using FSI or SLZ starter modules
New-Item -ItemType "directory" c:\Code\accelerator\config\lib
New-Item -ItemType "directory" c:\Code\accelerator\output
  1. Now we need to open the inputs.yaml file and add the following configuration found here: inputs-azure-devops.yaml.

It should look something like below:

# For detailed instructions on using this file, visit:
# https://aka.ms/alz/accelerator/docs

# Basic Inputs
iac_type: "terraform"
bootstrap_module_name: "alz_azuredevops"
starter_module_name: "platform_landing_zone"

# Shared Interface Inputs
bootstrap_location: "australiaeast"
starter_locations: ["australiaeast"]
root_parent_management_group_id: "Contoso"
subscription_id_management: "00000000-0000-4000-8000-000000000001"
subscription_id_identity: "00000000-0000-4000-8000-000000000002"
subscription_id_connectivity: "00000000-0000-4000-8000-000000000003"

# Bootstrap Inputs
azure_devops_personal_access_token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# azure_devops_agents_personal_access_token: "<token-2>"
azure_devops_organization_name: "Contoso"
use_separate_repository_for_templates: true
bootstrap_subscription_id: "00000000-0000-4000-8000-000000000004"
service_name: "plz"
environment_name: "mgmt"
postfix_number: 1
azure_devops_use_organisation_legacy_url: false
azure_devops_create_project: true
azure_devops_project_name: "ADO-PALZ"
use_self_hosted_agents: false
use_private_networking: true
allow_storage_access_from_my_ip: false
apply_approvers: ["[email protected]"]
create_branch_policies: true

# Advanced Inputs
bootstrap_module_version: "latest"
starter_module_version: "latest"
output_folder_path: "c:/Code/accelerator/output"
tip

For further customisation, make sure you take a look at the variables.tf file directly in the accelerator bootstrap modules GitHub, it can show further options that you can add to the bootstrap, such as the storage account replicatin type for your Terraform state files, or additinal custom roles and resource naming.

Now that we have configured the variables required for our bootstrap, let us define the Terraform variables for the Platform Landing Zone deployment, this will be used to determine the Azure resources we will deploy, such as the Hub and Spoke, Virtual WAN, Bastion, etc, and this is the platform-landing-zone.tfvars file. I recommend copying one from one of the already pre-existing Scenarios and modifying to suit your needs. For my purposes, I will be going with a Single region hub and spoke VNET with Azure Firewall.

  1. Open the platform-landing-zone.tfvars file and add the configuration and modify for your needs, for my purposes, I will be using the following configuration: platform_landing_zone/examples/full-single-region/hub-and-spoke-vnet.tfvars.
info

The platform-landing-zone.tfvars file is a crucial configuration for deploying an Azure Landing Zone using the Azure Landing Zones Accelerator with Terraform. This file defines the variables that customize your Azure foundation by your requirements, and this file will be your main configuration file for the deployment of the Platform Landing Zone.

Key Components of the File

Built-in Replacements

The file uses a templating system with $${variable_name} syntax to reference predefined values, such as:

  • Azure locations (e.g., $${starter_location_01})
  • Subscription IDs (e.g., $${subscription_id_management})
  • Management group IDs

These built-in replacements help maintain consistency throughout the configuration.

Custom Replacements

The configuration defines custom naming patterns and references for:

  1. Resource Names - Standardizing naming conventions for:

    • Resource groups
    • Virtual networks
    • Azure Firewall
    • Log Analytics workspace
    • And many other resources
  2. IP Address Spaces - Defining network address spaces for the hub network:

    • Virtual network address space
    • Subnet address prefixes
    • Firewall subnet

Management Resources

This section configures core management resources including:

  • Log Analytics workspace
  • Automation account
  • Azure Monitor Agent settings
  • Data Collection Rules for monitoring

Management Groups and Policy

The file configures:

  • Management group hierarchy structure
  • Policy assignments and overrides, for example Defender for Cloud Settings
  • Subscription placement within management groups

Connectivity Resources

The hub-and-spoke network topology is defined with:

  • DDoS protection plan
  • Virtual network configuration
  • Azure Firewall and routing tables
  • Virtual network gateways (ExpressRoute and VPN)
  • Private DNS zones and resolver
  • Azure Bastion

How to Modify This File

  1. Customize Basic Information
  • Email Contacts: Update security contact email addresses
  • Tags: Modify organization-specific tags
tags = {
deployed_by = "terraform"
technical_contact = "[email protected]"
environment = "production"
business_unit = "finance"
}
  1. Adjust Network Addressing

Modify the IP address ranges to match your organization's network plan:

primary_hub_address_space = "10.100.0.0/16"
primary_hub_virtual_network_address_space = "10.100.0.0/22"
  1. Change Resource Naming

Update naming conventions to align with your organization's standards:

log_analytics_workspace_name = "law-prod-eastus"
automation_account_name = "aa-prod-eastus"
  1. Modify Policy Settings

Adjust policy enforcement levels for your compliance requirements:

Enable-DDoS-VNET = {
enforcement_mode = "Default" # or "DoNotEnforce"
}
  1. Add or Remove Resources

You can customize which components are deployed by adding or removing sections:

  • Remove the VPN gateway if not needed
  • Add additional hub networks for multi-region deployments
  • Modify Azure Firewall SKU based on requirements

Also make sure you run a terraform validate and terraform fmt to validate the configuration and the Terraform formatting is correct on the file.

Make sure to check out the Options page for the Terraform Platform Landing Zone, as it will give you more information on the common scenarios, such as turning off DDOS protection plans, adding additional IP ranges etc.

And don't worry if you don't get this right the first time, you can always adjust and redeploy, this is the beauty of Infrastructure as Code. I work in an iterative approach, so it's always good to get something working, then adjust and improve, rather than trying to get it perfect the first time, and the Terraform plan and validate pipelines help with this approach.

  1. We are close, the last thing we will add is a custom library folder. This isn't required for base Platform Landing Zones, however, I recommend adding it in, for additional flexibility, especially as you start to deploy more complex environments and archetypes within your organization. You can refer to the Azure Landing Zones Library for more information on how to create your own custom library and additional information. Still, for now we are going to copy the alz folder from the Azure Landing Zones Library and place it in the lib folder in our config directory.

By default, the architecture that will be deployed will be (you can also refer to the README file in the lib folder for more information):

You can adujust the Management Group names and parent/child relationships by editing the alz.alz_architecture_definition.json file in the lib\architecture_definitions folder, and th architectype definitions allow you to configure the type of policy definitions, role assignments that are deployed to specific Management Groups with a certain archetype, for example you could have workload Landing Zones of 'Workload' archetype with specific policy definitions and role assignments, that may be different from the root or Platform groups, and Management Groups could share this same archetype, so you can have a consistent policy and role assignment across your environment.

tip

Not required, but make the alzlibtool tool, this is a tool that can help you create and manage your own custom library for your Azure Landing Zones, and can be used to check policy and Azure Landing Zone architecture definition structure, and document your own custom library.

  1. Now that the configuration files for the bootstrap, Terraform are in place, and the architectures, it's time to start the bootstrap. Run the following command to start the bootstrap process:
tip

If you need to make any last-minute changes, you can manually change the Terraform code after the Terraform plan and before the application. Check your local output folder. It is not something I would rely on - ideally the platform tfvars and yaml input file should be updated, but in a pinch, you can make manual changes. I had to do this recently, when deploying a Landing Zone into New Zealand North. I had to manually update the location of the Log Analytics workspace, as it has not been supported in that region yet. However, for Platform resources, you can also make this change once the code is in the repository.

Deploy-Accelerator `
-inputs "C:\Code\accelerator\config\inputs.yaml", "C:\Code\accelerator\config\platform-landing-zone.tfvars" `
-starterAdditionalFiles "C:\Code\accelerator\config\lib" `
-output "C:\Code\accelerator\output"

Azure Landing Zones - Customer Journey

Once completed, in Azure, you should have two resource groups - one for your Managed identities that will be linked to 2 Service Connections in Azure DevOps for Plan and Apply, and one for your Terraform state file.

Azure Landing Zones - Customer Journey

In Azure DevOps, you should have a new project, repository, and service connection, with the pipelines and environments set up for the Plan and Apply stages.

AzureDevOps Azure Landin Zone Code

info

The plz acronym I am using, is meant to indicate 'Platform Landing Zone'.

And Pipelines preconfigured - Continuous Integration (ie Terraform Validate and Plan) and Continuous Delivery (ie Terraform Apply) with the approvers and branch policies in place.

Azure DevOps Azure Landing Zone Pipelines

tip

I recommend renaming the pipelines, in Azure DevOps, so they are more descriptive, ie, 'Terraform Plan' and 'Terraform Apply' - pretty simplified, but can make more sense to people consuming the pipelines.

Azure DevOps Azure Landing Zone Pipelines

Now, let's run the Continuous Integration pipeline to see what the Terraform plan looks like.

Azure DevOps Azure Landing Zone Pipelines

As we can see, it validates and will deploy our full hub and spoke (both expressroute and VPN gateways) so that would need tweaking for my environment, but this is the beauty of Infrastructure as Code, you can see what is going to be deployed before it is deployed, and make the necessary adjustments, by opening up a new branch and adjusting the the platform-landing-zone.auto.tfvars, and run validate and plan on that branch until correct.

So, now let's deploy. Once you are happy with the plan, you can run the Continuous Delivery pipeline to deploy the Platform Landing Zone.

warning

Be aware that the initial deployment could take a while, especially if deploying all the default policies, and DNS zones. As such, the entire deployment is not shown in the GIF below, but you can see the new Platform Management Groups and core hub resources that have started to be created.

Azure DevOps Azure Landing Zone Pipelines

And once completed, you should have a full Platform Landing Zone deployed, with the Management Groups, Policies, and core resources in place.

info

You can rerun the Continuous Delivery pipeline, and select Destroy if you want to remove all the platform resources and start your deployment from scratch, in a production scenario, I recommend removing that, but not the additional approval step so that you can have a manual check before the Apply stage. The approval is done in Azure DevOps at the Service Connection, under Approval and Checks.

Azure DevOps Azure Landing Zone Pipelines Azure DevOps Azure Landing Zone Pipelines

โœ… Conclusionโ€‹

The Azure Landing Zone Terraform Accelerator offers a robust foundation for organizations looking to implement a well-architected Azure environment.

Through this article, we've explored how to:

  1. Bootstrap your environment with automation using the ALZ PowerShell module
  2. Configure and deploy Platform Landing Zone components using Infrastructure as Code (Terraform)
  3. Establish governance through management groups, policies, and controlled Azure DevOps pipelines.

Next Steps After Deployment

Once your Platform Landing Zone is established, consider these follow-up activities:

  • Document your environment: Create detailed documentation explaining your Landing Zone design choices and customizations _(make sure to checkout alzlibtool)
  • Establish operational procedures: Define processes for managing the environment, including approvals and adjustments to the platform
  • Plan your Application Landing Zones: Design the specific landing zones for your workloads based on your organization's needs and investigate Subscription vending.

Resources for Continued Learning

For the GitHub repos, remember to view the Issues and Pull Requests, you can learn a lot from what other people have contributed to the initiatives, and the Issues being raised.

Remember, the Landing Zone is not a one-time deployment but an evolving foundation that grows with your organization's cloud journey. Regular reviews and updates will ensure it continues to support your changing business needs while maintaining security and governance standards, and how the business plans on consuming this - is not to be underestimated in the design and implementation of this.