Skip to main content

Module 2: Cost Transparency & Tagging Strategy

Duration: 45 minutes | Level: Tactical
WAF Alignment: CO:01 (Financial Responsibility), CO:03 (Cost Data), CO:04 (Guardrails)


2.1 Why Cost Transparency Matters

Cost transparency is the foundation of any FinOps practice. Without it, organizations cannot:

  • Perform showback/chargeback to business units
  • Understand cost per workload or application
  • Identify cost anomalies or orphaned resources
  • Establish an accountability model for cost ownership
  • Make data-driven decisions about infrastructure spend
  • Benchmark cloud spend against industry standards

Key Insight: Organizations that implement robust cost transparency typically achieve 20-30% cost reduction within the first 6 months by exposing waste that was previously invisible.

Reference: FinOps Foundation - State of FinOps Report


2.2 Azure Tagging Strategy for Cost Management

Tags are key-value pairs applied to Azure resources, resource groups, and subscriptions. They are the primary mechanism for organizing, categorizing, and allocating cloud costs.

Microsoft Learn: Use tags to organize your Azure resources

Tag NamePurposeExample ValuesRequired?Scope
CostCenterFinancial allocation codeCC-1234, IT-OPS-001YESAll resources
BusinessUnitOrganizational unitEngineering, Marketing, HRYESAll resources
WorkloadNameApplication/workload nameERP-Production, WebApp-v2YESAll resources
EnvironmentDeployment environmentProduction, Staging, Dev, TestYESAll resources
BudgetApprovedBudget approval statusYes, No, PendingYESAll resources
OwnerResponsible person/teamteam-platform@company.comRECOMMENDEDAll resources
ProjectProject identifierPRJ-2026-MigrationRECOMMENDEDAll resources
EndDateExpected decommission date2026-12-31RECOMMENDEDNon-production
DataClassificationData sensitivity levelPublic, Internal, ConfidentialRECOMMENDEDData resources
CreatedByWho created the resourcejohn.doe@company.comOPTIONALAll resources
CriticalityBusiness criticalityHigh, Medium, LowOPTIONALProduction

Tag Naming Convention Rules

RuleGood ExampleBad Example
Use PascalCase consistentlyCostCentercost_center, costcenter
Keep names short but descriptiveBusinessUnitTheBusinessUnitThisResourceBelongsTo
Use standard valuesProduction, Devprod, PROD, production
Avoid special charactersPRJ-2026PRJ/2026, PRJ@2026
Document conventions in a tag dictionaryPublished wikiTribal knowledge

Microsoft Learn: Define your tagging strategy


2.3 Tag Inheritance Strategies

Azure does not automatically inherit tags from subscription to resource group to resource. You must implement tag inheritance manually using Azure Policy.

Strategy 1: Inherit Tag from Resource Group (Built-in Policy)

Azure provides a built-in policy to inherit tags from resource groups to resources:

  • Policy Name: Inherit a tag from the resource group
  • Policy ID: cd3aa116-8754-49c9-a813-ad46512ece54
  • Effect: Modify (automatically applies the tag)

Microsoft Learn: Assign policy for tag inheritance

Strategy 2: Inherit Tag from Subscription (Built-in Policy)

  • Policy Name: Inherit a tag from the subscription
  • Policy ID: b27a0cbd-a167-4571-a2ee-5f4b6cc94836
  • Effect: Modify (automatically applies the tag)

Implementation: Assign Tag Inheritance Policy via CLI

# Inherit CostCenter tag from Resource Group to child resources
az policy assignment create `
--name "Inherit-CostCenter-from-RG" `
--display-name "Inherit CostCenter tag from Resource Group" `
--policy "cd3aa116-8754-49c9-a813-ad46512ece54" `
--params '{"tagName": {"value": "CostCenter"}}' `
--scope "/subscriptions/<subscription-id>" `
--mi-system-assigned `
--location "westeurope" `
--role "Tag Contributor" `
--identity-scope "/subscriptions/<subscription-id>"

# Inherit BusinessUnit tag from Subscription to child resources
az policy assignment create `
--name "Inherit-BusinessUnit-from-Sub" `
--display-name "Inherit BusinessUnit tag from Subscription" `
--policy "b27a0cbd-a167-4571-a2ee-5f4b6cc94836" `
--params '{"tagName": {"value": "BusinessUnit"}}' `
--scope "/subscriptions/<subscription-id>" `
--mi-system-assigned `
--location "westeurope" `
--role "Tag Contributor" `
--identity-scope "/subscriptions/<subscription-id>"

Important: The Modify effect requires a managed identity with Tag Contributor role. The policy assignment will create a remediation task for existing resources.

Microsoft Learn: Remediate non-compliant resources


2.4 Azure Policy for Tag Enforcement

Three Levels of Tag Governance

LevelEffectBehaviorWhen to Use
Level 1AuditFlags non-compliant resources in dashboardStarting out, building awareness
Level 2ModifyAuto-adds or corrects tags on resourcesRemediating existing estate
Level 3DenyBlocks resource creation without tagsMature governance, strict enforcement

Microsoft Learn: Understand Azure Policy effects

Policy: Audit Missing Tags (Level 1)

This policy audits resources missing required cost tags. Non-compliant resources appear in the Azure Policy compliance dashboard.

{
"properties": {
"displayName": "Audit-Cost-Tags",
"policyType": "Custom",
"mode": "Indexed",
"description": "Audit resources missing required cost transparency tags. Non-compliant resources are reported but not blocked.",
"metadata": {
"category": "Tags",
"version": "1.0.0"
},
"parameters": {
"tagName1": {
"type": "String",
"metadata": {
"displayName": "Tag Name 1",
"description": "First required tag name, e.g., 'CostCenter'"
}
},
"tagName2": {
"type": "String",
"metadata": {
"displayName": "Tag Name 2",
"description": "Second required tag name, e.g., 'BusinessUnit'"
}
},
"tagName3": {
"type": "String",
"metadata": {
"displayName": "Tag Name 3",
"description": "Third required tag name, e.g., 'WorkloadName'"
}
}
},
"policyRule": {
"if": {
"anyOf": [
{
"field": "[concat('tags[', parameters('tagName1'), ']')]",
"exists": "false"
},
{
"field": "[concat('tags[', parameters('tagName2'), ']')]",
"exists": "false"
},
{
"field": "[concat('tags[', parameters('tagName3'), ']')]",
"exists": "false"
}
]
},
"then": {
"effect": "audit"
}
}
}
}

Policy: Auto-Remediate Tags Using Modify Effect (Level 2)

The modify effect is the recommended approach for tag remediation automation. It automatically adds missing tags with default values and can correct incorrect tag values. Unlike append, the modify effect can update existing resources through remediation tasks.

{
"properties": {
"displayName": "Modify-Add-CostCenter-Tag",
"policyType": "Custom",
"mode": "Indexed",
"description": "Adds CostCenter tag with a default value if the tag is missing. Uses modify effect to support remediation of existing resources.",
"metadata": {
"category": "Tags",
"version": "1.0.0"
},
"parameters": {
"tagName": {
"type": "String",
"defaultValue": "CostCenter",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag to add, e.g., 'CostCenter'"
}
},
"tagValue": {
"type": "String",
"defaultValue": "UNASSIGNED",
"metadata": {
"displayName": "Tag Value",
"description": "Default value for the tag, e.g., 'UNASSIGNED'"
}
}
},
"policyRule": {
"if": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": "false"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/4a9ae827-6dc8-4573-8ac7-8239d42aa03f"
],
"operations": [
{
"operation": "addOrReplace",
"field": "[concat('tags[', parameters('tagName'), ']')]",
"value": "[parameters('tagValue')]"
}
]
}
}
}
}
}

Key Detail: The roleDefinitionIds value 4a9ae827-... is the built-in Tag Contributor role. The policy engine needs this role to modify resource tags.

Microsoft Learn: Azure Policy modify effect

Running a Remediation Task for Existing Resources

After deploying a Modify policy, existing non-compliant resources are not automatically fixed. You must create a remediation task:

# Create a remediation task for an existing policy assignment
az policy remediation create `
--name "Remediate-CostCenter-Tags" `
--policy-assignment "Inherit-CostCenter-from-RG" `
--scope "/subscriptions/<subscription-id>" `
--resource-discovery-mode "ReEvaluateCompliance"

Microsoft Learn: Create a remediation task

Policy: Append Tags with Default Values (Level 2 - Legacy)

This policy adds default tag values at resource creation time. Note: append is the legacy approach; prefer modify for new implementations.

{
"properties": {
"displayName": "Append-Cost-Tags",
"policyType": "Custom",
"mode": "Indexed",
"description": "Add cost tags with default values to resources at creation time.",
"metadata": {
"category": "Tags",
"version": "1.0.0"
},
"parameters": {
"tagName1": {
"type": "String",
"metadata": {
"displayName": "Tag Name 1",
"description": "Name of first tag, such as 'WorkloadName'"
}
},
"tagValue1": {
"type": "String",
"metadata": {
"displayName": "Tag Value 1",
"description": "Default value of the tag, such as 'UNASSIGNED'"
}
},
"tagName2": {
"type": "String",
"metadata": {
"displayName": "Tag Name 2",
"description": "Name of second tag, such as 'BusinessUnit'"
}
},
"tagValue2": {
"type": "String",
"metadata": {
"displayName": "Tag Value 2",
"description": "Default value of the tag, such as 'UNASSIGNED'"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "[concat('tags[', parameters('tagName1'), ']')]",
"exists": "false"
},
{
"field": "[concat('tags[', parameters('tagName2'), ']')]",
"exists": "false"
}
]
},
"then": {
"effect": "append",
"details": [
{
"field": "[concat('tags[', parameters('tagName1'), ']')]",
"value": "[parameters('tagValue1')]"
},
{
"field": "[concat('tags[', parameters('tagName2'), ']')]",
"value": "[parameters('tagValue2')]"
}
]
}
}
}
}

Policy: Enforce Required Tags - Deny (Level 3)

This policy blocks resource creation if required cost tags are missing. Deploy this only after Level 1 and Level 2 have been in place and compliance is above 90%.

{
"properties": {
"displayName": "Enforce-Cost-Tags-Deny",
"policyType": "Custom",
"mode": "Indexed",
"description": "Deny resource creation without required cost tags: CostCenter, BusinessUnit, WorkloadName, Environment, BudgetApproved",
"metadata": {
"category": "Tags",
"version": "1.0.0"
},
"parameters": {
"tagName1": {
"type": "String",
"defaultValue": "CostCenter",
"metadata": {
"displayName": "Tag Name 1",
"description": "First required tag, e.g., 'CostCenter'"
}
},
"tagName2": {
"type": "String",
"defaultValue": "BusinessUnit",
"metadata": {
"displayName": "Tag Name 2",
"description": "Second required tag, e.g., 'BusinessUnit'"
}
},
"tagName3": {
"type": "String",
"defaultValue": "WorkloadName",
"metadata": {
"displayName": "Tag Name 3",
"description": "Third required tag, e.g., 'WorkloadName'"
}
},
"tagName4": {
"type": "String",
"defaultValue": "Environment",
"metadata": {
"displayName": "Tag Name 4",
"description": "Fourth required tag, e.g., 'Environment'"
}
},
"tagName5": {
"type": "String",
"defaultValue": "BudgetApproved",
"metadata": {
"displayName": "Tag Name 5",
"description": "Fifth required tag, e.g., 'BudgetApproved'"
}
}
},
"policyRule": {
"if": {
"anyOf": [
{
"field": "[concat('tags[', parameters('tagName1'), ']')]",
"exists": "false"
},
{
"field": "[concat('tags[', parameters('tagName2'), ']')]",
"exists": "false"
},
{
"field": "[concat('tags[', parameters('tagName3'), ']')]",
"exists": "false"
},
{
"field": "[concat('tags[', parameters('tagName4'), ']')]",
"exists": "false"
},
{
"field": "[concat('tags[', parameters('tagName5'), ']')]",
"exists": "false"
}
]
},
"then": {
"effect": "deny"
}
}
}
}

Available in knowledge base: Module Cost Transparency/Policy-Audit-Tags.json, Policy-Enforce-Cost-Tags.json, Policy-Append-Cost-Tags.json

Policy Rollout Best Practice

  1. Weeks 1-2: Deploy Audit policies to assess current compliance
  2. Weeks 3-4: Review compliance dashboard, socialize results with teams
  3. Weeks 5-6: Deploy Modify policies with default values (e.g., UNASSIGNED)
  4. Weeks 7-8: Run remediation tasks, verify tag coverage reaches >90%
  5. Weeks 9+: Deploy Deny policies to enforce going forward

2.5 Azure Resource Graph Queries for Untagged Resources

Azure Resource Graph enables fast queries across your entire Azure estate. Use these queries to find resources missing cost tags.

Query: Find All Resources Missing CostCenter Tag

resources
| where isnull(tags['CostCenter']) or tags['CostCenter'] == ''
| project name, type, resourceGroup, subscriptionId, location
| order by type asc

Query: Count Untagged Resources by Resource Type

resources
| where isnull(tags['CostCenter']) or tags['CostCenter'] == ''
| summarize count() by type
| order by count_ desc

Query: Tag Compliance Summary Across Subscriptions

resources
| extend hasCostCenter = isnotnull(tags['CostCenter']) and tags['CostCenter'] != ''
| extend hasBusinessUnit = isnotnull(tags['BusinessUnit']) and tags['BusinessUnit'] != ''
| extend hasWorkloadName = isnotnull(tags['WorkloadName']) and tags['WorkloadName'] != ''
| extend hasEnvironment = isnotnull(tags['Environment']) and tags['Environment'] != ''
| summarize
totalResources = count(),
taggedCostCenter = countif(hasCostCenter),
taggedBusinessUnit = countif(hasBusinessUnit),
taggedWorkloadName = countif(hasWorkloadName),
taggedEnvironment = countif(hasEnvironment)
by subscriptionId
| extend compliancePct = round(todouble(taggedCostCenter) / todouble(totalResources) * 100, 1)
| order by compliancePct asc

Query: Find Resources with UNASSIGNED Default Tags

resources
| where tags['CostCenter'] == 'UNASSIGNED'
or tags['BusinessUnit'] == 'UNASSIGNED'
| project name, type, resourceGroup, subscriptionId, tags
| order by type asc

Query: List All Unique Tag Keys in Use

resources
| mvexpand tags
| extend tagKey = tostring(bag_keys(tags)[0])
| distinct tagKey
| order by tagKey asc

Query: Find Resources by Specific Tag Value

resources
| where tags['Environment'] == 'Dev'
| summarize resourceCount = count(), estimatedMonthlyCost = sum(todouble(tags['MonthlyCost']))
by resourceGroup, subscriptionId
| order by resourceCount desc

Run Resource Graph Queries via CLI

# Run a Resource Graph query from Azure CLI
az graph query -q "
resources
| where isnull(tags['CostCenter']) or tags['CostCenter'] == ''
| summarize count() by type
| order by count_ desc
" --output table

# Export results to CSV for reporting
az graph query -q "
resources
| where isnull(tags['CostCenter'])
| project name, type, resourceGroup, subscriptionId
" --output tsv > untagged-resources.csv

Microsoft Learn: Starter Resource Graph queries


2.6 FOCUS Specification (FinOps Open Cost and Usage Specification)

What is FOCUS?

The FinOps Open Cost and Usage Specification (FOCUS) is an open-source specification that defines a vendor-neutral schema for cloud cost and usage data. It was created by the FinOps Foundation to standardize how cloud cost data is structured across providers, making multi-cloud cost management possible.

FOCUS Website: https://focus.finops.org/
Microsoft Learn: Understand FOCUS cost details

Why FOCUS Matters

Challenge Without FOCUSSolution With FOCUS
Each cloud provider uses different column namesStandardized column names across providers
AWS "Blended Rate" vs Azure "EffectivePrice"Unified EffectivePrice, BilledCost, ListCost
Comparing costs across clouds is manualJoin datasets using common schema
FinOps tooling must handle provider-specific formatsSingle schema all tools can consume
Showback/chargeback logic differs per cloudConsistent allocation logic

Key FOCUS Columns

FOCUS ColumnDescriptionExample Value
BillingAccountIdUnique ID for the billing account1234567890
BillingAccountNameFriendly name of the billing accountContoso Enterprise
BillingPeriodStartStart date of the billing period2026-02-01
BillingPeriodEndEnd date of the billing period2026-02-28
ChargePeriodStartStart of the charge window2026-02-15T00:00:00Z
ChargePeriodEndEnd of the charge window2026-02-16T00:00:00Z
ChargeCategoryType of chargeUsage, Purchase, Tax
ChargeFrequencyHow often the charge recursUsage-Based, One-Time, Recurring
CommitmentDiscountIdID of commitment (reservation/savings plan)reservations/abc123
EffectiveCostCost after all discounts applied12.50
BilledCostAmount actually billed12.50
ListCostCost at on-demand/list pricing25.00
ListUnitPriceOn-demand unit price0.10
PricingQuantityQuantity used for pricing125
PricingUnitUnit of measure for pricingHours, GB
ProviderNameCloud provider nameMicrosoft
PublisherNamePublisher of the serviceMicrosoft
RegionIdRegion identifierwesteurope
RegionNameFriendly region nameWest Europe
ResourceIdUnique resource identifier/subscriptions/.../vm1
ResourceNameFriendly resource namemyVirtualMachine01
ResourceTypeType of resourceVirtual Machine
ServiceCategoryCategory of serviceCompute, Storage, Networking
ServiceNameName of the serviceVirtual Machines
SkuIdSKU identifierDZH318Z0BPS6
SubAccountIdSub-account (subscription) IDsub-guid-here
SubAccountNameSub-account (subscription) nameProduction-Sub
TagsResource tags as key-value pairs{"CostCenter":"CC-1234"}

FOCUS vs Azure Native Cost Data Mapping

Azure Native ColumnFOCUS EquivalentNotes
SubscriptionIdSubAccountIdDirect mapping
SubscriptionNameSubAccountNameDirect mapping
ResourceIdResourceIdDirect mapping
MeterCategoryServiceNameApproximate mapping
CostInBillingCurrencyBilledCostDirect mapping
EffectivePriceEffectiveCost / PricingQuantityCalculated
PayGPriceListUnitPriceDirect mapping
ReservationIdCommitmentDiscountIdDirect mapping
TagsTagsDirect mapping (JSON format)

Accessing FOCUS Data in Azure

Azure Cost Management supports FOCUS-aligned exports:

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

Microsoft Learn: FOCUS cost and usage details


2.7 Cost Allocation Rules in Azure Cost Management

What Are Cost Allocation Rules?

Cost allocation rules allow you to redistribute shared costs (like networking, security, or platform services) across business units, subscriptions, or resource groups — even when those costs cannot be directly tagged.

When to Use Cost Allocation Rules

ScenarioExample
Shared networkingHub VNet, ExpressRoute, Firewall costs split across spokes
Platform servicesShared AKS cluster costs distributed by namespace usage
Security servicesMicrosoft Defender for Cloud costs shared across subscriptions
Management overheadLog Analytics workspace costs split by ingestion volume
License poolsShared SQL elastic pool costs split by DTU consumption

How to Configure Cost Allocation Rules

  1. Navigate to Azure Portal > Cost Management > Settings > Cost allocation (preview)
  2. Click + Add to create a new rule
  3. Define the source (shared cost to split) using subscription, resource group, or tag
  4. Define the targets (who receives the allocation) using subscription, resource group, or tag
  5. Choose the allocation method:
    • Proportional — distribute based on actual cost of targets
    • Even distribution — split equally among targets
    • Fixed percentage — manually set percentages per target
  6. Set the effective date (rules apply from the start of the month)

Cost Allocation Behavior

AspectDetail
Processing timeRules take up to 24 hours to reflect in Cost Analysis
RetroactiveRules can be applied retroactively to the start of the current month
ScopeAvailable at EA enrollment, MCA billing profile, and MPA partner scopes
LimitsUp to 50 rules per billing account
VisibilityAllocated costs appear as separate line items in Cost Analysis

Microsoft Learn: Create and manage cost allocation rules


2.8 Implementing Showback & Chargeback

Showback vs Chargeback

ApproachDescriptionBest ForComplexity
ShowbackDisplay costs to teams without billing themBuilding awareness, early-stage FinOpsLow
ChargebackBill costs back to business units via journal entriesMature organizations with cost centersHigh
HybridShowback for shared resources, chargeback for dedicatedMost enterprisesMedium

Step-by-Step: Showback/Chargeback with Power BI

Step 1: Configure Scheduled Cost Exports

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

Step 2: Connect Power BI to Azure Cost Management

  1. Open Power BI Desktop
  2. Get Data > Azure > Azure Cost Management
  3. Authenticate with your Azure credentials
  4. Select the billing scope (EA enrollment or MCA billing profile)
  5. Choose Amortized cost for reservation/savings plan distribution
  6. Set the date range

Microsoft Learn: Connect to Azure Cost Management data in Power BI Desktop

Step 3: Build Showback Reports

Create Power BI visuals using these recommended dimensions:

Visual TypeDimensionMetricPurpose
Bar chartCostCenter tagSum of CostInBillingCurrencyCost per cost center
TreemapBusinessUnit tagSum of CostInBillingCurrencyProportional spend
Line chartDate (daily)Sum of CostInBillingCurrencyTrend over time
TableResourceGroup, ServiceNameSum of CostInBillingCurrencyDetailed drill-down
KPI cardN/AMonth-over-month changeExecutive summary

Step 4: Automate Distribution

  • Schedule Power BI dataset refresh (daily or weekly)
  • Configure Power BI email subscriptions for stakeholders
  • Use Power BI workspaces to segment access by business unit
  • Optionally embed reports in Microsoft Teams channels

Step 5: Chargeback Integration (Advanced)

For true chargeback, integrate cost data with financial systems:

  1. Export cost data grouped by CostCenter tag to CSV/Parquet
  2. Map CostCenter values to GL (General Ledger) codes
  3. Generate journal entries for your ERP system (SAP, Oracle, etc.)
  4. Post entries monthly using your ERP's batch import API
  5. Reconcile Azure invoices with posted journal entries

Microsoft Learn: Tutorial: Create and manage exported data


2.9 Azure Cost Management Features for Transparency

FeatureWhat It DoesHow to AccessLearn More
Cost AnalysisInteractive cost explorer with filters, grouping, pivotsPortal > Cost Management > Cost AnalysisLink
Cost AlertsEmail notifications at budget thresholdsPortal > Cost Management > Cost AlertsLink
Anomaly DetectionML-powered detection of unexpected spend changesAutomatically enabled in Cost AnalysisLink
Cost ExportsScheduled CSV/Parquet exports to Storage AccountPortal > Cost Management > ExportsLink
FOCUS DatasetStandardized cost/usage format across cloud providersAvailable in Cost ExportsLink
Cost AllocationRedistribute shared costs to business unitsPortal > Cost Management > Cost allocationLink
Smart ViewsSaved and shared cost analysis viewsPortal > Cost Management > ViewsLink
Copilot in Cost MgmtNatural language cost queries powered by AIPortal > Cost Management (Copilot icon)Link

2.10 Best Practices for Cost Transparency

Implementation Checklist

#PracticePriorityStatus
1Define a tag dictionary with mandatory and optional tagsP0
2Deploy audit policies first to assess current complianceP0
3Enable tag inheritance from resource group to resourcesP0
4Use modify policies to auto-remediate untagged resourcesP1
5Run Resource Graph queries weekly to track tag complianceP1
6Configure cost exports (daily, amortized, FOCUS format)P1
7Build Power BI showback dashboards by business unitP1
8Set up cost allocation rules for shared infrastructureP2
9Deploy deny policies once compliance exceeds 90%P2
10Integrate chargeback with ERP/financial systemsP2
11Review FOCUS exports for multi-cloud cost normalizationP3
12Automate tag compliance reporting via Logic Apps or FunctionsP3

Common Pitfalls to Avoid

PitfallWhy It's a ProblemSolution
Enforcing Deny without Audit firstBlocks deployments, frustrates teamsFollow the Audit > Modify > Deny progression
Inconsistent tag naming (CostCenter vs costcenter)Breaks filtering and allocationEnforce PascalCase via a published tag dictionary
Not tagging resource groupsTags don't flow down to child resourcesUse tag inheritance policies
Relying only on tags for shared costsShared resources can't be directly tagged to single ownersUse Cost Allocation Rules
Manual tag applicationTags drift quickly, humans forgetAutomate with Azure Policy Modify effect
Not using amortized cost viewReservations appear as lump-sum purchasesAlways use amortized view for showback
Ignoring FOCUS formatLock-in to Azure-specific column namesExport in FOCUS format for portability

References


Previous Module: Module 1 — Cost Optimization Fundamentals
Next Module: Module 3 — Financial Controls & Budgets
Back to Overview: README — Cost Optimization

📖Learn