Skip to main content

Module 3: Financial Controls & Budgets

Duration: 45 minutes | Level: Tactical
WAF Alignment: CO:02 (Cost Model), CO:03 (Cost Data), CO:04 (Spending Guardrails)


3.1 Financial Controls Architecture

Financial controls are the guardrails that prevent cloud cost overruns. They combine budgets, alerts, policies, and governance hierarchies to create a layered defense against uncontrolled spending.

Microsoft Learn: Cost Management best practices


3.2 Azure Management Groups Hierarchy for Cost Governance

Management Groups provide a scope above subscriptions for organizing resources and applying governance at scale — including budgets, policies, and RBAC.

Cost Governance at Each Level

ScopeBudget PurposePolicy ExamplesWho Manages
Tenant Root MGTotal enterprise cloud spend capGlobal tagging, audit policiesCloud CoE / FinOps team
Production MGProduction workload spend controlAllowed regions, allowed SKUs, deny public IPsPlatform team
Non-Prod MGDev/Test spend guardrailsAuto-shutdown, smaller SKU restrictionsEngineering leads
Sandbox MGInnovation budget with strict capMaximum resource count, auto-delete after 30 daysIndividual developers
SubscriptionPer-subscription operational budgetWorkload-specific policiesSubscription owner
Resource GroupPer-application cost trackingTag enforcementApplication team

Microsoft Learn: Organize resources with Management Groups
Microsoft Learn: Management Group design in CAF


3.3 Budget Deployment Scopes

ScopeUse CaseARM Template AvailableSchema
Management GroupEnterprise-wide cost governancebudget-mg-deployment.jsonmanagementGroupDeploymentTemplate
SubscriptionPer-subscription spending controlbudget-subscription-deployment.jsonsubscriptionDeploymentTemplate
Resource GroupPer-workload/application controlbudget-resourcegroup-deployment.jsondeploymentTemplate

3.4 Budget ARM Template - Complete Walkthrough

Subscription-Level Budget Template

The following ARM template deploys a budget at the subscription scope with configurable thresholds, notification contacts, action groups, and resource filters.

{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"budgetName": {
"defaultValue": "MyBudget",
"type": "String",
"metadata": {
"description": "Name of the Budget. It should be unique within a subscription."
}
},
"amount": {
"defaultValue": "1000",
"type": "String",
"metadata": {
"description": "The total amount of cost or usage to track with the budget"
}
},
"categoryType": {
"defaultValue": "Cost",
"allowedValues": ["Cost", "Usage"],
"type": "String",
"metadata": {
"description": "The category of the budget, whether the budget tracks cost or usage."
}
},
"timeGrain": {
"defaultValue": "Monthly",
"allowedValues": ["Monthly", "Quarterly", "Annually"],
"type": "String",
"metadata": {
"description": "The time covered by a budget. Tracking of the amount will be reset based on the time grain."
}
},
"startDate": {
"type": "String",
"metadata": {
"description": "The start date must be first of the month in YYYY-MM-DD format. Future start date should not be more than three months. Past start date should be selected within the timegrain period."
}
},
"endDate": {
"type": "String",
"metadata": {
"description": "The end date for the budget in YYYY-MM-DD format. If not provided, we default this to 10 years from the start date."
}
},
"firstThreshold": {
"defaultValue": "90",
"type": "String",
"metadata": {
"description": "Threshold value associated with a notification. Notification is sent when the cost exceeded the threshold. The number must be between 0 and 1000."
}
},
"firstThresholdType": {
"defaultValue": "Actual",
"allowedValues": ["Actual", "Forecasted"],
"type": "String",
"metadata": {
"description": "Threshold Type: 'Actual' triggers when spend reaches threshold. 'Forecasted' triggers when projected spend will exceed threshold."
}
},
"secondThreshold": {
"defaultValue": "110",
"type": "String",
"metadata": {
"description": "Second threshold value. Use values >100 to get alerts for overspend (e.g., 110 = alert at 110% of budget)."
}
},
"secondThresholdType": {
"defaultValue": "Actual",
"allowedValues": ["Actual", "Forecasted"],
"type": "String",
"metadata": {
"description": "Threshold Type for the second notification."
}
},
"contactRoles": {
"defaultValue": ["Owner", "Contributor"],
"type": "Array",
"metadata": {
"description": "The list of contact roles to send the budget notification to when the threshold is exceeded."
}
},
"contactEmails": {
"type": "Array",
"metadata": {
"description": "The list of email addresses to send the budget notification to when the threshold is exceeded."
}
},
"contactGroups": {
"type": "Array",
"metadata": {
"description": "The list of Action Group resource IDs to trigger when the threshold is exceeded."
}
},
"resourceGroupFilterValues": {
"type": "Array",
"metadata": {
"description": "Comma-separated list of resource groups to filter on. Only costs from these RGs are tracked."
}
},
"meterCategoryFilterValues": {
"type": "Array",
"defaultValue": [],
"metadata": {
"description": "Comma-separated list of meter categories (e.g., 'Virtual Machines', 'Storage') to filter on."
}
}
},
"resources": [
{
"type": "Microsoft.Consumption/budgets",
"apiVersion": "2021-10-01",
"name": "[parameters('budgetName')]",
"properties": {
"timePeriod": {
"startDate": "[parameters('startDate')]",
"endDate": "[parameters('endDate')]"
},
"timeGrain": "[parameters('timeGrain')]",
"amount": "[parameters('amount')]",
"category": "[parameters('categoryType')]",
"notifications": {
"NotificationForExceededBudget1": {
"enabled": true,
"operator": "GreaterThan",
"threshold": "[parameters('firstThreshold')]",
"thresholdType": "[parameters('firstThresholdType')]",
"contactEmails": "[parameters('contactEmails')]",
"contactRoles": "[parameters('contactRoles')]",
"contactGroups": "[parameters('contactGroups')]"
},
"NotificationForExceededBudget2": {
"enabled": true,
"operator": "GreaterThan",
"threshold": "[parameters('secondThreshold')]",
"thresholdType": "[parameters('secondThresholdType')]",
"contactEmails": "[parameters('contactEmails')]",
"contactRoles": "[parameters('contactRoles')]",
"contactGroups": "[parameters('contactGroups')]"
}
}
}
}
]
}

Parameter-by-Parameter Explanation

ParameterTypeRequiredDescription
budgetNameStringYesUnique name within the scope. Use naming convention like budget-<sub>-monthly
amountStringYesTotal budget amount in billing currency (e.g., 10000 for $10,000/month)
categoryTypeStringYesCost = track monetary spend; Usage = track consumption units
timeGrainStringYesReset period: Monthly (most common), Quarterly, or Annually
startDateStringYesMust be first of a month in YYYY-MM-DD format
endDateStringYesBudget expiration date. Set 1-10 years out
firstThresholdStringYesPercentage threshold (0-1000). Use 90 for early warning
firstThresholdTypeStringYesActual = alert on real spend; Forecasted = alert on projected spend
secondThresholdStringYesSecond threshold. 110 catches overspend
contactEmailsArrayYesEmail recipients for alerts
contactRolesArrayNoRBAC roles to notify (Owner, Contributor, Reader)
contactGroupsArrayNoAzure Action Group resource IDs for advanced alerting
resourceGroupFilterValuesArrayNoRestrict budget scope to specific resource groups
meterCategoryFilterValuesArrayNoFilter by service category (Virtual Machines, Storage, etc.)

Deploy the Template

# Deploy subscription-level budget
az deployment sub create `
--location "westeurope" `
--template-file "budget-subscription-deployment.json" `
--parameters `
budgetName="Production-Monthly-Budget" `
amount="15000" `
timeGrain="Monthly" `
startDate="2026-03-01" `
endDate="2027-03-01" `
firstThreshold="90" `
firstThresholdType="Forecasted" `
secondThreshold="100" `
secondThresholdType="Actual" `
contactEmails='["finops@company.com","cfo@company.com"]' `
contactRoles='["Owner"]' `
contactGroups='[]' `
resourceGroupFilterValues='[]' `
meterCategoryFilterValues='[]'

Full templates available in: knowledge_base/Module Financial Controls/Budgets/

Microsoft Learn: Tutorial: Create and manage budgets


3.5 Action Groups for Budget Alerts

Action Groups define who gets notified and what automated actions to take when a budget threshold is breached.

What Is an Action Group?

An Action Group is an Azure Monitor resource that specifies a collection of notification preferences and actions. Budget alerts can reference Action Groups to trigger:

Action TypeWhat It DoesExample Use Case
Email/SMSSend notifications to individualsAlert FinOps team at 90%
Azure FunctionRun serverless codeAuto-stop dev VMs after budget breach
Logic AppRun workflow automationCreate ServiceNow ticket for budget review
WebhookCall external APIPost alert to Slack / Teams channel
ITSMCreate ticket in ITSM toolAuto-create incident in ServiceNow
Automation RunbookRun Azure Automation scriptScale down resources when budget exceeded
Event HubStream alert to Event HubFeed into SIEM or analytics pipeline

Create an Action Group via CLI

# Create an Action Group for budget notifications
az monitor action-group create `
--resource-group "rg-finops" `
--name "FinOps-Budget-Alerts" `
--short-name "FinOpsBdgt" `
--action email finops-team finops-team@company.com `
--action email cfo cfo@company.com `
--action webhook teams-webhook "https://company.webhook.office.com/webhookb2/..." `
--tags CostCenter=IT-FinOps Environment=Production

Create an Action Group via ARM Template

{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Insights/actionGroups",
"apiVersion": "2023-01-01",
"name": "FinOps-Budget-Alerts",
"location": "Global",
"properties": {
"groupShortName": "FinOpsBdgt",
"enabled": true,
"emailReceivers": [
{
"name": "FinOps Team",
"emailAddress": "finops-team@company.com",
"useCommonAlertSchema": true
},
{
"name": "CFO Office",
"emailAddress": "cfo@company.com",
"useCommonAlertSchema": true
}
],
"smsReceivers": [
{
"name": "FinOps On-Call",
"countryCode": "1",
"phoneNumber": "5551234567"
}
],
"webhookReceivers": [
{
"name": "Teams Channel",
"serviceUri": "https://company.webhook.office.com/webhookb2/...",
"useCommonAlertSchema": true
}
],
"azureFunctionReceivers": [
{
"name": "Auto-Stop-DevVMs",
"functionAppResourceId": "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Web/sites/<funcApp>",
"functionName": "StopDevVMs",
"httpTriggerUrl": "https://<funcApp>.azurewebsites.net/api/StopDevVMs",
"useCommonAlertSchema": true
}
]
}
}
]
}

Reference the Action Group resource ID in budget contactGroups:

# Get the Action Group resource ID
$actionGroupId = az monitor action-group show `
--resource-group "rg-finops" `
--name "FinOps-Budget-Alerts" `
--query id --output tsv

# Create budget with Action Group
az consumption budget create `
--budget-name "Production-Monthly" `
--amount 10000 `
--time-grain Monthly `
--start-date "2026-03-01" `
--end-date "2027-03-01" `
--category Cost `
--notifications '{
"90PercentForecasted": {
"enabled": true,
"operator": "GreaterThanOrEqualTo",
"threshold": 90,
"thresholdType": "Forecasted",
"contactEmails": ["finops@company.com"],
"contactGroups": ["'$actionGroupId'"]
},
"100PercentActual": {
"enabled": true,
"operator": "GreaterThanOrEqualTo",
"threshold": 100,
"contactEmails": ["finops@company.com","cfo@company.com"],
"contactGroups": ["'$actionGroupId'"]
}
}'

Microsoft Learn: Create and manage Action Groups


3.6 Spending Guardrails with Azure Policy

Azure Policy-Based Guardrails

GuardrailPolicy EffectWhat It DoesBuilt-in?
Allowed VM SKUsDenyRestrict deployable VM sizes to approved listYes
Allowed RegionsDenyRestrict deployments to approved regionsYes
Require TagsDenyBlock untagged resource creationYes
Max Resource CountDenyLimit number of resources per subscriptionCustom
Require BudgetAuditFlag subscriptions without budgetsCustom
Deny Public IPsDenyPrevent public IP creationYes
Deny Premium StorageDenyBlock Premium SSD disks in Dev/TestCustom

Microsoft Learn: Azure Policy built-in definitions

Policy: Restrict Allowed VM SKUs

This policy restricts which VM sizes can be deployed, preventing teams from spinning up expensive SKUs without approval.

Built-in Policy ID: cccc23c7-8427-4f53-ad12-b6a63eb452b3

{
"properties": {
"displayName": "Allowed-VM-SKUs",
"policyType": "Custom",
"mode": "Indexed",
"description": "Restrict VM creation to approved cost-effective SKUs only",
"metadata": {
"category": "Compute",
"version": "1.0.0"
},
"parameters": {
"allowedSKUs": {
"type": "Array",
"metadata": {
"displayName": "Allowed VM SKUs",
"description": "The list of approved VM SKUs. e.g., Standard_B2s, Standard_D2s_v5"
},
"defaultValue": [
"Standard_B2s",
"Standard_B2ms",
"Standard_B4ms",
"Standard_D2s_v5",
"Standard_D4s_v5",
"Standard_D8s_v5",
"Standard_E2s_v5",
"Standard_E4s_v5"
]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"not": {
"field": "Microsoft.Compute/virtualMachines/sku.name",
"in": "[parameters('allowedSKUs')]"
}
}
]
},
"then": {
"effect": "deny"
}
}
}
}

Policy: Restrict Allowed Regions

Limit deployments to approved regions to control data residency and cost (regions have different pricing).

Built-in Policy ID: e56962a6-4747-49cd-b67b-bf8b01975c4c

{
"properties": {
"displayName": "Allowed-Regions",
"policyType": "Custom",
"mode": "Indexed",
"description": "Restrict resource deployment to approved Azure regions only",
"metadata": {
"category": "General",
"version": "1.0.0"
},
"parameters": {
"allowedLocations": {
"type": "Array",
"metadata": {
"displayName": "Allowed Locations",
"description": "The list of approved Azure regions",
"strongType": "location"
},
"defaultValue": [
"westeurope",
"northeurope",
"germanywestcentral"
]
}
},
"policyRule": {
"if": {
"not": {
"field": "location",
"in": "[parameters('allowedLocations')]"
}
},
"then": {
"effect": "deny"
}
}
}
}

Policy: Limit Maximum Resource Count per Resource Group

Prevent resource sprawl by setting a maximum number of resources a team can create.

{
"properties": {
"displayName": "Max-Resource-Count-Per-RG",
"policyType": "Custom",
"mode": "All",
"description": "Audit resource groups that exceed maximum resource count threshold",
"metadata": {
"category": "Cost Optimization",
"version": "1.0.0"
},
"parameters": {
"maxResourceCount": {
"type": "Integer",
"metadata": {
"displayName": "Maximum Resource Count",
"description": "Maximum number of resources allowed in a resource group"
},
"defaultValue": 50
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
"then": {
"effect": "audit"
}
}
}
}

Note: Azure Policy does not natively support counting resources within a resource group. Use this audit policy combined with Azure Resource Graph queries for monitoring, or implement an Azure Function trigger that evaluates resource count and blocks deployments via an approval workflow.

Policy: Deny Expensive Storage Tiers in Non-Production

{
"properties": {
"displayName": "Deny-Premium-Storage-NonProd",
"policyType": "Custom",
"mode": "Indexed",
"description": "Deny Premium SSD managed disks in non-production environments to reduce costs",
"metadata": {
"category": "Cost Optimization",
"version": "1.0.0"
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/disks"
},
{
"field": "Microsoft.Compute/disks/sku.name",
"in": ["Premium_LRS", "Premium_ZRS"]
},
{
"field": "tags['Environment']",
"in": ["Dev", "Test", "Staging"]
}
]
},
"then": {
"effect": "deny"
}
}
}
}

Assign Policies via CLI

# Assign allowed VM SKUs policy at subscription scope
az policy assignment create `
--name "Allowed-VM-SKUs" `
--display-name "Restrict VM sizes to approved SKUs" `
--policy "cccc23c7-8427-4f53-ad12-b6a63eb452b3" `
--params '{
"listOfAllowedSKUs": {
"value": ["Standard_B2s","Standard_B2ms","Standard_D2s_v5","Standard_D4s_v5"]
}
}' `
--scope "/subscriptions/<subscription-id>"

# Assign allowed regions policy at management group scope
az policy assignment create `
--name "Allowed-Regions" `
--display-name "Restrict to EU regions only" `
--policy "e56962a6-4747-49cd-b67b-bf8b01975c4c" `
--params '{
"listOfAllowedLocations": {
"value": ["westeurope","northeurope","germanywestcentral"]
}
}' `
--scope "/providers/Microsoft.Management/managementGroups/<mg-id>"

Microsoft Learn: Assign policies via CLI


3.7 Cost Anomaly Detection & Response

Azure Cost Management includes ML-powered anomaly detection that automatically identifies unusual spending patterns. It is enabled by default and available at no additional cost.

How Anomaly Detection Works

AspectDetail
AlgorithmMachine learning model trained on 90 days of historical spend
GranularityDetects daily anomalies per subscription
DimensionsAnalyzes by service, resource group, and resource
SensitivityAdjusts automatically based on spend variability
LatencyAnomalies detected within 24-36 hours of occurrence
CostFree, included with Azure Cost Management

Configuring Anomaly Alert Emails

  1. Navigate to Azure Portal > Cost Management > Cost alerts
  2. Under Anomaly alerts, click Manage
  3. Configure email recipients (supports up to 20 email addresses)
  4. Set alert frequency: Daily (same-day detection) or Weekly (digest)
  5. Anomaly alerts are scoped to subscription level

Microsoft Learn: Analyze unexpected charges

Common Anomaly Root Causes

CauseExampleImmediate ResponseLong-term Fix
Resource sprawlUnauthorized VM creationIdentify who created, stop/deleteApply deny policies
Scale eventAutoscaler triggered aggressivelyValidate if expected, set max limitsTune autoscaler settings
Pricing changeNew billing model appliedReview plan change historySet up price change alerts
Data explosionLog Analytics ingestion spikeApply daily capImplement data collection rules
Forgotten resourcesDev/test resources never cleaned upDelete orphaned resourcesAutomate cleanup scripts
Reservation expiryRI expired, resources on pay-as-you-goRenew or exchange reservationSet RI expiry reminders
New service deploymentLarge-scale deployment without budgetReview deployment, add to budgetRequire budget approval tag

Anomaly Investigation with Cost Analysis

Use the Cost Analysis smart views to investigate:

Azure Portal > Cost Management > Cost Analysis > Select "DailyCosts" view
> Filter by: Subscription, Date Range (last 7 days)
> Group by: Service name
> Look for spikes in the chart

3.8 Cost Management Exports

Cost Management exports allow you to schedule automated cost data delivery to an Azure Storage Account, where it can be consumed by Power BI, Fabric, or custom analytics pipelines.

Export Types

Export TypeDescriptionBest For
Actual CostCosts as billed (RI purchases shown as lump sums)Invoice reconciliation
Amortized CostRI/savings plan costs distributed over usage periodShowback/chargeback
FOCUS CostFOCUS-specification aligned formatMulti-cloud normalization
UsageUsage quantity without cost informationConsumption analysis

Configure Exports via CLI

# Create a daily amortized cost export
az costmanagement export create `
--name "Daily-Amortized-Export" `
--scope "/subscriptions/<subscription-id>" `
--type "AmortizedCost" `
--timeframe "MonthToDate" `
--storage-account-id "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<sa>" `
--storage-container "cost-exports" `
--storage-directory "amortized" `
--schedule-recurrence "Daily" `
--schedule-status "Active"

# Create a monthly actual cost export
az costmanagement export create `
--name "Monthly-Actual-Export" `
--scope "/subscriptions/<subscription-id>" `
--type "ActualCost" `
--timeframe "TheLastMonth" `
--storage-account-id "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<sa>" `
--storage-container "cost-exports" `
--storage-directory "actual" `
--schedule-recurrence "Monthly" `
--schedule-status "Active"

# List all configured exports
az costmanagement export list `
--scope "/subscriptions/<subscription-id>" `
--output table

# Trigger an export manually (run now)
az costmanagement export execute `
--name "Daily-Amortized-Export" `
--scope "/subscriptions/<subscription-id>"

Storage Account Best Practices for Exports

SettingRecommendationReason
SKUStandard LRSCost-effective for analytical data
Access TierCoolData accessed infrequently (monthly reporting)
Lifecycle policyDelete after 13 monthsRetain 1 year + current month
Network accessPrivate endpoint or service endpointSecurity
Container nameClear naming: cost-exportsDiscoverability

Connect Exports to Power BI

  1. Open Power BI Desktop
  2. Get Data > Azure > Azure Blob Storage or Azure Cost Management connector
  3. Enter Storage Account name and container
  4. Navigate to the CSV/Parquet files in the export directory
  5. Transform data as needed (parse dates, pivot tags)
  6. Publish to Power BI Service for scheduled refresh

Microsoft Learn: Analyze costs with Power BI
Microsoft Learn: Cost Management Power BI App


3.9 Managing Budgets via Azure CLI

Create Budgets

# Create a monthly budget with email alerts
az consumption budget create `
--budget-name "Production-Monthly" `
--amount 10000 `
--time-grain Monthly `
--start-date "2026-03-01" `
--end-date "2027-03-01" `
--category Cost

# Create budget with multiple threshold alerts
az consumption budget create `
--budget-name "DevTest-Budget" `
--amount 5000 `
--time-grain Monthly `
--start-date "2026-03-01" `
--end-date "2027-03-01" `
--category Cost `
--notifications '{
"50Percent": {
"enabled": true,
"operator": "GreaterThanOrEqualTo",
"threshold": 50,
"contactEmails": ["team-lead@company.com"],
"contactRoles": ["Owner"]
},
"75Percent": {
"enabled": true,
"operator": "GreaterThanOrEqualTo",
"threshold": 75,
"contactEmails": ["team-lead@company.com","finops@company.com"]
},
"90PercentForecasted": {
"enabled": true,
"operator": "GreaterThanOrEqualTo",
"threshold": 90,
"thresholdType": "Forecasted",
"contactEmails": ["finops@company.com"]
},
"100Percent": {
"enabled": true,
"operator": "GreaterThanOrEqualTo",
"threshold": 100,
"contactEmails": ["finops@company.com","cfo@company.com"]
},
"110Percent": {
"enabled": true,
"operator": "GreaterThanOrEqualTo",
"threshold": 110,
"contactEmails": ["finops@company.com","cfo@company.com","vp-engineering@company.com"]
}
}'

List and Manage Budgets

# List all budgets for the current subscription
az consumption budget list --output table

# Show details of a specific budget
az consumption budget show --budget-name "Production-Monthly"

# Delete a budget
az consumption budget delete --budget-name "Old-Budget-2025"

# Update budget amount
az consumption budget update `
--budget-name "Production-Monthly" `
--amount 12000

Resource-Scoped Budgets via REST API

For resource-group-level budgets, use the REST API or ARM templates:

# Deploy a resource-group-scoped budget via ARM template
az deployment group create `
--resource-group "rg-production-erp" `
--template-file "budget-resourcegroup-deployment.json" `
--parameters `
budgetName="ERP-Monthly-Budget" `
amount="8000" `
startDate="2026-03-01" `
endDate="2027-03-01" `
contactEmails='["erp-team@company.com"]' `
contactRoles='["Owner","Contributor"]' `
contactGroups='[]' `
resourceGroupFilterValues='[]' `
meterFilterValues='[]'

Microsoft Learn: Create budgets programmatically
Microsoft Learn: Budgets API reference


3.10 Cost Management Copilot Capabilities

Azure Cost Management includes Microsoft Copilot integration that allows natural language queries about your cloud spend.

What You Can Ask Copilot

Query TypeExample PromptWhat It Returns
Spend summary"What did I spend last month?"Total cost with service breakdown
Cost comparison"Compare this month vs last month"Variance analysis with % change
Top spenders"What are my top 5 most expensive resources?"Ranked resource list with costs
Anomaly investigation"Why did my cost spike on Feb 15?"Root cause analysis with details
Service breakdown"How much am I spending on VMs vs Storage?"Service-level cost comparison
Forecast"What will I spend this month?"Projected month-end total
Savings opportunities"Where can I save money?"Advisor recommendations summary

How to Access

  1. Navigate to Azure Portal > Cost Management > Cost Analysis
  2. Click the Copilot icon (sparkle icon) in the top toolbar
  3. Type your cost question in natural language
  4. Copilot generates analysis with charts and data tables

Prerequisites

  • Must have Cost Management Reader role or higher
  • Feature may require opt-in via Cost Management Labs
  • Available for EA, MCA, and CSP billing accounts

Microsoft Learn: Microsoft Copilot in Azure Cost Management


3.11 Cost Governance Best Practices

PracticeLevelDescriptionLearn More
Set budgets at every scopeBasicMG, Subscription, and RG level budgetsLink
Configure multi-threshold alertsBasic50%, 75%, 90%, 100%, 110%Link
Enable anomaly alertsBasicAI-powered anomaly detection (free)Link
Create Action GroupsBasicRoute alerts to email, SMS, webhooks, automationLink
Implement Azure PolicyIntermediateRestrict SKUs, regions, require tagsLink
Schedule weekly cost reviewsIntermediateReview Cost Analysis with stakeholdersLink
Automate cost exportsIntermediateExport to Storage, process with Power BILink
Use forecasted thresholdsIntermediateAlert on projected overspend before it happensLink
Implement resource locksAdvancedPrevent accidental deletion of critical resourcesLink
Use Management GroupsAdvancedHierarchical governance across subscriptionsLink
Try Copilot in Cost MgmtAdvancedNatural language cost investigationLink
Automate via Action GroupsAdvancedTrigger Functions/Runbooks on budget breachLink
ThresholdTypeRecipientPurpose
50%ActualTeam LeadAwareness checkpoint
75%ActualTeam Lead + FinOpsReview spending trajectory
80%ForecastedFinOps TeamEarly warning on projected overspend
90%ActualFinOps + Engineering VPInvestigation required
100%ActualFinOps + CFOBudget exceeded, action required
110%ActualFinOps + CFO + CTOEscalation, remediation mandatory

Implementation Checklist

#TaskPriorityStatus
1Design Management Group hierarchy for cost governanceP0
2Create budgets at MG, subscription, and RG scopesP0
3Configure multi-threshold alerts (50%, 75%, 90%, 100%, 110%)P0
4Set up Action Groups with email + webhook notificationsP0
5Enable anomaly detection alertsP1
6Deploy allowed VM SKUs policy at Production MGP1
7Deploy allowed regions policy at Tenant Root MGP1
8Configure daily amortized cost exports to Storage AccountP1
9Connect Power BI to cost export dataP2
10Implement forecasted threshold alerts at 80%P2
11Set up automated remediation via Action Group + FunctionsP3
12Trial Copilot in Cost Management for ad-hoc analysisP3

References


Previous Module: Module 2 — Cost Transparency & Tagging
Next Module: Module 4 — Rate Optimization
Back to Overview: README — Cost Optimization

📖Learn