Azure Landing Zone

Deploy a default Azure Landing Zone using the Bicep repo.


When you are onboarding VMs at scale then it makes sense to prepare the target environment first. The customer, Wide World Importers, has requested that Azure Landing Zones (ALZ) is used as they are keen to be aligned to the Microsoft best practice recommendations and leverage the IP baked into the official repos. This will be the first step in the target environment preparation.

The microsite has a full set of Cloud Adoption Framework documentation specifically for hybrid and multi-cloud landing zone scenarios.

This is a small POC and you have only been provided with a single subscription but it is still possible to apply ALZ. The expectation is that multiple subscriptions would be used in production as per the Azure Landing Zones documentation.

There are three recommended Microsoft repos for Azure Landing Zones:

The first two are recommended approaches for partners and customers deploying via infrastructure as code. The ARM repo underpins the Deploy to Azure options.

In this lab we will use the Bicep repo.


Wide World Importers would like a vanilla deployment of Azure Landing Zones applied to the POC environment to understand how that impacts the virtual machine onboarding.

Use the Bicep modules. The deployment follows the order in the Deployment Flow.

High-Level Deployment

⚠️ There is no need here for Azure networking services or for custom role assignments, so steps 5, 6 and 9 will be skipped.

Management Groups

You need to have the ability to create a custom management group below the root. Elevate your permissions and assign Owner at the root level.

Elevate your AAD permission

  1. Log in to the Azure Portal as an ID with Global Administrator role

  2. Navigate to the Azure Active Directory properties page

  3. Toggle Access management for Azure resources to Yes and click Save

Assign Owner role at root

  1. Open the Cloud Shell

  2. Get your AAD object ID

    id=$(az ad signed-in-user show --query id --output tsv)
  3. Add the Owner role at root

    az role assignment create --scope / --role Owner --assignee $id

    For information, the root (/) is above the Tenant Root Group (/<tenant_id>) management group that is automatically created if you were to enable Management Groups in the portal.

Clone the ALZ-Bicep repo

  1. Clone the repo

    In Cloud Shell:

    git clone
  2. Change directory

    cd ~/ALZ-Bicep
  3. Update bicep

    az bicep upgrade

Create the management groups

  1. Deploy the Management Groups Module

    az deployment tenant create \
      --template-file infra-as-code/bicep/modules/managementGroups/managementGroups.bicep \
      --parameters @infra-as-code/bicep/modules/managementGroups/parameters/managementGroups.parameters.all.json \
      --location westeurope

Custom Policy Definitions

  1. Deploy the Custom Policy Definitions Module

    az deployment mg create \
      --template-file infra-as-code/bicep/modules/policy/definitions/customPolicyDefinitions.bicep \
      --parameters @infra-as-code/bicep/modules/policy/definitions/parameters/customPolicyDefinitions.parameters.all.json \
      --location westeurope \
      --management-group-id alz
  2. Display the custom policies

    The custom roles are are defined at the Azure Landing Zones (alz) management group.

    Select the management group, then click on Policy and then Definitions.

    Note that the set of in-built and custom policies are always being updated, so expect this list to change as more are contributed.

Custom Role Definitions

  1. Deploy the Custom Role Definitions Module

    az deployment mg create \
      --template-file infra-as-code/bicep/modules/customRoleDefinitions/customRoleDefinitions.bicep \
      --parameters @infra-as-code/bicep/modules/customRoleDefinitions/parameters/customRoleDefinitions.parameters.all.json \
      --location westeurope \
      --management-group-id alz

Logging and Security

Create a resource group (alz-logging) and deploy the default log analytics workspace and solutions.

  1. Create a resource group

    az group create --name alz-logging --location westeurope
  2. Deploy the Logging & Security Module

    az deployment group create \
      --template-file infra-as-code/bicep/modules/logging/logging.bicep \
      --parameters @infra-as-code/bicep/modules/logging/parameters/logging.parameters.all.json \
      --parameters parLogAnalyticsWorkspaceLocation=westeurope \
      --parameters parAutomationAccountLocation=westeurope \
      --resource-group alz-logging
  3. Display the resources

    Show the resources in the alz-logging resource group.

    The various solutions work with the automation account to log diagnostics data to the ‘alz-log-analytics’ Log Analytics workspace.

Subscription Placement

The on prem virtual machines are internal facing systems and will be onboarded to a subscription within the Corp management group.

  1. Get the subscription ID

    subscription_id=$(az account show --query id --output tsv)
  2. Deploy the Subscription Placement Module

    Move the subscription under the Corp management group. The id for this management group is alz-landingzones-corp.

    az deployment mg create \
      --template-file infra-as-code/bicep/modules/subscriptionPlacement/subscriptionPlacement.bicep \
      --parameters '{"parTargetManagementGroupId": {"value": "alz-landingzones-corp"}, "parSubscriptionIds": {"value": ["'$subscription_id'"]}}' \
      --location westeurope --management-group-id alz

    The subscription will inherit any policy assignments at

    • Azure Landing Zones

    • Landing Zones

    • Corp

      As well as anything assigned at the subscription scope itself.

Built-In and Custom Policy Assignments

The policy assignment module allows you to customise the policy assignment of both built-in and custom policy definitions.

The main Policy Assignment readme includes examples and info as this is one of the more complex modules and facilitates a lot of customisation.

You will deploy the module using the Azure Landing Zone default policy assignments.

  1. Get the workspace id

    alz_logging_workspace_id=$(az monitor log-analytics workspace show --resource-group alz-logging --workspace-name alz-log-analytics --query id --output tsv)
  2. Set the email for Defender for Cloud
  3. Deploy the default policy assignments

    az deployment mg create \
      --template-file infra-as-code/bicep/modules/policy/assignments/alzDefaults/alzDefaultPolicyAssignments.bicep \
      --parameters @infra-as-code/bicep/modules/policy/assignments/alzDefaults/parameters/alzDefaultPolicyAssignments.parameters.min.json \
      --parameters parLogAnalyticsWorkSpaceAndAutomationAccountLocation=westeurope \
      --parameters parLogAnalyticsWorkspaceResourceId=$alz_logging_workspace_id \
      --parameters parMsDefenderForCloudEmailSecurityContact=$email_security_contact \
      --location westeurope \
      --management-group-id alz

    Note that there is also an alzDefaultPolicyAssignments.parameters.all.json parameters file. The min version ensures the parDdosProtectionPlanId and parPrivateDnsResourceGroupId parameter values remain empty, as we don’t have a Connectivity subscription and will avoid DDOS Standard to keep costs down.. .

  4. View the policy assignments

    Select the subscription in the portal, click on Policies and then Assignments

  5. View the Enable Azure Monitor for VMs policy initiative

    Click on Enable Azure Monitor for VMs. Note that the logAnalytics_1 parameter has been set to the workspace ID.

    Click on View definition to see the set of policies within the initiative. Sort on Policy.

    The Enable Azure Monitor for VMs policy initiative includes deploy if not exists policies that will add the MMA Log Analytics extension and the Dependency agent and extensions to onboarded Azure Arc-enabled VMs.

Policy Definitions

The Azure Landing Zones creates a useful set of default platform resources, policies and RBAC role assignments. There are a number of custom and built-in policies that are applicable to Azure Arc-enabled Servers. Some are already assigned, and some are unassigned.

  1. Select the Azure Landing Zones management group

  2. Select Policy | Definitions

  3. Filter Categories to

    • Azure Arc
    • Monitoring
    • Security Center
  4. Search on “Arc

    The screenshot below shows a selection of the Azure Arc related policies and policy initiatives.

    In addition, the policies in the Guest Configuration category can be used with Azure Arc-enabled Servers as well as Azure servers. You will explore this in the later Governance lab.

    Note that searching on *arc" will also bring up policies containing search etc. Ignore these.

Policy Assignments

Before we move on, let’s quickly cover some of the key components involved in Policy assignments:

  • assignment info (name, display name, description)

  • policy or policy initiative id (or name)

  • scope

  • parameters

  • managed identity (system or user assigned, identity scope, role and location)

    The managed identity definition is only needed by the template deployments in deploy if not exist policies.

The Azure documentation has a maintained index of the built-in policies and policy initiatives, which then links to the definitions in the Azure Policy GitHub repo. Alternatively, you can search the Policy definitions using the CLIs or the portal.

Success criteria

Show your proctor:

  • Management group structure with your subscription under Corp
  • The policy assignments inherited by the subscription
  • The parameter values for the Enable Azure Monitor for VMs policy initiative assignment

Next Steps

The proof of concept environment has the default ALZ management groups, custom policy definitions, custom role definitions, standard set of policy assignments and the subscription is now under the correct management group to inherit the policy assignments.

Note that whilst the Bicep modules have been deployed individually, it is also possible to use an orchestration template such as the one for hub and spoke deployments. The Bicep file shows the individual module deployments and the explicit dependencies between them.

In the next lab we’ll configure a target resource group and service principal for onboarding.

Help us improve

Azure Citadel is a community site built on GitHub, please contribute and send a pull request

 Make a change