Skip to content

Azure Governance: Subscriptions, Policy and Cost Management

Step 5 of 30

Azure Governance for AZ-104: Subscriptions, Policy and Cost Management

Introduction

Azure governance for AZ-104 brings together subscriptions, Azure Policy, resource locks, tags and cost management. This lesson completes the skills area Manage Azure identities and governance (20–25% of the exam) with the objective manage Azure subscriptions and governance. The study guide lists the tasks: implement and manage Azure Policy, configure resource locks, apply and manage tags on resources, manage resource groups, manage subscriptions, manage costs by using alerts, budgets and Azure Advisor recommendations, and configure management groups.

In the lesson on Azure RBAC roles, scopes and effective access, you learned that Azure RBAC answers the question "who can do what?". Governance answers a different set of questions: "what is allowed to exist?", "what must never be deleted by accident?", "who is paying for it?" and "how do we organize hundreds of subscriptions consistently?". An administrator who masters these tools can give teams freedom inside guardrails instead of approving every deployment by hand.

After this lesson you will be able to design a management group hierarchy, write and assign Azure Policy definitions, protect critical resources with locks, enforce tagging, move resources between groups and subscriptions, and control spending with budgets and Advisor.

Learning objectives

  • Describe the Azure resource hierarchy: management groups, subscriptions, resource groups and resources.
  • Explain what Azure Policy evaluates, the common effects (Audit, Deny, Modify, DeployIfNotExists, Append) and how initiatives and remediation tasks work.
  • Choose between Azure Policy, Azure RBAC and resource locks for a given requirement.
  • Configure CanNotDelete and ReadOnly locks and predict their side effects.
  • Apply tags, enforce them with policy and understand tag inheritance limits.
  • Move resources between resource groups and subscriptions, and know what cannot be moved.
  • Create budgets, cost alerts and act on Azure Advisor cost recommendations.

The resource hierarchy

Azure Resource Manager organizes resources into four scope levels. RBAC and policy assignments flow down the hierarchy, subject to their scope and exclusions. Locks can be applied at subscription, resource-group or resource scope and are inherited below those scopes; management groups do not support resource locks.

Level What it is Typical use
Management group Container for subscriptions (and other management groups), up to six levels deep below the root, excluding the subscription level Apply policy and RBAC to many subscriptions at once
Subscription Billing boundary and a limit/quota boundary; trusts exactly one Microsoft Entra tenant Separate production from development, or one business unit from another
Resource group Logical container for resources that share a lifecycle Group everything for one application so it can be deployed and deleted together
Resource The actual service instance (VM, storage account, virtual network) —

Key facts to remember:

  • Every Entra tenant has a single root management group (its ID is the tenant ID). All subscriptions and management groups roll up to it. A tenant can contain up to 10,000 management groups.
  • A management group or subscription has exactly one parent. A resource belongs to exactly one resource group.
  • A resource group stores metadata, so its location is only where that metadata lives. Resources inside it may be in different regions.
  • A subscription is the unit of billing and of many service limits. Deleting a resource group attempts to delete its resources; locks and resource dependencies can prevent completion.

Management groups

Management groups let you manage access, policy and compliance across subscriptions. A common design follows the company structure or the environment:

Text
Tenant Root Group
├── Contoso-Platform
│   ├── Connectivity subscription
│   └── Management subscription
├── Contoso-LandingZones
│   ├── Production
│   │   └── Sub-Prod-Finance
│   └── NonProduction
│       └── Sub-Dev-Finance
└── Contoso-Sandbox

You create a management group in the portal (Management groups > Create), with the CLI, or with PowerShell:

Bash
az account management-group create --name contoso-landingzones --display-name "Contoso Landing Zones"
az account management-group subscription add --name contoso-landingzones --subscription 11111111-2222-3333-4444-555555555555

By default, new subscriptions are placed in the root management group unless you configure a default management group in the hierarchy settings. Visibility and management depend on Azure RBAC at the relevant scopes. No user has root management-group access by default; a Microsoft Entra Global Administrator can elevate access and then delegate Azure roles. Users already assigned suitable Azure roles can see and manage the corresponding hierarchy. By default, tenant users can create management groups; administrators can restrict this through hierarchy settings. Moving a subscription requires the appropriate permissions on the subscription and affected parent groups.

Managing subscriptions

A subscription is created from a billing account (Enterprise Agreement, Microsoft Customer Agreement, pay-as-you-go, and so on). As an administrator you will mostly:

  • Rename a subscription or change its management group.
  • Transfer billing ownership to another billing account.
  • Change the directory (move the subscription to another Entra tenant). Warning: this removes all RBAC role assignments, because assignments depend on principals of the old tenant. System-assigned managed identities must be reenabled and their permissions restored; user-assigned identities must be recreated and reattached. Check service-specific tenant-transfer restrictions before proceeding.
  • Cancel a subscription. A canceled subscription is disabled, and its resources are deleted only after a retention period (Microsoft documents 30–90 days for data retention after cancellation).
  • Check quotas and request increases, for example for vCPUs per region.

Exam tip: Moving a subscription to another management group does not change its billing or its tenant. Changing the directory does change the tenant and wipes role assignments.

Resource groups

Resource groups hold resources that share the same lifecycle, owner and permissions. Rules to know:

  • A resource group cannot be nested, and it cannot be renamed.
  • Deleting a group targets everything it contains; locks or dependencies can block the operation, so review the contents and permissions first.
  • Creating a group requires a location, used for metadata, as noted above.

Moving resources

You can move many resources between resource groups and between subscriptions (in the same tenant) with Move in the portal, or with:

Bash
resourceId="$(az storage account show --resource-group rg-dev \
  --name stcontosodev01 --query id --output tsv)"
az resource move --destination-group rg-app-prod --ids "$resourceId"

What happens during a move:

  • The resource ID changes (it contains the subscription and group name). Scripts and templates that hard-code the ID break.
  • Both source and target groups are temporarily locked against resource creation, updates and deletion during the move. Existing workloads generally keep running; this management lock does not stop their data-plane traffic.
  • The region of the resource does not change; to change region you redeploy or use a resource mover.
  • The move requires Microsoft.Resources/subscriptions/resourceGroups/moveResources/action on the source group and Microsoft.Resources/subscriptions/resourceGroups/write on the destination, plus read access needed to discover resources and dependencies. Direct resource or child-resource RBAC assignments do not move: inventory them and recreate them at the new scope.
  • Not every resource type supports move. Use the Validate move step, which runs a pre-check and reports problems before you commit.

If a destination subscription is in a different tenant, a move is not possible; you have to redeploy.

Azure Policy

Azure Policy evaluates resources against rules and either reports non-compliance or prevents or fixes it. RBAC controls what a user can do; Policy controls what a resource may look like, whoever creates it. Even an Owner cannot create a non-compliant resource if a Deny policy applies.

The pieces

Concept Meaning
Policy definition The rule: a condition (if) and an effect (then), written in JSON. Built-in or custom
Initiative (policy set) A group of definitions managed and assigned together, for example a regulatory compliance set
Assignment Applies a definition or initiative at a scope (management group, subscription, resource group)
Exclusion A scope under the assignment that is exempt (for example one resource group)
Parameters Make a definition reusable, for example the list of allowed regions
Exemption A time-limited or permanent waiver for a specific resource or scope, with a category (waiver or mitigated)
Remediation task Brings existing non-compliant resources into compliance for DeployIfNotExists and Modify

A custom definition

This illustrative definition denies supported regional resources created outside approved locations. It excludes global resources and uses Indexed, so it does not enforce resource-group locations. Use the separate resource-group location policy when that is required. Microsoft already ships a built-in version named Allowed locations, so you rarely need to write this one, but the structure is the same for every definition:

JSON
{
  "properties": {
    "displayName": "Allowed locations",
    "mode": "Indexed",
    "parameters": {
      "listOfAllowedLocations": {
        "type": "Array",
        "metadata": { "displayName": "Allowed locations", "strongType": "location" }
      }
    },
    "policyRule": {
      "if": {
        "allOf": [
          { "field": "location", "notIn": "[parameters('listOfAllowedLocations')]" },
          { "field": "location", "notEquals": "global" }
        ]
      },
      "then": { "effect": "deny" }
    }
  }
}

The mode is Indexed for resource types that support tags and location, or All for every resource type and resource groups.

Effects

Effect Behavior Notes
Deny Blocks the create or update request Does not touch existing resources; they become non-compliant
Audit Allows the request, logs a warning event and marks it non-compliant Safe first step when rolling out a rule
Append Adds fields (such as a tag or IP rule) during create/update Largely replaced by Modify
Modify Adds, updates or removes properties or tags on create/update, and on existing resources through a remediation task A remediation task needs an assignment managed identity with the required role
DeployIfNotExists After a create/update, deploys a related resource if it does not exist (for example a diagnostic setting) Deployment uses the assignment managed identity; existing resources need a remediation task
AuditIfNotExists Flags resources that lack a related resource No change is made
Disabled Turns the rule off Useful for testing

Evaluation order matters when several effects apply to one request: Disabled first, then Append and Modify, then Deny, then Audit. The practical consequence is that a Modify policy can fix a request before a Deny rule examines it.

Assignment and compliance

When you assign a policy, new and updated resources are evaluated immediately. A full evaluation cycle for existing resources runs about every 24 hours; you can trigger one on demand with az policy state trigger-scan. Results appear in Policy > Compliance. A freshly created assignment can take several minutes before it starts reporting.

Set subscriptionId and definitionId to your subscription and policy definition IDs before running this Bash example.

Bash
az policy assignment create \
  --name allowed-locations \
  --display-name "Allowed locations - EU" \
  --scope "/subscriptions/$subscriptionId" \
  --policy "$definitionId" \
  --params '{"listOfAllowedLocations":{"value":["westeurope","northeurope"]}}'

For DeployIfNotExists and Modify, the assignment needs a managed identity, and that identity must hold the roles the definition lists (for example Contributor or Log Analytics Contributor). The portal can create the identity and the role assignment for you; with the CLI you pass --mi-system-assigned and --location, then separately grant the identity the roles listed in roleDefinitionIds. Creating the identity alone does not grant those permissions.

Worked example: enforcing a cost-center tag

Scenario. Contoso wants every resource group in the subscription to carry a CostCenter tag. Existing groups without it should get the value Unassigned so finance can find them, and new groups created without the tag must be rejected.

Reasoning, step by step.

  1. Assign Require a tag on resource groups at subscription scope with tagName = CostCenter to reject new groups without the tag.
  2. Inventory existing untagged groups before enabling enforcement. Assign Add a tag to resource groups with tagName = CostCenter, tagValue = Unassigned and enforcement mode DoNotEnforce. This evaluates compliance without automatically changing new requests.
  3. Give the Modify assignment a managed identity with the role required by the definition, such as Tag Contributor.
  4. Run an explicit remediation task against the existing non-compliant groups, verify the results, then remove the temporary Modify assignment. Manual remediation is available while enforcement is disabled.
  5. Keep the Deny assignment enforced for future requests. An enforced Modify assignment would run before Deny and fill the missing tag, allowing a request that should have been rejected. The temporary assignment avoids that conflict.

Why the alternatives are worse. An Audit policy would only report. An RBAC role cannot force a tag. A lock does not examine tags at all.

Resource locks

A resource lock protects a subscription, resource group or resource against accidental changes or deletion, regardless of RBAC. There are two lock levels:

Lock Effect
CanNotDelete (Delete in the portal) Authorized users can read and modify, but not delete
ReadOnly Authorized users can read, but cannot modify or delete; does not grant Reader access and does not block data-plane writes

Facts that commonly appear on the exam:

  • Locks are inherited: a lock on a resource group applies to every resource in it, including resources added later.
  • Locks apply to the control plane (management operations through Azure Resource Manager), not to data-plane operations. A ReadOnly lock on a storage account does not stop someone writing blobs with a SAS token, but it does block listing the account keys, because that is a POST management operation.
  • To create or delete a lock you need Microsoft.Authorization/locks/* permissions, held by Owner and User Access Administrator.
  • The most restrictive lock wins when more than one applies.
  • A ReadOnly lock on a VM can stop it from being started because start is a POST management operation; a ReadOnly lock on an App Service plan can block scaling; on a resource group it can block deployments into the group.
  • Even an Owner must remove the lock first to delete a locked resource; deleting a resource group fails if any child has a lock.
Bash
az lock create --name protect-prod --lock-type CanNotDelete \
  --resource-group rg-app-prod --notes "Production workload, change request required"

Policy, RBAC and locks compared

Mechanism Controls Typical question it answers
Azure RBAC Which identities can perform which actions "Can Maria delete this VM?"
Azure Policy What properties resources are allowed to have "Can anyone create a VM outside West Europe?"
Resource lock Whether a resource can be changed or deleted at all "Can this production database be deleted by mistake?"

Tags

Tags are name/value pairs attached to resources, resource groups and subscriptions. They support cost reporting, automation and ownership tracking (Environment=Prod, CostCenter=4521, Owner=team-payments).

  • Up to 50 tag name/value pairs per resource, resource group or subscription. Tag names are case-insensitive; values are case-sensitive. Names have length and character restrictions (for example, no <, >, %, &, \, ?, /).
  • Tags are not inherited. Tagging a resource group does not tag its resources. To inherit, use a Modify policy such as Inherit a tag from the resource group, or Cost Management's tag inheritance setting, which copies tags for cost reporting only.
  • Not every resource type supports tags, and some tags do not appear in billing data for certain services.
  • Tags move with the resource when you move it.
Bash
az tag update --resource-id "/subscriptions/$subscriptionId/resourceGroups/rg-app-prod" --operation merge \
  --tags Environment=Prod CostCenter=4521

Managing costs

Azure Cost Management has three tools the exam tests: cost analysis, budgets with alerts, and Azure Advisor.

Cost analysis

Cost analysis lets you group and filter spend by resource group, service, location or tag. This is where tags pay off: grouping by CostCenter gives each department its bill.

Budgets and alerts

A budget sets a spending threshold for a supported billing or resource scope over a period (monthly, quarterly, annually). You define one or more alert conditions as a percentage of the budget, for either actual or forecasted cost.

  • Budgets notify; they do not stop spending. Nothing is shut down automatically unless you attach an action group that triggers automation, such as a runbook or Logic App that deallocates VMs.
  • Scope availability depends on the billing offer. Use subscription or resource-group budgets for action-group integration; action groups are not supported for management-group budgets. The creator needs budget write permissions, for example Cost Management Contributor, and appropriate access to any action group.
  • Cost data is typically available after 8–24 hours and budgets are evaluated every 24 hours. Notifications and automation are delayed responses, not a hard spending cap. Amounts use the scope's billing currency.
Bash
az consumption budget create --budget-name monthly-dev --amount 2000 \
  --category cost --time-grain monthly \
  --start-date 2026-11-01 --end-date 2027-10-31 \
  --resource-group-filter rg-dev

This preview CLI command creates a subscription budget filtered to rg-dev; it does not create the email conditions or action-group integration. Configure those separately in Cost Management or an ARM/Bicep budget definition. For repeatable deployments, see ARM templates and Bicep for AZ-104.

Azure Advisor

Azure Advisor analyzes your resource configuration and usage and gives recommendations in five categories: Reliability, Security, Operational excellence, Performance and Cost. Cost recommendations include shutting down or resizing underused VMs, buying reservations or savings plans, and deleting unattached disks. You can filter by subscription, postpone or dismiss recommendations, and configure alerts to be notified when new ones arrive.

Worked example: responding to development budget thresholds

Scenario. A development subscription billed in EUR has a planning budget of 2,000 EUR per month. The team lead wants an email at 80% of actual spend, the finance team wants a warning when forecasted spend reaches 100%, and an alert at 110% of actual spend should trigger VM deallocation. The team accepts delayed notification and understands this cannot guarantee a maximum bill.

Solution.

  1. Create a monthly budget of 2,000 EUR scoped to the subscription.
  2. Add three conditions: Actual 80% (email to the team lead), Forecasted 100% (email to finance), Actual 110% (action group).
  3. Build an action group that runs an Azure Automation runbook or Logic App that deallocates VMs, and link it to the third condition.
  4. Use Advisor cost recommendations to find idle VMs ahead of time.

Why not simply rely on the budget? A budget alone sends notifications only. Without configured automation nothing is stopped. Even with automation, reporting delays and non-VM charges mean spending can exceed the threshold. A policy cannot cap spend either; policy can only restrict which SKUs or regions are allowed.

Pitfalls and exam tips

  • Policy vs RBAC. If the question says "regardless of the user's permissions" or "all resources must", think Policy. If it says "user X must be able to", think RBAC.
  • Deny does not fix existing resources. Look for Modify or DeployIfNotExists plus a remediation task.
  • Tags are not inherited unless a policy or Cost Management setting does it.
  • Locks beat Owner. An Owner cannot delete a locked resource until the lock is removed.
  • A ReadOnly lock can break things you did not expect, for example listing storage keys or scaling an App Service plan.
  • Changing directory removes role assignments; moving a management group does not.
  • Budgets do not stop spending.
  • Exclusions versus exemptions: an exclusion removes a scope from an assignment; an exemption is a separate object that waives specific resources and can expire.
  • A resource group's location does not restrict where its resources go. A common policy-versus-location confusion: only an Allowed locations policy does that.

Mini case study: Fabrikam consolidation

Fabrikam has acquired a smaller company. Its tenant now has four subscriptions: two production and two development. Requirements from the CIO:

  1. Supported regional resources in production must be in West Europe or North Europe; global resources are exempt.
  2. Developers may create anything in development, and each development subscription, billed in EUR, needs a 3,000 EUR monthly budget with a delayed automated response to overspend.
  3. The production network resource group must never be deleted by mistake, but network engineers must still change routes.
  4. Every taggable resource must carry an Owner tag. It may inherit a maintained Owner value from its resource group, and existing untagged resources must be repaired.

Proposed solution.

  • Create management groups Fabrikam-Prod and Fabrikam-Dev under the root and move the subscriptions into them.
  • Requirement 1: assign the built-in Allowed locations policy with Deny at Fabrikam-Prod. Because it is assigned at the management group, it also covers subscriptions added later.
  • Requirement 2: create a separate 3,000 EUR monthly budget on each development subscription with an actual-cost condition tied to an action group that deallocates VMs. Budget evaluation is delayed, so this reduces overspend rather than enforcing a hard cap. Review Advisor's cost recommendations monthly.
  • Requirement 3: place a CanNotDelete lock on the network resource group. A ReadOnly lock would block route changes, so it is the wrong choice.
  • Requirement 4: maintain an Owner tag on resource groups, then assign an inherit-if-missing Modify policy for taggable resources with the required managed identity and role. Run remediation for existing resources. A subsequent Deny rule can reject requests that remain untagged, for example when their group has no Owner value. Because Modify runs first, inheriting a valid value is deliberately allowed here.

Commentary. The key choices are the scope (management group so that future subscriptions inherit), the lock level (CanNotDelete, not ReadOnly), and using remediation for existing resources while deciding explicitly whether future requests may inherit tags or must supply their own values.

Key terms

  • Management group: container above subscriptions for applying policy and RBAC at scale.
  • Subscription: billing and quota boundary, tied to one Entra tenant.
  • Azure Policy: service that evaluates resource properties against rules.
  • Initiative: a set of policy definitions assigned as one unit.
  • Remediation task: job that fixes existing resources for Modify and DeployIfNotExists.
  • Resource lock: CanNotDelete or ReadOnly protection on a scope.
  • Tag: name/value metadata, not inherited by default.
  • Budget: spending threshold with alerts; it does not enforce a cap.
  • Azure Advisor: recommendation engine across five categories.

Summary checklist

  • I can draw the hierarchy from root management group to resource and say what is inherited.
  • I can pick the right policy effect and know that existing resources need a remediation task.
  • I know that Modify and DeployIfNotExists assignments need a managed identity with roles.
  • I can choose between CanNotDelete and ReadOnly and predict side effects.
  • I know tags are not inherited and how to enforce them.
  • I can move resources and explain what changes (resource ID, temporary write lock).
  • I can build budgets with actual and forecasted alerts, and I know they do not stop spending.
  • I can name Advisor's five categories.

For practical examples of these guardrails on real resources, continue with Azure storage account configuration and redundancy.

Official sources