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

by G.R Badhon

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) in 2025 provide a scalable, opinionated baseline that separates platform from workloads, centralizes identity, and automates governance.

ALZ gives you: a consistent Management Group hierarchy, policy assignments at the right scopes, platform subscriptions for shared services, and standardized RBAC backed by Microsoft Entra ID. The result is faster onboarding, predictable security, and lower ops overhead.

Reference architecture

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-: 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

  • Everyone gets least privilege by default. Elevation via PIM with just-in-time.
  • Require justification, ticket ID, and set activation duration to minimal. Use access reviews quarterly.

Governance: policy and deployment

Azure Blueprints retired. The modern pattern is Management Groups + Azure Policy + 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

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

targetScope = 'tenant'

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

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

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

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

Terraform – MGs and policy assignment

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
}

CLI and PowerShell quick actions

# 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
az consumption budget create \
  --name sub-monthly \
  --amount 1000 \
  --category cost \
  --time-grain monthly \
  --start-date 2025-09-01 --end-date 2026-08-31 \
  --subscription <subId> \
  --notification key=warn80 enabled=true operator=GreaterThan threshold=80 \
  --notification key=crit95 enabled=true operator=GreaterThan threshold=95 \
  --contact-emails finops@contoso.com
Connect-AzAccount

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

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

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

Naming and tagging standards

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

Resource Pattern Example Notes Management Group – contoso-platform pillar: platform, lz, sandboxes Subscription — contoso-hub-net subpurpose: mgmt, hub, dev, prod Resource Group rg— rg-app1-dev-we env: dev, test, prod VNet vnet— vnet-hub-prod-we scope: hub or app name Subnet sn- sn-firewall purpose: spoke, pe, agw, db Storage st stapp1prd123 follows global 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:
  • 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.

You may also like