Entra ID & Identity

Designing Cloud-Native on Azure with Entra ID–centric RBAC

Ad-hoc subscriptions tend to sprawl. Policies drift, teams request exceptions, and security becomes reactive. Azure Landing Zones (ALZ) in 2025 provide a...

Azure landing zones and Entra ID centric RBAC. Entra ID and Identity article banner on grbadhon.com

Why Azure Landing Zones vs. ad-hoc subscriptions

Ad-hoc subscriptions tend to sprawl. Policies drift, teams request exceptions, and security becomes reactive. Azure Landing Zones (ALZ) provide a scalable, opinionated baseline that separates platform from workloads, centralises identity, and automates governance.

ALZ gives you: a consistent Management Group hierarchy, policy assignments at the right scopes, platform subscriptions for shared services, and standardised RBAC backed by Microsoft Entra ID. The result is faster onboarding, predictable security, and lower ops overhead. The identity half of that rests on Conditional Access policy design, because a landing zone with tidy RBAC and no access conditions is only half governed.

Reference architecture

code
Tenant Root Group
└─ <org> (mg: contoso)
   ├─ Platform (mg: contoso-platform)
   │  ├─ Management (sub: mgmt)
   │  │   ├─ Monitoring - Log Analytics, Monitor, Sentinel
   │  │   └─ Automation - Image gallery, update mgmt
   │  └─ Connectivity (sub: hub)
   │      ┌──────── Hub VNet ────────┐
   │      │ Azure Firewall           │
   │      │ Private DNS Resolver     │
   │      │ DDoS Plan, Bastion       │
   │      │ ER/VPN GW, NAT Gateway   │
   │      └───────────┬──────────────┘
   │                  │
   ├─ LandingZones (mg: contoso-lz)
   │   ├─ Corp (mg)
   │   │   ├─ App1 Sub - Spoke VNet - PE to hub - Private Endpoints
   │   │   └─ App2 Sub - Spoke VNet - PE to hub - Private Endpoints
   │   └─ Online (mg)
   │       └─ App3 Sub - Internet facing
   └─ Sandboxes (mg)

Identity plane: Microsoft Entra ID
 - Groups: Platform-Admins, NetOps, SecOps, AppTeam-App1
 - PIM eligible assignments for Azure RBAC
 - Workload identities: Managed Identities, Entra Workload ID for AKS and CI pipelines
 - Access Packages for governed onboarding

Design notes:

  • Hub is platform-owned. No workload resources in hub. Spokes connect via peering. Private Endpoints land in spokes. Private DNS zones are in hub and linked to spokes.
  • Management subscriptions host shared monitoring and security tooling.
  • Policy is assigned at the LandingZones and child MGs. Exemptions are scoped narrow and time-bound.

Entra ID–centric RBAC model

Principles

  • Assign roles to Entra ID groups, not individuals.
  • Use PIM so roles are eligible and time-bound with approval and MFA.
  • Separate platform roles from workload roles. Platform teams operate the hub, policy, and monitoring. App teams own their subscriptions and resource groups.

Platform roles

  • Platform-Admins: built from custom role with limited capabilities. Avoid Owner. Combine with User Access Administrator only when needed for break-glass.
  • NetOps: Network Contributor on the hub subscription and on vnet objects where required.
  • SecOps: Security Admin on Sentinel and security resources. Reader at high scope.

Workload roles

  • AppTeam-<app>: Subscription Contributor on dedicated app subscriptions. Resource Group Owner for their RGs. No write access to platform resources.

Custom roles Create small, capability-focused roles. Examples: Policy-Reader-Only, PrivateDNS-Contributor, Firewall-Rules-Contributor. Store as IaC and review quarterly.

PIM eligibility

Governance: policy and deployment

Azure Blueprints is on the way out, but it has not gone yet, and the difference matters if you still have assignments in place. Checked on 26 September 2026: new blueprint definitions and versions stopped being creatable on 31 July 2026, existing definitions can no longer be modified after 31 October 2026, existing assignments freeze on 31 December 2026, and the service retires on 31 January 2027, at which point the API stops responding and anything not exported is deleted permanently. Microsoft’s blueprint retirement guidance points at deployment stacks for lifecycle and deny assignments, with template specs for versioning. The pattern to build on now is Management Groups plus Azure Policy plus IaC. Use Azure Policy initiatives to enforce guardrails: deny public IP, require private endpoints, enforce tags, restrict locations, enforce Defender plans, and enforce diagnostic settings.

Bicep – create MGs and assign policy

yaml
// target: tenant
// Deploy with elevated permissions at tenant scope

targetScope = &#039;tenant'

@description(&#039;Org short name')
param org string = &#039;contoso'
@description(&#039;Parent MG id, usually the tenant root MG id')
param parentMgId string
@description(&#039;Policy definition id to assign at LandingZones')
param policyDefId string

resource mgPlatform &#039;Microsoft.Management/managementGroups@2020-05-01' = {
  name: &#039;${org}-platform'
  properties: {
    displayName: &#039;Platform'
    parent: {
      id: &#039;/providers/Microsoft.Management/managementGroups/${parentMgId}'
    }
  }
}

resource mgLz &#039;Microsoft.Management/managementGroups@2020-05-01' = {
  name: &#039;${org}-lz'
  properties: {
    displayName: &#039;LandingZones'
    parent: {
      id: &#039;/providers/Microsoft.Management/managementGroups/${parentMgId}'
    }
  }
}

resource assignLz &#039;Microsoft.Authorization/policyAssignments@2022-06-01' = {
  name: &#039;lz-guardrails'
  scope: tenantResourceId(&#039;Microsoft.Management/managementGroups', mgLz.name)
  properties: {
    displayName: &#039;Landing Zones guardrails'
    policyDefinitionId: policyDefId
    enforcementMode: &#039;Default'
  }
}

Terraform – MGs and policy assignment

code
provider "azurerm" { features {} }

variable "org" { default = "contoso" }
variable "parent_mg_id" {}
variable "policy_def_id" {}

resource "azurerm_management_group" "platform" {
  display_name = "Platform"
  name         = "${var.org}-platform"
  parent_management_group_id = "/providers/Microsoft.Management/managementGroups/${var.parent_mg_id}"
}

resource "azurerm_management_group" "lz" {
  display_name = "LandingZones"
  name         = "${var.org}-lz"
  parent_management_group_id = "/providers/Microsoft.Management/managementGroups/${var.parent_mg_id}"
}

resource "azurerm_management_group_policy_assignment" "lz_guardrails" {
  name                 = "lz-guardrails"
  management_group_id  = azurerm_management_group.lz.id
  policy_definition_id = var.policy_def_id
}

The newsletter

Get the next Entra ID fix like this one by email

Subscribe and get the free 8-page Intune troubleshooting field guide (PDF), then new fixes about twice a month. From a Microsoft MVP.

Free. Confirm by email, unsubscribe in one click. Privacy.

CLI and PowerShell quick actions

code
# Create MGs
az account management-group create --name contoso-platform --display-name Platform --parent /providers/Microsoft.Management/managementGroups/<rootMgId>
az account management-group create --name contoso-lz --display-name LandingZones --parent /providers/Microsoft.Management/managementGroups/<rootMgId>

# Assign a built-in policy at the LZ MG
az policy assignment create \
  --name lz-guardrails \
  --display-name "Landing Zones guardrails" \
  --policy "/providers/Microsoft.Authorization/policyDefinitions/<policyDefId>" \
  --scope "/providers/Microsoft.Management/managementGroups/contoso-lz"

# RBAC via group-based assignment
az role assignment create \
  --assignee-object-id <entraGroupObjectId> \
  --assignee-principal-type Group \
  --role "Network Contributor" \
  --scope "/providers/Microsoft.Management/managementGroups/contoso-platform"

# Budget at subscription scope.
# Parameter names matter here: the command takes --budget-name, not --name, and it
# exposes no notification or contact-email parameters at all. Alert thresholds need
# az consumption budget create-with-rg, ARM, or the portal. The command group is
# still marked preview. Set a window that has not already closed: a budget with an
# end date in the past is accepted without complaint and then does nothing.
az consumption budget create \
  --budget-name sub-monthly \
  --amount 1000 \
  --category cost \
  --time-grain monthly \
  --start-date 2026-10-01 --end-date 2027-09-30 \
  --subscription <subId>
powershell
Connect-AzAccount

# Create MGs
New-AzManagementGroup -GroupName &#039;contoso-platform' -DisplayName 'Platform' -ParentId '/providers/Microsoft.Management/managementGroups/<rootMgId>'
New-AzManagementGroup -GroupName &#039;contoso-lz' -DisplayName 'LandingZones' -ParentId '/providers/Microsoft.Management/managementGroups/<rootMgId>'

# Assign policy
New-AzPolicyAssignment -Name &#039;lz-guardrails' -DisplayName 'Landing Zones guardrails' `
  -Scope &#039;/providers/Microsoft.Management/managementGroups/contoso-lz' `
  -PolicyDefinitionId &#039;/providers/Microsoft.Authorization/policyDefinitions/<policyDefId>'

# RBAC assignment to an Entra group
New-AzRoleAssignment -ObjectId <entraGroupObjectId> -RoleDefinitionName &#039;Network Contributor' `
  -Scope &#039;/providers/Microsoft.Management/managementGroups/contoso-platform'

Naming and tagging standards

Keep names short, consistent, and parsable. Use tags for metadata and cost allocation.

ResourcePatternExampleNotes
Management Group<org>-<pillar>contoso-platformpillar: platform, lz, sandboxes
Subscription<org>-<purpose>-<env>contoso-hub-netpurpose: mgmt, hub, dev, prod
Resource Grouprg-<app>-<env>-<region>rg-app1-dev-weenv: dev, test, prod
VNetvnet-<scope>-<env>-<region>vnet-hub-prod-wescope: hub or app name
Subnetsn-<purpose>sn-firewallpurpose: spoke, pe, agw, db
Storagest<app><env><nnn>stapp1prd123follows the global storage naming rules

Tags

  • costCenter, owner, app, env, dataClass, businessUnit, managedBy, deploymentVersion
  • Require tags via policy at MG. Block deploy if missing owner and costCenter.

Cost and operations

  • Budgets and alerts with Azure Cost Management. Route to Teams or email. Use anomaly detection.
  • FinOps quick wins: put non-production compute on a start and stop schedule, buy reservations or savings plans only once a workload has three months of steady baseline, move cold blob data to cool or archive tiers, and delete unattached managed disks, which keep billing long after the VM they belonged to is gone.
  • Observability: enable diagnostic settings via policy to send to Log Analytics and Storage. Standardize KQL workbooks and alerts per landing zone.

Common pitfalls

  • Assigning Owner at high scopes and bypassing policy. Use custom roles and PIM instead.
  • Mixing platform and workload in the hub. Keep hubs clean and minimal.
  • Private DNS split-brain. Centralize zones in hub and link to spokes.
  • Unscoped exemptions that never expire. Time-bound and reviewed.
  • Drift between IaC and portal changes. Audit with policy compliance and GitOps.

Rollout plan

Week 1 – Foundation

  • Confirm org and security requirements. Approve MG hierarchy and naming. Stand up Platform and LandingZones MGs.
  • Create core Entra groups. Configure PIM settings and access reviews.

Week 2 – Connectivity and identity

  • Build hub subscription with Firewall, Private DNS Resolver, Bastion, and gateways as needed.
  • Establish peering pattern, DDoS plan, and Private Endpoint standards. Document network rules workflow.

Week 3 – Governance and automation

  • Assign core policy initiatives at LZ MG. Enable diagnostics, tag enforcement, location allowlist, Defender plans.
  • Implement IaC pipelines for Bicep and Terraform. Introduce Deployment Stacks for lifecycle and prune.

Week 4 – Onboard and refine

  • Create first spoke subscriptions for App1 dev and prod. Apply RBAC via group assignments. Onboard monitoring and budgets.
  • Run compliance scan, fix drifts, capture lessons learned and publish a catalog for app teams.

Common questions

Platform teams operate the hub, policy and monitoring, so they hold roles such as a limited custom Platform-Admins role, Network Contributor on the hub subscription and Security Admin on Sentinel. Application teams own their own subscriptions and resource groups as Contributor or Resource Group Owner, with no write access to platform resources.

Assign roles to Microsoft Entra ID groups, never to individuals. Make the assignments eligible through Privileged Identity Management so elevation is just-in-time, requires justification and a ticket reference, enforces multi-factor authentication and expires after a short activation window. Run access reviews quarterly so memberships that are no longer needed are removed.

No. Azure Blueprints is retired, and the current pattern combines Management Groups, Azure Policy initiatives and infrastructure as code in Bicep or Terraform. Policy initiatives carry the guardrails: deny public IP addresses, require private endpoints, enforce tags, restrict locations, enforce Microsoft Defender plans and enforce diagnostic settings across the hierarchy.

Split-brain private DNS is the usual cause. Private DNS zones belong in the hub, linked out to the spokes, so every workload resolves private endpoint names the same way. Creating duplicate zones inside individual spokes produces inconsistent answers. The other frequent faults are unscoped policy exemptions that never expire and portal changes drifting away from the code.

Creating management groups under the tenant root and assigning policy at that level is a tenant scope deployment, and the sample Bicep is written with targetScope set to tenant and deployed with elevated permissions. Role assignments themselves are made against the group object id with the principal type set to Group, at the management group scope.

The standard tag set is costCenter, owner, app, env, dataClass, businessUnit, managedBy and deploymentVersion, required by policy at management group level. Deployments that lack owner and costCenter should be blocked outright. Tags carry cost allocation and ownership metadata, so keep names short, consistent and parsable and apply the same convention everywhere.

The newsletter

Free: the Intune troubleshooting field guide

Subscribe and get my 8-page PDF: 13 common Intune problems, the order to check them in, and the fix for each. Then Microsoft 365 fixes from the field, about twice a month. From G.R Badhon, Microsoft MVP.

  • The field guide, sent the moment you confirm
  • New Intune, Entra ID and Purview guides as they publish
  • One field-tested fix or script per issue

Free. Confirm by email, unsubscribe in one click. Privacy.