Azure Cost Governance & Policies — Complete Guide
In this tutorial, you'll learn about Azure Cost Governance & Policies. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Azure cost governance is the discipline of enforcing spending rules across subscriptions using Azure Policy, management groups, RBAC, and mandatory tagging — preventing resource sprawl before it reaches the bill.
What You'll Learn
You'll implement Azure Policy to enforce cost rules, design a management group hierarchy for budget isolation, apply RBAC to restrict expensive resource creation, and build a tagging governance framework that ensures every resource is accountable to a cost center.
Why It Matters
Without governance, developers provision GPU VMs for testing, leave load balancers running over weekends, and spin up resources in expensive regions — all without oversight. Azure Policy and management groups prevent this at the subscription level. DodaTech reduced non-production spend by 35% across 12 subscriptions by enforcing Deny policies on expensive SKUs for dev environments.
flowchart TD
A[Management Group Root] --> B[Production MG]
A --> C[Non-Production MG]
A --> D[Sandbox MG]
B --> E[Azure Policy: Allowed SKUs]
B --> F[Policy: Required Tags]
C --> G[Policy: Deny GPU / High-Mem]
C --> H[Policy: Enforce Dev/Test Pricing]
D --> I[Policy: Budget Limit $500]
D --> J[Policy: Auto-Shutdown 7PM-7AM]
E --> K[Compliant Spend]
style K fill:#22c55e,color:#fff
1. Management Group Hierarchy
Management groups let you apply policies and budgets at scale across hundreds of subscriptions.
# Create management group structure
az account management-group create --name "dodatech-root" --display-name "DodaTech Root"
az account management-group create --name "production" --display-name "Production" --parent "dodatech-root"
az account management-group create --name "non-prod" --display-name "Non-Production" --parent "dodatech-root"
az account management-group create --name "sandbox" --display-name "Sandbox" --parent "dodatech-root"
# Move a subscription into a management group
az account management-group subscription add \
--name "production" \
--subscription "sub-12345678-1234-1234-1234-123456789012"
# List hierarchy
az account management-group list --query "[].{Name:name, DisplayName:displayName, Children:children}"
Expected output:
[
{"Name": "dodatech-root", "DisplayName": "DodaTech Root", "Children": ["production", "non-prod", "sandbox"]},
{"Name": "production", "DisplayName": "Production", "Children": []},
{"Name": "non-prod", "DisplayName": "Non-Production", "Children": []},
{"Name": "sandbox", "DisplayName": "Sandbox", "Children": []}
]
2. Azure Policy for Cost Control
Azure Policy enforces rules on resources at creation time. Cost-related policies prevent expensive resources in environments where they don't belong.
# Create a policy to deny expensive VM SKUs in non-production
az policy definition create \
--name "deny-expensive-skus-nonprod" \
--display-name "Deny expensive VM SKUs in non-prod" \
--description "Prevent GPU, memory-optimized, and high-CPU VMs in non-production subscriptions" \
--rules '{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines]
},
{
"field": "Microsoft.Compute/virtualMachines/sku.name",
"in": ["Standard_NC6", "Standard_NC12", "Standard_NC24", "Standard_E64s_v3", "Standard_E80is_v4"]
}
]
},
"then": {"effect": "Deny"}
}'
# Assign policy to non-production management group
az policy assignment create \
--name "deny-expensive-skus-nonprod-assignment" \
--policy "deny-expensive-skus-nonprod" \
--scope "/providers/Microsoft.Management/managementGroups/non-prod"
# Create a policy to require specific tags
az policy definition create \
--name "require-cost-tags" \
--display-name "Require cost allocation tags" \
--rules '{
"if": {
"field": "tags",
"exists": "false"
},
"then": {"effect": "deny"}
}' \
--params '{
"tagNames": {
"type": "Array",
"metadata": {"displayName": "Required Tags"},
"allowedValues": ["CostCenter", "Environment", "Project", "Owner"]
}
}'
Expected output:
{
"name": "deny-expensive-skus-nonprod",
"properties": {
"policyType": "Custom",
"mode": "All",
"displayName": "Deny expensive VM SKUs in non-prod"
}
}
3. RBAC for Cost Management
Use Azure RBAC to control who can create, modify, or delete resources and manage budgets.
# Create a custom role for cost viewers
az role definition create \
--role-definition '{
"Name": "Cost Reader",
"Description": "View costs and budgets but cannot modify resources",
"Actions": [
"Microsoft.Consumption/*/read",
"Microsoft.Billing/*/read",
"Microsoft.Management/*/read]
],
"DataActions": [],
"NotActions": [],
"AssignableScopes": ["/subscriptions/sub-12345678-1234-1234-1234-123456789012"]
}'
# Assign Cost Reader role to a user
az role assignment create \
--assignee "finops-user@dodatech.com" \
--role "Cost Reader" \
--scope "/subscriptions/sub-12345678-1234-1234-1234-123456789012"
# Restrict who can create expensive resources
az role definition create \
--role-definition '{
"Name": "Limited VM Creator",
"Description": "Can only create VMs under a specific cost threshold",
"Actions": [
"Microsoft.Compute/virtualMachines/write",
"Microsoft.Network/*/write]
],
"NotActions": [],
"AssignableScopes": ["/subscriptions/sub-12345678-1234-1234-1234-123456789012/resourceGroups/dev-rg"]
}'
4. Tagging Governance Strategy
Enforce a standard tag taxonomy across all resources for cost allocation and chargeback.
# Apply tags to a resource group via policy
az policy definition create \
--name "inherit-resourcegroup-tags" \
--display-name "Inherit resource group tags on new resources" \
--rules '{
"if": {
"field": "type",
"in": ["Microsoft.Compute/virtualMachines", "Microsoft.Storage/storageAccounts", "Microsoft.Sql/servers/databases"]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": ["/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"],
"operations": [
{
"operation": "addOrReplace",
"field": "tags[\"CostCenter\"]",
"value": "[resourceGroup().tags[\"CostCenter\"]]"
}
]
}
}
}'
Mandatory tag taxonomy:
CostCenter: cc-1001, cc-1002, cc-1003Environment: prod, staging, dev, test, sandboxProject: web-app, data-pipeline, ml-trainingOwner: email alias of team responsibleAutoShutdown: true, false (enforced on non-prod)
5. Budget Governance with Action Groups
Automate responses to budget breaches using Azure Action Groups.
# Create an action group for cost alerts
az monitor action-group create \
--name "cost-alerts" \
--resource-group "management-rg" \
--action email finops "finops@example.com" \
--action email cto "cto@example.com" \
--action azure-function auto-remediate "func-cost-remediation.azurewebsites.net"
# Create a budget with automated actions
az consumption budget create \
--budget-name "monthly-prod" \
--category cost \
--amount 50000 \
--time-grain monthly \
--scope "/subscriptions/sub-12345678-1234-1234-1234-123456789012" \
--start-date 2026-01-01 \
--end-date 2026-12-31 \
--notifications '{
"Actual_GreaterThan_80": {
"enabled": true,
"operator": "GreaterThan",
"threshold": 80,
"contact-emails": ["finops"@example".com"],
"contact-roles": ["Owner"],
"contact-groups": ["/subscriptions/sub-12345678-1234-1234-1234-123456789012/resourceGroups/management-rg/providers/microsoft.insights/actionGroups/cost-alerts"]
}
}'
Common Mistakes
Policies without exclusions: A blanket Deny policy can block legitimate production deployments. Always add exclusion scopes for emergency break-glass scenarios.
No management group hierarchy: Applying policies to individual subscriptions is unsustainable at scale. Use management groups for inheritance.
Tags without enforcement: Optional tags are ignored. Use Azure Policy with
denyormodifyeffects to enforce mandatory tags at resource creation.RBAC too permissive: The
Contributorrole can create any resource. Scope custom roles to specific resource types and SKUs for cost-sensitive environments.Ignoring sandbox subscriptions: Without budget limits, sandbox subscriptions can run up costs. Enforce strict budgets and auto-shutdown policies on sandboxes.
Practice Questions
How does Azure Policy prevent cost overruns before they happen? Answer: Azure Policy evaluates resources at creation time and can
DenyorModifythem based on rules — preventing expensive SKUs, enforcing tags, and blocking resources in unapproved regions before they incur cost.What is the difference between a management group and a subscription in cost governance? Answer: Management groups are containers for organizing subscriptions. Policies and budgets applied at the management group level are inherited by all child subscriptions, enabling governance at scale.
How do you enforce mandatory cost allocation tags across all Azure resources? Answer: Create a custom Azure Policy definition with effect
denythat requires specific tags (CostCenter,Environment,Owner) on all resources. Assign it at the root management group.
Challenge
Design a cost governance framework for a 50-subscription Azure enterprise: create a three-level management group hierarchy (Production, Non-Production, Sandbox), write Azure Policy definitions that deny GPU SKUs in non-production and require CostCenter tags, assign the Cost Reader role to each team's FinOps lead, configure budget alerts at 80/95/100% with Action Groups, and implement auto-shutdown policies for all non-production VMs between 7 PM and 7 AM.
FAQ
What's Next
| Topic | Description |
|---|---|
| {{< card link="../azure-cost-management" title="Azure Cost Management" icon="currency-dollar" >}} | Full Azure cost optimization guide |
| {{< card link="../tagging-labeling-strategy" title="Tagging & Labeling Strategy" icon="tag" >}} | Cloud resource tagging best practices |
Related topics: Cloud Cost Optimization, Azure, DevOps
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro