Part 1 of 1645 min read · 13 diagramsAI-assisted

Fundamentals & Governance

Table of Contents#

  1. Why Azure Gets Its Own Dedicated Series
  2. Azure's Geography — Regions, Availability Zones & Region Pairs
  3. Sovereign Clouds and Data Residency Boundaries
  4. The Tenant, Management Groups, Subscriptions & Resource Groups Hierarchy
  5. Designing a Subscription Structure That Scales
  6. Subscription Quotas and Limits — Planning Around Azure's Own Ceilings
  7. Governance: Azure Policy and Azure RBAC
  8. The Azure Well-Architected Framework
  9. The Shared Responsibility Model on Azure
  10. Azure Resource Manager — The Control Plane Underneath Everything
  11. Tools of the Trade: Portal, CLI, PowerShell & Cloud Shell
  12. Tagging and Resource Discovery at Scale
  13. Azure Resource Graph — Querying Your Entire Estate at Scale
  14. Billing Accounts: Enterprise Agreements vs. Microsoft Customer Agreements
  15. Understanding the Bill — Pricing Models, Reservations & Hybrid Benefit
  16. Cost Management, Budgets & Azure Advisor
  17. Azure Arc — Extending Governance to Hybrid and Multi-Cloud Resources
  18. A Full Worked Landing Zone Bootstrap, Start to Finish
  19. Part 1 CLI Cheat Sheet
  20. Common Mistakes and Interview Traps
  21. Worked Practice Problems
  22. Summary and What's Next

This series runs a single fictional company through all sixteen parts: Meridian Freight, a mid-size logistics brokerage moving its shipment-tracking platform onto Azure. Its footprint is deliberately small enough to reason about end to end — a public shipment-api, an internal rates-db, a driver-portal used by field staff, and a docs-processor pipeline that turns scanned bills of lading into structured data — but realistic enough that every architectural decision in this series has genuine stakes. Later parts build directly on the account structure, network, and governance model this chapter establishes.

Why Azure Gets Its Own Dedicated Series#

Every prior series in this course taught concepts that apply everywhere: replication (Databases & Storage Reliability), rolling deployments (Automation, CI/CD & GitOps), the CAP theorem (Reliability & Architecture Patterns), least privilege (DevSecOps). Those ideas don't belong to any one vendor — this AWS and GCP series already covered the same ground for two of the other three major public clouds. Azure earns its own series for a reason beyond completeness: Microsoft built Azure around a different lineage than either of the other two — it grew out of Microsoft's own enterprise identity stack (Active Directory), its enterprise licensing relationships, and a datacenter fabric organized around the Windows Server/Hyper-V virtualization model long before "cloud" was the product. That lineage still shows up constantly in the actual architecture: Azure's identity model is a first-class product on its own (Microsoft Entra ID) rather than a per-account IAM store, its VM host isolation model borrows directly from Hyper-V's own security boundaries, and a meaningful fraction of enterprise Azure adoption starts from an existing on-premises Active Directory or System Center estate that has to hybrid-connect rather than fully migrate on day one.

This series follows the same discipline the AWS and GCP series already established: every Azure-specific mechanism gets pointed back to the general principle it's a concrete implementation of, and every place Azure's design genuinely diverges from AWS's or GCP's equivalent gets an explicit, worked comparison rather than a hand-wave. A reader who has been through the AWS or GCP series already understands availability zones, IAM, and infrastructure-as-code as ideas — this series' job is showing precisely how Azure implements them, where the vocabulary maps directly, and where it doesn't.

Diagram

One emoji-free note worth stating up front, since it recurs throughout this series: Azure's own official certification tracks (AZ-104 Administrator, AZ-305 Solutions Architect, AZ-700 Network Engineer, AZ-500 Security Engineer) are unusually well-organized bodies of knowledge for exactly this kind of comprehensive coverage, and this series' chapter boundaries deliberately follow their domain structure — not to prepare a reader for a specific exam, but because Microsoft's own skills-measured outlines are the clearest existing map of what a working Azure practitioner is actually expected to know end to end.


Azure's Geography — Regions, Availability Zones & Region Pairs#

Strip away the branding and Azure geography reduces to the same three-tier idea every hyperscaler uses, with Azure-specific names and one genuinely distinct extra layer.

Diagram
ConceptWhat it isAWS/GCP equivalent
GeographyA discrete market area (e.g., United States, Germany) containing one or more regions, often tied to specific data-residency and legal boundariesNo direct AWS equivalent; loosely maps to GCP's multi-region groupings
RegionA set of datacenters deployed within a latency-defined perimeter, identified by a name like eastus or westeuropeAWS Region / GCP Region
Availability Zone (AZ)One or more physically separate datacenters within a region, each with independent power, cooling, and networkingAWS AZ / GCP Zone
Region PairTwo specific regions within the same geography, explicitly paired by Microsoft for sequential update rollout and prioritized recoveryNo direct equivalent — AWS and GCP leave region-pairing entirely to the customer

Region pairs are the one piece of this geography model genuinely worth calling out as distinct, worth stating precisely: Microsoft only rolls out planned platform updates to one region in a pair at a time, and during a broad regional outage, a paired region gets recovery priority over an arbitrary, unpaired region. This doesn't replace deliberate multi-region architecture (Part 16 covers that in depth) — it's a platform-level default that happens to favor the paired region, not a guarantee any single workload automatically gets. Not every Azure region has an announced pair, and not every region has three Availability Zones yet — checking Azure's regions page before designing a zone-redundant architecture around a specific region is a real, necessary step, not paranoia.

# List every Azure region and whether it currently supports Availability Zones
az account list-locations --output table

# Check whether a SPECIFIC region supports zones for a given resource type
az vm list-skus --location eastus --zone --output table

Choosing a Region — Real Constraints#

The same three practical constraints that governed region choice in the AWS and GCP series apply here, largely unchanged in substance:

  1. Latency — physical distance still sets a hard floor via the speed of light; a driver-portal user in Mumbai hitting a backend in eastus pays for that distance on every request, which is exactly why Meridian Freight's design in Part 6 puts Azure Front Door in front of its public endpoints rather than serving directly from one region.
  2. Compliance and data residency — GDPR and sector-specific regulations (freight and logistics commonly touch customs and cross-border trade data with their own residency rules) can force a region choice regardless of where users physically sit.
  3. Service availability and pricing — Azure does not launch every service in every region simultaneously, and prices genuinely differ by region; a region decision sometimes has to bend around "which region actually has the service this design needs."

From the Trenches: A team designing Meridian Freight's docs-processor pipeline picked a region purely by proximity to headquarters, only to discover during implementation that the specific Cognitive Services tier they needed for document extraction wasn't yet available there. The fix — relocating just that one component to a nearby region and accepting a small added cross-region latency — was cheap to make during design and would have been a genuinely painful mid-migration change discovered during a later deployment instead.


Sovereign Clouds and Data Residency Boundaries#

Beyond ordinary region and geography choices, Azure operates entirely separate sovereign cloud instances — physically and logically isolated from the commercial (public) Azure cloud most of this series describes — worth knowing exist even for engineers who never work in one directly, since a design built assuming standard public Azure can be entirely wrong for an organization required to use one of these instead.

Diagram
DeploymentWhat makes it differentWho it's for
Azure Public (commercial)The standard global Azure fabric this entire series describesEveryone else
Azure GovernmentPhysically and logically isolated US datacenter regions, screened personnel, additional compliance certifications (FedRAMP High, DoD IL5)US federal, state, and local government agencies and their contractors
Azure operated by 21VianetA physically separate deployment inside China, operated under license by a local partner rather than directly by MicrosoftOrganizations required to operate inside mainland China
EU Data BoundaryNot a separate cloud at all — a data-residency commitment layered onto specific commercial Azure regions, keeping in-scope customer data within EU datacentersEU-based organizations with strict data-residency requirements, without needing an isolated sovereign deployment

Why this distinction matters for architecture, not just legal compliance, worth stating explicitly: a subscription in Azure Government cannot peer a VNet, share a Private DNS zone, or federate identity directly with a subscription in commercial Azure — the isolation is real and total, not a configuration toggle. An organization like Meridian Freight, operating purely commercially with no government contracts, will never touch Azure Government directly, but a reader moving into public-sector consulting work should recognize immediately that "just spin up a subscription" doesn't apply the same way once government or China-specific requirements are in scope — the correct starting question becomes "which Azure cloud, not just which region."


The Tenant, Management Groups, Subscriptions & Resource Groups Hierarchy#

This is the single most foundational structural difference from AWS and GCP worth understanding immediately, because nearly every governance decision in this series builds on it.

Diagram

The Tenant — Identity's Root#

A Microsoft Entra tenant is the outermost boundary in Azure — a dedicated, single instance of Entra ID representing one organization's identities. This is a genuinely important structural difference from AWS and GCP worth stating precisely: AWS and GCP treat identity (IAM) as a feature scoped inside an account or project; Azure treats identity as the root the entire hierarchy hangs from. Every Azure subscription is associated with exactly one Entra tenant at a time (though a tenant can be associated with many subscriptions, and a subscription's tenant association can be changed). Part 2 covers Entra ID's own internal structure — users, groups, app registrations, Conditional Access — in full depth; this chapter only needs the fact that the tenant sits above everything else.

Management Groups — Grouping Subscriptions#

Management groups are Azure's direct analog to AWS Organizational Units and GCP Folders: a way to apply governance (Azure Policy, RBAC) to a whole group of subscriptions at once, arranged in a tree up to six levels deep beneath the single root management group every tenant gets automatically.

# Create a management group under the tenant root
az account management-group create --name "landing-zones" --display-name "Landing Zones"

# Create a child management group nested under it
az account management-group create --name "production" --display-name "Production" \
  --parent "landing-zones"

# Move a subscription into a management group
az account management-group subscription add \
  --name "production" --subscription "<subscription-id>"

Why keeping this hierarchy shallow is worth stating as a hard recommendation, not a style preference: Microsoft's own Cloud Adoption Framework guidance caps a sane management group hierarchy at roughly three to four levels — every additional level adds real inheritance-reasoning overhead every time someone has to answer "which policies and role assignments actually apply to this one subscription," without a corresponding governance benefit past that depth.

Subscriptions — The Real Isolation & Billing Boundary#

A subscription is Azure's equivalent of an AWS account or GCP project — the actual boundary for billing, resource quotas, and (by default) network isolation. This is worth stating as precisely as the AWS series stated its account boundary: a subscription, not a resource group, is Azure's real isolation boundary. Two resources in different subscriptions cannot interact by default without deliberate cross-subscription configuration (VNet peering, a shared Private Link connection, an explicit RBAC grant) — exactly the "bulkhead" resilience pattern from the Reliability & Architecture Patterns series, now expressed in Azure's specific vocabulary.

# List every subscription the currently signed-in identity can see
az account list --output table

# Set the active subscription for all subsequent CLI commands
az account set --subscription "meridian-prod-app"

# Confirm which subscription (and tenant) is currently active —
# the Azure equivalent of AWS's `sts get-caller-identity`
az account show --output table

Resource Groups — Lifecycle, Not Isolation#

A resource group is a logical container for resources that share a lifecycle — typically deployed, updated, and deleted together — but it is explicitly not a security or isolation boundary the way a subscription is. RBAC and Azure Policy can be scoped to a resource group, which makes it a genuinely useful unit for day-to-day access management, but two resources in the same subscription communicate freely across resource-group boundaries by default (network rules, not resource-group membership, are what actually restrict that traffic).

LayerReal purposeGovernsMeridian Freight example
TenantIdentity rootWho exists as a user/app in the organizationmeridianfreight.onmicrosoft.com
Management groupPolicy/RBAC inheritance at scaleWhich policies and roles apply to a set of subscriptionsProduction management group
SubscriptionBilling, quotas, real isolationWhat counts as one billable, isolated environmentmeridian-prod-app
Resource groupLifecycle groupingWhat gets deployed/deleted togetherrg-shipment-api-prod

From the Trenches: A newly onboarded engineer, used to AWS's single-account-per-environment mental model, assumed Meridian Freight's staging and production resource groups (both inside the same subscription, an early-stage shortcut the team later corrected) were as isolated from each other as separate AWS accounts would have been. A broad az deployment group delete intended to tear down a staging resource group ran against the wrong resource-group name — one character off — and both groups were in the same subscription with a shared IAM role that had contributor access to the whole subscription, not scoped per resource group. The blast radius was exactly as large as the subscription, not the resource group. The fix wasn't a smarter script; it was moving staging into its own subscription so a mistake like this would hit a genuine isolation boundary instead of a merely organizational one.


Designing a Subscription Structure That Scales#

Why a Single Subscription for Everything Is a Trap#

The same lesson the AWS and GCP series both taught, worth restating with Azure's specific failure signatures.

Diagram

A Realistic Landing Zone (Azure Landing Zone Pattern)#

Microsoft's own prescriptive answer to this problem is documented as the Azure Landing Zone (ALZ) pattern under the Cloud Adoption Framework — conceptually the same idea as an AWS or GCP landing zone, with Azure's specific management-group vocabulary.

Diagram

Why separating a dedicated Connectivity subscription from workload subscriptions matters concretely, worth stating explicitly and previewing Part 4/5: a hub-and-spoke network topology puts shared networking infrastructure — the hub VNet, the ExpressRoute gateway, Azure Firewall — in one centrally managed subscription, while each workload's own VNet lives in its own spoke subscription and peers into the hub. This mirrors the AWS series' shared-networking account pattern almost exactly, just under Azure's own naming. The Platform management group's subscriptions are typically owned and operated by a central platform team, while Landing Zones subscriptions are where individual application teams (like the one running Meridian Freight's shipment-api) actually deploy workloads, inheriting the platform team's governance and connectivity without having to rebuild it themselves.

Subscription categoryTypical contentsWho usually owns it
IdentityDomain controllers, Entra Connect sync servers (hybrid scenarios)Central IT/security team
ManagementCentralized Log Analytics workspace, Azure Monitor, Automation accountsPlatform/SRE team
ConnectivityHub VNet, ExpressRoute/VPN gateways, Azure FirewallNetwork/platform team
Landing zone (per environment)Application workloads, their own spoke VNetsIndividual application teams
SandboxPersonal/experimental resources, aggressively cost-cappedIndividual engineers

Subscription Design Models — A Real, Recurring Debate#

Beyond "not one shared subscription for everything," teams genuinely disagree on the next level of granularity, and the right answer depends on organizational shape more than technical constraints.

Diagram
ModelIsolation granularityOperational overheadFits best when
Per environmentCoarse (prod vs. non-prod)LowSmall-to-mid teams, a handful of workloads sharing a platform
Per business unitMediumMediumMultiple product lines with genuinely separate budgets and compliance needs
Per workload/microserviceFineHigh — every subscription needs its own network, policy, and monitoring wiringLarge enterprises with dedicated platform teams and mature automation

Meridian Freight, as a mid-size company with one product, lands squarely in the "per environment" model shown in this chapter's landing zone diagram — the same right-sized reasoning the AWS series applied to its own 50-person-startup worked example. A much larger organization with genuinely independent business units (say, a freight brokerage division and a warehousing division with separate P&Ls and separate compliance obligations) would reasonably justify per-business-unit subscriptions instead, accepting the added overhead in exchange for cleaner cost and compliance separation between the two.


Subscription Quotas and Limits — Planning Around Azure's Own Ceilings#

Every Azure subscription starts with default limits — quotas — on nearly everything: vCPU cores per region per VM family, public IP addresses, VNets per region, storage accounts per region. Hitting one unexpectedly mid-incident or mid-launch is a genuinely common, avoidable failure mode, and it's worth covering here in Fundamentals rather than waiting until Part 3's compute deep dive, since it applies just as much to networking and storage quotas as it does to VMs.

# Check current usage against quota for a specific VM family in a region
az vm list-usage --location eastus --output table

# Request a quota increase proactively, before a launch or scale-out —
# not reactively, during one
az quota create \
  --resource-name "standardDDS_Family" \
  --scope "/subscriptions/<sub-id>/providers/Microsoft.Compute/locations/eastus" \
  --limit-object value=64 limit-object-type=LimitValue

Why a new subscription's default quota being deliberately small is worth understanding, not just working around: a fresh subscription in a region like East US commonly starts with only 10–20 vCPUs of quota for a general-purpose VM family, and specialized hardware (GPU VM families in particular) frequently starts at a default quota of ZERO until explicitly requested and approved. This is a deliberate anti-abuse control, not an oversight — but it means a team's very first attempt at deploying a GPU-backed workload, or scaling a VM Scale Set (Part 3) past a modest size, can fail with a quota error that has nothing to do with the deployment's own configuration.

Quota typeWhat it limitsTypical defaultIncrease turnaround
Regional vCPU quotaTotal vCPUs of a VM family in one regionOften 10–20 cores for common familiesMinutes to a few hours for modest increases
Specialized hardware (GPU) quotaGPU-backed VM familiesFrequently zero until requested1–5 business days, sometimes longer
Network resource quotasVNets, public IPs, NSGs per regionTens to low hundreds, varies by resource typeMinutes to hours
Storage account quotaStorage accounts per region per subscription250 by defaultSupport-ticket based

From the Trenches: A team preparing Meridian Freight's docs-processor pipeline for a GPU-accelerated document-classification model requested the VM only two days before a planned production cutover, assuming provisioning would be immediate the way ordinary VM creation is. The deployment failed with a quota error — the subscription's GPU VM family quota was still at its default of zero, since nothing in that subscription had ever requested GPU compute before. The quota increase request itself took just under two business days to approve, which very nearly missed the cutover date entirely. The corrective habit adopted afterward: check and pre-request quota for any new VM family or resource type a design introduces as a standard step of capacity planning, the same discipline the AWS series' Service Quotas section recommended for exactly this failure mode.


Governance: Azure Policy and Azure RBAC#

Two genuinely distinct governance mechanisms exist in Azure, and confusing them is one of the most common early mistakes engineers coming from AWS or GCP make.

Azure RBAC — Who Can Act#

Azure role-based access control (RBAC) answers "who can perform which actions on which resources." A role definition is a named set of permitted (and explicitly denied) actions; a role assignment binds a security principal (a user, group, or service principal) to a role definition at a specific scope (management group, subscription, resource group, or individual resource).

# Assign the built-in "Contributor" role to a group, scoped to
# ONE resource group only — not the whole subscription
az role assignment create \
  --assignee "<group-object-id>" \
  --role "Contributor" \
  --scope "/subscriptions/<sub-id>/resourceGroups/rg-shipment-api-prod"

# List every role assignment currently effective on a resource group —
# a genuinely important habit before trusting an access boundary
az role assignment list --resource-group rg-shipment-api-prod --output table

Azure Policy — What's Allowed to Exist#

Azure Policy answers a completely different question: "what configuration is a resource allowed to have, regardless of who's creating it." A user with full Contributor RBAC rights can still be blocked by a Policy assignment that denies, for example, creating a Storage Account without encryption enabled.

Diagram

Why this ordering matters, worth stating precisely as the single cleanest interview answer for this topic: RBAC and Policy are evaluated independently, and either one can block a request on its own — a request needs BOTH a valid RBAC grant AND policy compliance to succeed. This is the direct Azure analog of the AWS series' "SCPs are guardrails, not grants" distinction, just inverted in emphasis: an AWS SCP sets a ceiling that IAM policies grant permissions up to; Azure Policy instead evaluates the actual resource configuration being requested, independent of who's requesting it or what they're otherwise allowed to do.

# Create a Policy assignment (built-in definition) at the
# management-group level — inherits down to every subscription beneath it
az policy assignment create \
  --name "require-storage-encryption" \
  --display-name "Require storage account encryption" \
  --policy "404c3081-a854-4457-ae30-26a93ef643f9" \
  --scope "/providers/Microsoft.Management/managementGroups/production"

Policy Initiatives and Inheritance#

Assigning fifty individual policy definitions to ten management groups one at a time doesn't scale — an initiative (Azure's term for a policy set) bundles many policy definitions into one named group, assigned as a single unit.

Policy effectWhat it does
DenyBlocks the non-compliant request outright — closest to an AWS SCP Deny
AuditAllows the request but flags it as non-compliant in Azure Policy's compliance dashboard
DeployIfNotExistsAllows the request, then automatically deploys a remediation resource (e.g., attaching a diagnostic setting)
ModifyActively alters the resource's properties during creation to bring it into compliance (e.g., force-adding a required tag)

Why DeployIfNotExists and Modify are worth calling out as genuinely more powerful than anything in AWS's SCP model, worth stating explicitly: neither AWS SCPs nor GCP Organization Policies can actively reach in and remediate or alter a resource — they can only allow or block. Azure Policy's remediation effects turn governance from a purely preventive control into something that can proactively fix drift, directly extending the "continuous compliance" idea from the DevSecOps series into something with real teeth.

Resource Locks — A Blunter, Different Tool#

A resource lock is a third, simpler mechanism, unrelated to both RBAC and Policy: it prevents a resource, resource group, or subscription from being deleted (CanNotDelete) or modified at all (ReadOnly), regardless of what RBAC or Policy would otherwise allow.

# Prevent accidental deletion of the production networking resource group —
# even a subscription Owner cannot delete it without first removing the lock
az lock create \
  --name "prevent-delete" \
  --resource-group rg-networking-prod \
  --lock-type CanNotDelete
MechanismQuestion it answersCan it be bypassed by a higher RBAC role?
Azure RBACWho can perform this action?N/A — this IS the permission check
Azure PolicyIs this resource's configuration allowed?No — Policy evaluates independently of RBAC
Resource LockCan this specific resource be deleted or changed at all?No — even a subscription Owner must remove the lock first

The Azure Well-Architected Framework#

Azure's own distilled best-practices framework, structurally identical in purpose to AWS's Well-Architected Framework and GCP's Architecture Framework, worth knowing by name and by pillar since Azure documentation and Azure-focused interviews reference it constantly.

Diagram

A genuinely useful framing already established in the AWS series, worth restating here: every one of these five pillars is a vendor-branded restatement of a principle already covered in depth elsewhere in this course — Reliability is the Reliability & Architecture Patterns and Disaster Recovery series; Security is the DevSecOps series; Cost Optimization and Performance Efficiency are the Capacity Planning series; Operational Excellence is SRE Fundamentals and Incident Management. Recognizing this instantly, out loud, in an interview is exactly as strong a move here as it was for the AWS series' equivalent framework.


The Shared Responsibility Model on Azure#

Directly the same concept already introduced generically in the DevSecOps series and revisited concretely in both the AWS and GCP series — Azure's version follows the identical shape.

Diagram

The exact same nuance the AWS series flagged applies identically here: the dividing line moves depending on the service tier. For an Infrastructure-as-a-Service VM (Part 3), the customer patches the guest OS; for a fully managed Platform-as-a-Service offering like Azure Functions (Part 10) or Azure SQL Database (Part 9), Microsoft manages the OS entirely, and the customer's responsibility narrows to data, access configuration, and application-level settings. "My data, my access control" never moves off the customer's side of the line regardless of how managed the service is — the strongest, most reusable answer to this question across all three cloud providers.


Azure Resource Manager — The Control Plane Underneath Everything#

Every single example so far in this chapter — az group create, az role assignment create, az policy assignment create — ultimately resolves to a request against one control plane: Azure Resource Manager (ARM). Understanding what ARM actually does is what makes the rest of this series' Infrastructure as Code content (Part 15) make sense, rather than feeling like memorized syntax.

Diagram

ARM does three things worth naming explicitly: it provides one consistent API surface every client (Portal, CLI, PowerShell, SDKs, Bicep/ARM templates) calls into, regardless of which one a human happens to be using; it enforces RBAC and Policy on every single request, no matter which client issued it; and it keeps a deployment history per resource group, letting a later az deployment group list answer "what was actually deployed here, and when" — genuinely useful during an incident, the same way the AWS series flagged AWS Config's configuration history as an incident-response tool.

Resource Providers — Namespaces for Azure's Own Services#

Every Azure service is implemented behind a resource provider namespace (Microsoft.Compute, Microsoft.Storage, Microsoft.Network, and hundreds more), and a subscription must have the relevant provider registered before it can create resources of that type — a common, easy-to-miss gotcha in a freshly created subscription.

# List registration state for every resource provider in the current subscription
az provider list --query "[?registrationState=='NotRegistered'].namespace" -o tsv

# Register a provider explicitly before deploying its resource types
az provider register --namespace Microsoft.ContainerService

From the Trenches: A team provisioning Meridian Freight's first AKS cluster (Part 10) in a brand-new subscription hit a deployment failure referencing Microsoft.ContainerService with no immediately obvious cause in the error message's first line. The actual root cause, two levels deep: the subscription had never had any container-related resource created in it before, so the Microsoft.ContainerService resource provider was still in NotRegistered state — a state every new subscription starts in for providers it has never used, not a permissions or quota problem at all. Registering the provider explicitly (a one-time, idempotent operation) resolved it in under a minute once correctly diagnosed, after nearly an hour spent investigating RBAC and quota causes first.

Idempotent Deployments and what-if#

A defining property of ARM (and by extension Bicep, Part 15) worth stating precisely: deployments are idempotent — re-running the exact same template against the same resource group converges it to the same declared state rather than failing or duplicating resources, the same declarative idea already covered generically for Terraform in the Automation & IaC series.

# Preview exactly what a deployment WOULD change, without applying it —
# genuinely worth running before every production deployment
az deployment group what-if \
  --resource-group rg-shipment-api-prod \
  --template-file main.bicep --parameters main.bicepparam

ARM JSON Templates vs. Bicep — Same Engine, Different Syntax#

Worth stating clearly before Part 15 goes deep on either: ARM JSON templates and Bicep are not two different deployment engines — Bicep compiles down to the exact same ARM JSON that a hand-written template produces, submitted to the exact same ARM deployment API. The difference is entirely in authoring ergonomics.

{
  "type": "Microsoft.Storage/storageAccounts",
  "apiVersion": "2023-01-01",
  "name": "[concat('meridianfreight', uniqueString(resourceGroup().id))]",
  "location": "[resourceGroup().location]",
  "sku": { "name": "Standard_LRS" },
  "kind": "StorageV2"
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: 'meridianfreight${uniqueString(resourceGroup().id)}'
  location: resourceGroup().location
  sku: { name: 'Standard_LRS' }
  kind: 'StorageV2'
}
# Bicep can always be decompiled back to ARM JSON, and vice versa —
# useful when inheriting an older, hand-written ARM template
az bicep decompile --file azuredeploy.json

The Bicep version expresses the identical resource with dramatically less syntactic noise — no bracketed template-function strings, no top-level resources array boilerplate. Microsoft's own current guidance, reflected in the AZ-104 skills outline this chapter is grounded in, treats Bicep as the default authoring format for new work, with ARM JSON template literacy still required for reading and modifying an organization's existing, older templates.


Tools of the Trade: Portal, CLI, PowerShell & Cloud Shell#

Azure offers a genuinely wider set of first-class interfaces than AWS or GCP typically emphasize, and knowing which one fits which job is a practical, everyday skill.

# Azure CLI — cross-platform, the interface used throughout this series
az login
az account show

# Every az command follows: az <service> <action> [options]
az vm list --output table
az storage account list --output table
# Azure PowerShell — the historically native interface, still
# preferred in many Windows-centric enterprise environments
Connect-AzAccount
Get-AzVM
InterfaceBest fitRuns where
Azure PortalExploration, learning, one-off visual configurationBrowser only
Azure CLI (az)Scripting, CI/CD pipelines, cross-platform automationAny OS, or Cloud Shell
Azure PowerShell (Az module)Windows-centric automation, deep integration with on-prem PowerShell toolingAny OS with PowerShell 7+, or Cloud Shell
Azure Cloud ShellZero-install browser-based shell with az, PowerShell, and common tools preinstalledBrowser, backed by a small persistent file share
ARM templates / Bicep (Part 15)Declarative, repeatable infrastructure deploymentDeployed via CLI, PowerShell, or the portal

Why "the Portal, CLI, PowerShell, and Bicep are all just different clients calling the same underlying Azure Resource Manager API" is worth stating explicitly, the same clarifying line the AWS series made for its own API: nothing achievable in the Portal is fundamentally unavailable to the CLI, PowerShell, or Bicep — they all resolve to the same ARM control-plane calls, which is precisely why Infrastructure as Code works at all against Azure.


Tagging and Resource Discovery at Scale#

The same unglamorous, easy-to-skip discipline the AWS and GCP series both emphasized, with Azure's own enforcement mechanism.

# Tag a resource group at creation
az group create --name rg-shipment-api-prod --location eastus \
  --tags Environment=production Team=logistics-platform CostCenter=CC-2041

# Apply the SAME tags to every resource inside it, retroactively
az resource list --resource-group rg-shipment-api-prod --query "[].id" -o tsv | \
  xargs -I {} az resource tag --tags Environment=production Team=logistics-platform --ids {}
TagWhy it matters
EnvironmentLets Policy, cost reports, and automation distinguish blast-radius-sensitive resources
Team / OwnerAnswers "who do I page about this?" during an incident, directly connecting to the Incident Management series
CostCenterMakes the cost-allocation views in Part 16 usable — untagged resources show up as an unattributed lump sum
ManagedBy (e.g., bicep)Warns a human against manually editing a resource Infrastructure as Code owns

An Azure Policy Modify effect (introduced earlier in this chapter) is the practical, enforced version of this — rather than trusting every engineer to remember tags, a policy assignment can force-inject the required tag set onto any resource missing it at creation time, closing the gap a wiki-page convention alone always eventually develops.


Azure Resource Graph — Querying Your Entire Estate at Scale#

Tagging solves attribution, but a genuinely common operational question — "show me every VM across all forty subscriptions running an unsupported OS image" — needs something faster than iterating subscriptions one at a time with az vm list. Azure Resource Graph indexes resource metadata across every subscription a caller can see and exposes it through Kusto Query Language (KQL), the same query language used by Log Analytics (Part 13).

# Query every publicly-exposed Storage Account across ALL accessible
# subscriptions in a single call — impossible to do this fast with
# per-subscription resource listing alone
az graph query -q "
Resources
| where type =~ 'microsoft.storage/storageaccounts'
| where properties.publicNetworkAccess != 'Disabled'
| project name, resourceGroup, subscriptionId, location
"

Why this matters concretely for governance at real scale, worth stating explicitly: Resource Graph is what makes an organization-wide compliance question answerable in seconds instead of a multi-hour scripted crawl across every subscription individually — directly complementing Azure Policy's compliance dashboard (which answers "is this compliant" for policy-covered properties) with an open-ended query surface for anything captured in resource metadata, tags included.


Billing Accounts: Enterprise Agreements vs. Microsoft Customer Agreements#

Everything this chapter has covered — subscriptions, management groups, tags — sits below a layer this series hasn't touched yet: how a subscription actually gets billed in the first place. Two distinct commercial agreement types exist, and which one an organization is on changes real, practical details about how billing is structured.

Diagram
Enterprise Agreement (EA)Microsoft Customer Agreement (MCA)
Typical audienceLarge organizations, 500+ users/devices, negotiated multi-year contractAny size, increasingly the default path for new enrollments
Contract termFixed, typically 3 years, renewed/renegotiatedNo fixed expiration — a modern, digital agreement
Pricing currencyLocal currencyUS Dollars worldwide
Cost-center granularityCoarser — department-level tracking bolted on less nativelyInvoice sections give genuine per-cost-center billing granularity without internal rebilling

Why this is worth knowing even for engineers who never touch procurement, worth stating explicitly: an organization migrating from EA to MCA (a real, common transition Microsoft has been actively driving) changes ONLY the billing relationship — it is explicitly not an Azure resource, access, or permissions change — existing subscriptions, RBAC assignments, and resources are entirely unaffected by which billing model sits above them. Meridian Freight's own platform team doesn't need to reason about this daily, but knowing it exists is what prevents a confused "why does our cost report look different this quarter" investigation from wasting time looking for a resource-level cause when the actual change happened one layer up, in billing.


Understanding the Bill — Pricing Models, Reservations & Hybrid Benefit#

A practical, foundational topic worth covering before any specific service, since every later part references pricing.

Pricing modelHow it worksBest fit
Pay-As-You-GoBilled per second/hour/GB of actual usage, no commitmentUnpredictable or short-lived workloads, getting started
Reserved Instances / Savings PlansCommit to 1 or 3 years of compute usage for a significant discountStable, predictable, long-running baseline workloads
Spot VMsBid on Azure's spare capacity at up to ~90% off, subject to eviction with short noticeFault-tolerant, interruptible batch or autoscaled workloads
Azure Hybrid BenefitApply an existing on-premises Windows Server or SQL Server license (with Software Assurance) toward Azure compute, cutting the licensing portion of the costEnterprises migrating existing licensed Windows/SQL workloads

Why Azure Hybrid Benefit is worth calling out as genuinely distinct from anything AWS or GCP offers directly, worth stating explicitly: it's a real, substantial cost lever unique to organizations with an existing Microsoft Enterprise Agreement, and skipping it when migrating an existing licensed estate leaves real, immediately available savings on the table. A full, dedicated treatment of cost strategy — reservation math, Spot design, rightsizing — is covered later in this series (Part 16), once the underlying services are already understood.


Cost Management, Budgets & Azure Advisor#

Azure bundles cost visibility and best-practice recommendations as first-class, built-in tooling rather than a bolt-on service.

# Create a monthly budget with an alert at 80% of the threshold
az consumption budget create \
  --budget-name "meridian-prod-monthly" \
  --amount 5000 --time-grain Monthly \
  --category Cost \
  --start-date 2026-09-01 --end-date 2027-08-31

# Get current cost-optimization recommendations from Azure Advisor
az advisor recommendation list --category Cost --output table

Azure Advisor evaluates a subscription against Microsoft's best-practice checklist across five categories — cost, security, reliability, operational excellence, and performance — genuinely comparable to AWS Trusted Advisor's role in that series, and worth running as a standard first pass on any new subscription.


Azure Arc — Extending Governance to Hybrid and Multi-Cloud Resources#

Everything covered so far in this chapter — Policy, RBAC, tagging, Resource Graph — assumes the resource in question actually lives in Azure. Azure Arc extends that same governance surface to servers, Kubernetes clusters, and databases running outside Azure entirely: on-premises, in another cloud, or at the edge — a real, increasingly emphasized part of Azure's own governance story as of the 2026 AZ-104 skills update.

Diagram

An Arc-enabled server or cluster is installed with a lightweight agent that registers it as a projected resource inside a chosen resource group — from that point forward, it shows up in az resource list, can be targeted by an Azure Policy assignment (for example, enforcing a specific patch baseline), and appears in Resource Graph queries alongside genuinely Azure-native resources, without the underlying workload ever moving off its original infrastructure.

Why this is worth stating as a real governance capability rather than a marketing checkbox, worth stating explicitly: an organization mid-migration — exactly Meridian Freight's own situation, with some legacy on-premises freight-routing servers not yet moved — gets ONE consistent governance and monitoring plane across both its Azure and non-Azure estate, rather than maintaining separate tooling for "resources in Azure" versus "everything else" during what can be a multi-year migration window.


A Full Worked Landing Zone Bootstrap, Start to Finish#

Bringing every concept in this chapter together into one concrete, ordered bootstrap sequence for Meridian Freight's own Azure footprint.

# 1. Create the core management group structure
az account management-group create --name "platform" --display-name "Platform"
az account management-group create --name "landing-zones" --display-name "Landing Zones"
az account management-group create --name "production" --display-name "Production" --parent "landing-zones"
az account management-group create --name "non-production" --display-name "Non-Production" --parent "landing-zones"

# 2. Create the platform subscriptions (identity, management, connectivity)
#    — typically pre-provisioned by the enterprise agreement/billing account

# 3. Attach a policy initiative enforcing the required tag set, org-wide
az policy assignment create --name "require-tags" \
  --policy-set-definition "<initiative-id>" \
  --scope "/providers/Microsoft.Management/managementGroups/landing-zones"

# 4. Create the workload subscription and move it under Production
az account management-group subscription add \
  --name "production" --subscription "meridian-prod-app"

# 5. Create the first resource group, tagged from creation
az group create --name rg-shipment-api-prod --location eastus \
  --tags Environment=production Team=logistics-platform CostCenter=CC-2041

# 6. Set a resource lock on anything that must never be accidentally deleted
az lock create --name "prevent-delete" --resource-group rg-shipment-api-prod --lock-type CanNotDelete

# 7. Set a monthly budget with an alert threshold
az consumption budget create --budget-name "meridian-prod-monthly" --amount 5000 --time-grain Monthly

Why doing these steps roughly in this order matters, echoing the AWS series' identical point: governance (management groups, policy) and cost guardrails should exist BEFORE workload subscriptions are populated with real resources — retrofitting governance after hundreds of untagged, unlocked resources already exist is dramatically more painful than building it in from the very first subscription.


Part 1 CLI Cheat Sheet#

AreaCommandPurpose
Identityaz account showConfirm which tenant/subscription is currently active
Subscriptionsaz account list / az account setList and switch active subscription
Management groupsaz account management-group createCreate a management group
Management groupsaz account management-group subscription addMove a subscription into a management group
RBACaz role assignment createGrant a role at a specific scope
RBACaz role assignment listList effective role assignments
Policyaz policy assignment createAssign a policy or initiative
Locksaz lock createPrevent deletion or modification of a resource
Taggingaz resource tagApply tags to an existing resource
Costaz consumption budget createCreate a budget with alert thresholds
Costaz advisor recommendation listGet best-practice recommendations
Regionsaz account list-locationsList available regions
Resource providersaz provider registerRegister a resource provider before deploying its resource types
ARM deploymentsaz deployment group what-ifPreview a deployment's effect before applying it
ARM deploymentsaz deployment group listView deployment history for a resource group
Resource Graphaz graph query -q "..."Run a KQL query across every accessible subscription at once
Quotasaz vm list-usageCheck current usage against quota for a region/VM family
Quotasaz quota createRequest a quota increase proactively

Common Mistakes and Interview Traps#

MistakeWhy It's WrongFix
Running production and every other environment in one subscriptionSubscriptions, not resource groups, are Azure's real isolation boundary — a shared subscription shares quotas, RBAC blast radius, and cost visibilityAdopt a landing zone with separate subscriptions per environment via Management Groups
Believing a resource group provides the same isolation as a subscriptionResources in the same subscription communicate freely across resource groups by defaultUse subscriptions for security/billing isolation; resource groups only for lifecycle grouping
Assuming full RBAC Contributor access means a resource can always be created as configuredAzure Policy evaluates independently of RBAC and can deny a technically-permitted request outrightCheck both RBAC assignments AND applicable policy definitions/initiatives before assuming an action will succeed
Treating Azure Policy and Azure RBAC as interchangeableRBAC governs who can act; Policy governs what configuration is allowed to exist — confusing them leads to gaps in bothUse RBAC for access control, Policy for configuration compliance — apply both deliberately
Deferring resource locks and budgets until after a costly mistake happensA single unlocked, unbudgeted subscription has no guardrail against accidental deletion or runaway spendBootstrap locks on critical resource groups and a budget with alerts as part of initial landing zone setup
Skipping tagging "for now"Makes cost attribution and blast-radius-aware governance impossible to retrofit cleanly laterEnforce a minimum tag set via a Policy Modify effect from the first resource created
Assuming every Azure region has three Availability ZonesNot every region has zone support, and this changes the actual HA guarantees a design can makeCheck az vm list-skus --zone for the target region before designing around zone redundancy
Deploying a resource type into a brand-new subscription and treating the resulting error as a permissions problemA subscription that has never used a given service starts with that service's resource provider in NotRegistered state — an unrelated failure mode that looks like an access issueCheck az provider list for NotRegistered providers before deep-diving into RBAC or quota causes
Applying an ARM/Bicep deployment directly to production without previewing it firstA template change can unexpectedly delete or recreate resources depending on how the declared state differs from the current stateRun az deployment group what-if before every production deployment, not just when something feels risky
Auditing compliance by scripting a loop over every subscription individuallySlow, easy to miss a subscription, and doesn't scale past a handful of subscriptionsUse Azure Resource Graph for any cross-subscription query — it's built for exactly this
Requesting a GPU or specialized VM family for the first time only days before it's neededSpecialized hardware quota commonly defaults to zero and can take several business days to approveCheck and pre-request quota for any new VM family or resource type as a standard part of capacity planning
Assuming "just spin up a subscription" applies identically in Azure Government or Azure operated by 21VianetSovereign clouds are physically and logically isolated — no VNet peering, DNS sharing, or identity federation across the boundary to commercial AzureConfirm which Azure cloud (not just which region) a design must target before assuming standard commercial-Azure patterns apply

Worked Practice Problems#

Problem 1: Meridian Freight's platform team originally placed the shipment-api production workload and the driver-portal staging workload in the same subscription, in separate resource groups, reasoning that resource groups provided sufficient separation. A contractor with Contributor access scoped (they believed) only to the staging resource group ran a script that also modified several production resources. How did this happen, and what's the correct fix?

Answer: The contractor's RBAC assignment was almost certainly scoped at the subscription level rather than the resource-group level — or, even if correctly scoped to one resource group, a resource group boundary alone never prevented resources in different resource groups within the same subscription from being reachable by a sufficiently broad role assignment or network path. Resource groups are a lifecycle/organizational boundary, not a security boundary; the actual isolation boundary in Azure is the subscription. The fix is migrating staging into a genuinely separate subscription (ideally under a separate Non-Production management group) so a role assignment or mistake confined to that subscription cannot reach production resources at all, regardless of how carefully resource-group-level RBAC was configured.

Problem 2: An engineer with the Owner role on a subscription attempts to create a Storage Account without encryption enabled and the request is denied, even though Owner includes every permission RBAC can grant, including Microsoft.Storage/storageAccounts/write. What's actually blocking this request, and why doesn't the Owner role override it?

Answer: An Azure Policy assignment — likely a built-in or custom definition with a Deny effect requiring storage encryption — is blocking the request independently of RBAC. Azure Policy evaluates resource configuration against compliance rules regardless of the requester's RBAC permissions; Owner grants the permission to attempt the action, but Policy separately evaluates whether the resulting resource configuration is allowed to exist. No RBAC role, including Owner, can override a Policy Deny — a request needs to satisfy both RBAC and Policy to succeed, exactly the two-gate model this chapter's sequence diagram illustrates.

Problem 3: A finance team requests a cost breakdown by team across Meridian Freight's Azure environment and finds that a large fraction of spend appears as unattributed. Investigation reveals no Policy assignment was ever created enforcing the organization's tagging standard, despite a tagging convention documented in an internal wiki for over a year. What's the root cause and the correct governance fix?

Answer: The root cause is that a tagging convention with no enforcement mechanism behind it inevitably erodes as an organization grows and engineers turn over — a wiki page cannot stop an engineer from creating an untagged resource, and nothing in Azure's default behavior requires tags. The fix is an Azure Policy assignment using either an Audit effect (surfacing non-compliant resources for manual cleanup) or, more robustly, a Modify effect that automatically injects the required tag set at resource-creation time, turning tagging from an optional best practice into a structurally enforced requirement — the same shift-left philosophy already covered for security scanning in the DevSecOps series.

Problem 4: A platform team is designing Meridian Freight's landing zone and debates whether to build a deep, seven-level management group hierarchy to precisely mirror the company's org chart (division, department, team, sub-team, project, environment, and workload), or a flatter structure. What's the risk in the deep hierarchy, and what would you recommend?

Answer: A seven-level management group hierarchy makes every governance question — "which policies and role assignments actually apply to this one subscription" — require reasoning through seven layers of inheritance, which becomes genuinely error-prone and slows down both troubleshooting and onboarding new platform engineers, without a corresponding governance benefit; Microsoft's own Cloud Adoption Framework guidance explicitly recommends staying within roughly three to four levels. The stronger recommendation is a flatter hierarchy organized by governance need (Platform, Landing Zones split into Production/Non-Production, Sandbox) rather than mirroring the org chart directly — an org chart changes far more often than a well-designed governance hierarchy should need to.

Problem 5: Meridian Freight migrates a fleet of existing on-premises Windows Server VMs, already licensed under an active Enterprise Agreement with Software Assurance, directly to Azure Pay-As-You-Go VM pricing without adjusting the licensing configuration. Six months later, a cost review finds the compute bill is significantly higher than a comparable competitor's published Azure cost estimate for an equivalent workload. What licensing lever was likely missed, and what would you recommend?

Answer: Azure Hybrid Benefit was very likely not applied. Pay-As-You-Go Windows Server VM pricing bundles the Windows Server license cost into the per-hour rate; Azure Hybrid Benefit lets an organization with existing Software Assurance-covered Windows Server (or SQL Server) licenses apply those licenses toward Azure compute instead, paying only the base infrastructure rate. For an organization migrating an already-licensed on-premises estate, failing to apply Azure Hybrid Benefit means effectively paying for the same Windows Server license twice — once through the existing Enterprise Agreement, and again bundled into the Azure VM rate. The fix is reviewing the migrated fleet's licensing eligibility and converting eligible VMs to Azure Hybrid Benefit pricing, which is a pure cost reduction with no change to the workload itself.

Problem 6: Meridian Freight's security team asks for a list of every resource across all twelve of the company's Azure subscriptions that is missing the mandatory Environment tag, to feed into an upcoming compliance audit due in two days. An engineer starts writing a script that loops over each subscription with az resource list and filters the results locally. What faster approach exists, and what governance gap does the need for this ad-hoc script actually reveal?

Answer: Azure Resource Graph answers this directly in a single query — Resources | where isnull(tags['Environment']) run across all accessible subscriptions at once — rather than requiring a hand-rolled, per-subscription crawl that's slow, easy to get subtly wrong, and has to be rebuilt every time a similar cross-subscription question comes up. The deeper governance gap this reveals, though, is that the question needed to be asked reactively at all: if the required tag set had been enforced from the start via an Azure Policy Modify or Deny effect (as this chapter recommends), every resource would already carry the tag, and the compliance audit would need no ad-hoc query to prepare for — the Resource Graph query is the right immediate fix, but closing the missing Policy assignment is the actual root-cause fix.

Problem 7: Six months into Meridian Freight's Azure migration, an engineer proposes deploying the docs-processor pipeline's document-classification workload into an Azure Government region to "future-proof it in case Meridian ever pursues government freight contracts." What's wrong with this reasoning, and what would you recommend instead?

Answer: Azure Government is a physically and logically isolated deployment restricted to US government agencies and their qualifying contractors — it isn't a stricter or more "future-proof" tier of ordinary commercial Azure that any company can opt into speculatively, and a commercial company without an active government contract generally cannot provision resources there at all. Even setting eligibility aside, moving a workload into Azure Government would sever it from every other Meridian Freight resource in commercial Azure, since the two are isolated with no VNet peering or shared identity federation between them. The correct recommendation is to keep the workload in commercial Azure and revisit the question only if and when Meridian actually pursues a specific government contract that contractually requires it — at which point that specific workload, not the whole company's footprint, would be the one evaluated for a sovereign-cloud move.


Summary and What's Next#

  • Azure is a specific, concrete implementation of concepts already covered generically elsewhere in this course, and of concepts the AWS and GCP series already implemented in their own vendor-specific ways — every mechanism in this series maps back to a principle you already understand, with explicit call-outs wherever Azure's design genuinely diverges.
  • Azure's geography adds region pairs on top of the familiar Region/Availability Zone model — a platform-level default favoring one specific paired region for update sequencing and recovery priority, not a substitute for deliberate multi-region design.
  • The tenant → management group → subscription → resource group hierarchy is Azure's distinct structural signature: identity sits at the root, and the subscription — not the resource group — is the real isolation and billing boundary.
  • Azure RBAC (who can act) and Azure Policy (what's allowed to exist) are two independent gates, both of which must pass for a request to succeed — a critical, frequently-tested distinction, sharper in Azure than the AWS SCP/IAM relationship because Policy can actively remediate (DeployIfNotExists, Modify), not just allow or deny.
  • The Azure Well-Architected Framework's five pillars and the Shared Responsibility Model are Azure's own branded restatements of principles this entire course already covers in depth.
  • Azure Hybrid Benefit is a genuinely distinct cost lever unique to organizations with existing Microsoft licensing, worth checking before accepting Pay-As-You-Go pricing at face value.
  • Sovereign clouds (Azure Government, Azure operated by 21Vianet) are physically isolated from commercial Azure with no cross-boundary networking or identity federation — a design consideration that comes before region choice, not after it, for any workload that might need one.
  • Subscription quotas default conservatively, especially for specialized hardware — proactively checking and requesting quota increases is a standard part of capacity planning, not a reactive fix for a failed deployment.

Continue to Part 2 (02-identity-and-access.md) for a deep dive into Microsoft Entra ID — the identity platform that sits at the root of everything covered in this chapter, and governs every RBAC assignment made against it.