give me examples of business, technical and operational requirements for setting up basic finops capabiliry in a greenfield Azure implementation
We need to provide examples of business, technical, and operational requirements for setting up a basic FinOps capability in a greenfield Azure implementation. The context is a new Azure environment with no existing cloud usage. FinOps (Cloud Financial Management) aims to manage and optimize cloud costs. So we need to define what requirements would be needed to establish a basic FinOps practice. We should categorize them into business, technical, and operational requirements.
- Business requirements: High-level goals from business perspective, like cost visibility, budgeting, accountability, etc.
- Technical requirements: Specific Azure services, tools, configurations needed to enable cost management, tagging, monitoring, etc.
- Operational requirements: Processes, roles, workflows for ongoing cost management, optimization, reporting.
Let’s outline examples for each.
We can think of a basic FinOps capability as including:
- Cost allocation (tagging, resource organization)
- Budgeting and alerts
- Cost reporting and visualization
- Optimization (right-sizing, reserved instances, etc.)
- Governance and policies
We need to be specific to Azure: Azure Cost Management, Azure Policy, Azure budgets, Azure Advisor, Azure Resource Graph, tagging, management groups, subscriptions, etc.
We should also consider that it’s greenfield, so we have opportunity to set things up correctly from start.
We’ll provide a list of examples for each category.
Here are examples of business, technical, and operational requirements to establish a basic FinOps capability in a new (greenfield) Azure implementation.
Business Requirements
These define the goals and value expectations from a financial management perspective.
# | Requirement | Description |
1 | Cost Visibility | Provide business stakeholders with clear, timely visibility into Azure spending, broken down by department, project, or application. |
2 | Budgetary Control | Establish monthly/quarterly budgets for each cost center and receive alerts when spending approaches or exceeds thresholds. |
3 | Showback/Chargeback | Enable allocation of cloud costs to the appropriate internal teams or customers for accountability and financial transparency. |
4 | Forecasting Accuracy | Maintain a process to forecast future cloud spend based on historical trends and planned changes, with variance reporting. |
5 | Optimization Targets | Set periodic goals for reducing waste (e.g., idle resources, oversized services) and increasing usage of committed use discounts. |
6 | Governance Alignment | Ensure cloud spending aligns with corporate financial policies, procurement rules, and compliance requirements. |
7 | Cross‑functional Collaboration | Foster collaboration between finance, engineering, and operations to balance cost, performance, and innovation. |
Technical Requirements
These specify the Azure services, configurations, and tools needed to enable cost management.
# | Requirement | Description |
1 | Resource Hierarchy | Design an Azure management group and subscription structure that mirrors the organization (e.g., by business unit, environment, application) to enable logical cost aggregation. |
2 | Tagging Strategy | Define and enforce a mandatory set of resource tags (e.g., CostCenter, Owner, Environment, Project) to allow cost allocation and filtering in reports. |
3 | Azure Policy for Tags | Implement Azure Policy rules that require specific tags at resource creation and optionally inherit missing tags from resource groups. |
4 | Cost Management + Billing | Enable and configure Azure Cost Management, including access to billing data, cost views, and budgets for all subscriptions. |
5 | Budgets and Alerts | Create budgets at management group, subscription, or resource group scope with email and action group alerts for threshold breaches. |
6 | Advisor Integration | Enable Azure Advisor to generate cost recommendations (e.g., right‑sizing, reserved instance purchases) and integrate them into regular reviews. |
7 | Workbook/Dashboard | Build custom Azure workbooks or dashboards in Azure Monitor that display key FinOps metrics (spend by tag, forecast, top resources) for different audiences. |
8 | Reserved Instance Planning | Configure Azure to provide reserved instance recommendations and track coverage percentage. |
9 | Access Control | Use Azure RBAC to grant appropriate permissions (e.g., Cost Management Reader) to finance and engineering teams without giving full billing access. |
10 | Automated Remediation | (Optional) Set up automation (e.g., Azure Functions, Logic Apps) to stop or deallocate underutilized resources based on tags or schedules. |
Operational Requirements
These define the people, processes, and workflows to sustain and mature the FinOps practice.
# | Requirement | Description |
1 | FinOps Roles & Responsibilities | Assign a cloud financial manager (or center of excellence) and designate cost owners for each business unit / application. |
2 | Cost Review Cadence | Hold recurring (e.g., weekly or bi‑weekly) cost reviews with engineers and finance to analyze anomalies, discuss optimization, and track progress. |
3 | Tagging Governance | Establish a process to validate tag compliance regularly and remediate untagged or incorrectly tagged resources. |
4 | Budget Management Workflow | Define how new budgets are requested, approved, and updated; link budget changes to project planning. |
5 | Optimization Lifecycle | Create a process to: |
6 | Anomaly Detection Process | Set up procedures to investigate unexpected cost spikes – including root cause analysis and corrective action documentation. |
7 | Reserved Instance Strategy | Establish a quarterly review of RI/ savings plan coverage, purchase approvals, and commitment alignment with projected usage. |
8 | Reporting & Communication | Publish a monthly FinOps report to stakeholders summarizing spend vs. budget, savings achieved, and forecasts. |
9 | Training & Enablement | Provide basic FinOps and Azure cost management training to engineers, emphasising cost‑aware design and tagging discipline. |
10 | Tooling Evolution | Periodically assess whether native Azure tools suffice or if third‑party FinOps platforms are needed as the environment grows. |
These requirements can be adapted based on the organization’s size, culture, and maturity goals. Starting with a greenfield Azure environment allows these FinOps fundamentals to be embedded from day one, preventing costly waste and ensuring financial accountability scales with the cloud footprint.
Hmm, the user is asking for a practical implementation guide to enforce specific mandatory tags (Cost Centre, Environment, Owber, ApplicationID) with allowed values using Azure Policy for FinOps purposes. The question appears technical and implementation-focused, likely from a cloud architect, FinOps practitioner, or Azure administrator setting up governance.
I’ll structure my answer to cover both the Azure Policy implementation approach and how it fits into the broader FinOps framework. The response should include actual policy code, best practices for enforcement, and considerations for rollout.
Looking at the search results, I find several highly relevant sources. The Microsoft FinOps Toolkit documentation provides excellent guidance on cloud policy and governance as part of the FinOps Framework, emphasizing the importance of tagging for allocation, chargeback, and workload management. Another Microsoft Learn article reinforces these concepts with similar authoritative weight.
For the actual policy implementation, a Microsoft Q&A thread contains a working policy definition that enforces a tag with predefined allowed values, using the in operator with an array parameter. This is directly applicable to the user’s requirement. A community hub post shows PowerShell automation for FinOps tagging enforcement, demonstrating practical deployment methods.
The KodeKloud notes provide an excellent tutorial on grouping multiple tagging policies into an initiative, which is exactly what the user needs for managing four tags together. The step-by-step approach for assignment and testing is valuable.
Some search results are less useful. The Infracost glossary provides general information but lacks the specific implementation details needed. The Valorem Reply blog discusses tagging concepts but focuses more on cost reporting architecture than policy enforcement.
I’ll recommend the initiative approach since managing four separate policies would be cumbersome. The policy rule structure from can be adapted with multiple allOf conditions. For allowed values, I’ll suggest parameterizing them for flexibility. I’ll also include PowerShell automation from and guidance on using deny versus audit effects from . The rollout strategy of starting with audit before enforce is sound advice.
The response will combine the authoritative Microsoft sources for FinOps context with practical implementation examples to give the user a complete solution from strategy to code to deployment.
Enforcing a tagging strategy with allowed values is a foundational step in any FinOps practice, enabling accurate cost allocation and showback/chargeback models . To enforce your specific tags—Cost Centre, Environment, Owner, and ApplicationID—you have two primary approaches: creating individual policies or a single, combined initiative.
For ease of management and to ensure consistent enforcement, it is best practice to group these related tags into a single Policy Initiative (also known as a Policy Set) . This allows you to assign one package to your management group or subscription rather than managing four separate assignments.
Here is the JSON code for a custom Azure Policy Initiative that enforces these four tags with their respective allowed values.
Azure Policy Initiative: Enforce FinOps Mandatory Tags
This initiative combines four individual policy definitions. Each policy rule checks for the existence of a specific tag and validates its value against a predefined list. If a resource is missing a required tag or has a non-approved value, the deployment is blocked ("effect": "deny") .
{ "properties": { "displayName": "FinOps Enforce Mandatory Tags with Allowed Values", "policyType": "Custom", "description": "Policy initiative to enforce the mandatory tags: Cost Centre, Environment, Owner, and ApplicationID with their allowed values for FinOps cost tracking.", "metadata": { "version": "1.0.0", "category": "Tags" }, "parameters": { "costCentreAllowedValues": { "type": "Array", "metadata": { "displayName": "Allowed values for Cost Centre", "description": "List of allowed Cost Centre codes, e.g., Marketing, R&D, Sales." }, "allowedValues": [ "Marketing", "R&D", "Sales", "IT", "Finance" ] }, "environmentAllowedValues": { "type": "Array", "metadata": { "displayName": "Allowed values for Environment", "description": "List of allowed Environment types, e.g., Prod, Dev, Test." }, "allowedValues": [ "Prod", "Dev", "Test", "UAT", "DR" ] }, "ownerAllowedValues": { "type": "Array", "metadata": { "displayName": "Allowed values for Owner", "description": "List of allowed Owner team names or email aliases." }, "allowedValues": [ "TeamAlpha", "TeamBeta", "PlatformTeam", "DataTeam" ] }, "applicationIdAllowedValues": { "type": "Array", "metadata": { "displayName": "Allowed values for ApplicationID", "description": "List of allowed Application IDs." }, "allowedValues": [ "ERP-SAP", "CRM-Dynamics", "Web-App", "Data-Lake" ] } }, "policyDefinitions": [ { "policyDefinitionReferenceId": "EnforceCostCentreTag", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/your-policy-definition-id-for-tag-enforcement", "parameters": { "tagName": { "value": "Cost Centre" }, "allowedTagValues": { "value": "[parameters('costCentreAllowedValues')]" } }, "groupNames": [] }, { "policyDefinitionReferenceId": "EnforceEnvironmentTag", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/your-policy-definition-id-for-tag-enforcement", "parameters": { "tagName": { "value": "Environment" }, "allowedTagValues": { "value": "[parameters('environmentAllowedValues')]" } }, "groupNames": [] }, { "policyDefinitionReferenceId": "EnforceOwnerTag", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/your-policy-definition-id-for-tag-enforcement", "parameters": { "tagName": { "value": "Owner" }, "allowedTagValues": { "value": "[parameters('ownerAllowedValues')]" } }, "groupNames": [] }, { "policyDefinitionReferenceId": "EnforceApplicationIDTag", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/your-policy-definition-id-for-tag-enforcement", "parameters": { "tagName": { "value": "ApplicationID" }, "allowedTagValues": { "value": "[parameters('applicationIdAllowedValues')]" } }, "groupNames": [] } ] } }
Note: You will need to replace "/providers/Microsoft.Authorization/policyDefinitions/your-policy-definition-id-for-tag-enforcement" with the actual Resource ID of a core “Require tag and its value” policy. You can use a built-in one or the custom definition shown below.
Underlying Policy Definition: Require Tag and Its Value
The initiative above references a standard policy definition. If you don’t have one, here is the custom JSON for the underlying policy that performs the actual check and denial .
{ "properties": { "displayName": "Require a specific tag and its value on resources", "policyType": "Custom", "mode": "Indexed", "description": "Enforces a required tag and its value. Does not apply to resource groups.", "metadata": { "version": "1.0.0", "category": "Tags" }, "parameters": { "tagName": { "type": "String", "metadata": { "displayName": "Tag Name", "description": "Name of the tag, such as 'Cost Centre'." } }, "allowedTagValues": { "type": "Array", "metadata": { "displayName": "Allowed Tag Values", "description": "The list of allowed values for the tag." } } }, "policyRule": { "if": { "not": { "field": "[concat('tags[', parameters('tagName'), ']')]", "in": "[parameters('allowedTagValues')]" } }, "then": { "effect": "deny" } } } }
Implementation and FinOps Best Practices
Once you have defined your Initiative, you need to assign it to the desired scope (e.g., a Management Group or Subscription) and integrate it into your FinOps workflow.
Define Allowed Values via Parameters: When assigning the initiative, you will be prompted to fill in the parameters. This is where you define the specific
allowedValuesfor your organization, such as your specific Cost Centre codes or Environment types. Using parameters makes the policy reusable across different departments or subscriptions without editing the core JSON .Start with Audit Before Deny: To avoid disrupting existing workflows, it is highly recommended to start with an Audit effect. This will report on non-compliant resources without blocking them. Once you are confident in your tagging strategy and have communicated with your teams, you can switch the effect to Deny by modifying the underlying policy definition .
Combine with Inheritance Policies: For a more robust FinOps implementation, consider adding another policy to your initiative that inherits tags from the resource group to the resources within it. This reduces the burden on developers and ensures that all resources created in a properly tagged resource group are automatically compliant .
Automate Deployment: Deploy your policy initiative using Infrastructure as Code (IaC) tools like Bicep, ARM templates, or Terraform, and integrate it into your CI/CD pipelines (e.g., using Azure DevOps or GitHub Actions) .
Summary of Tags for FinOps
| Tag Name | FinOps Purpose | Example Allowed Values |
|---|---|---|
| Cost Centre | Allocates costs to the correct department or business unit for chargeback/showback . | Marketing, R&D, IT, Finance |
| Environment | Identifies the workload stage for cost optimization (e.g., turning off non-prod resources) . | Prod, Dev, Test, UAT, DR |
| Owner | Identifies the team or individual responsible for the resource for cost investigation and anomaly alerts . | TeamAlpha, TeamBeta, PlatformTeam |
| ApplicationID | Groups resources belonging to a specific application for granular cost analysis and reporting . | ERP-SAP, CRM-Dynamics, Web-App |
We need to provide Bicep code to enforce Azure mandatory tags (Cost Centre, Environment, Owner, ApplicationID) with allowed values, as part of a FinOps policy implementation. The user wants Bicep instead of JSON. We should provide Bicep modules or resources that define custom policy definitions and a policy initiative (set). The Bicep should be deployable.
We’ll structure the answer:
Explanation of approach: using Bicep to create custom policy definitions and a policy set definition (initiative). Include parameters for allowed values.
Provide Bicep code:
Define a reusable policy definition for “require tag and allowed values” (like the JSON earlier) as a Bicep module or resource.
Then define the policy set (initiative) that includes four instances of that definition, each with parameters for tag name and allowed values.
The allowed values can be passed as parameters to the Bicep deployment.
Show assignment if needed, but maybe just the definition.
Mention deployment commands and considerations.
We need to ensure the Bicep is correct: using Microsoft.Authorization/policyDefinitions and Microsoft.Authorization/policySetDefinitions.
We’ll also include metadata, parameters, and policy rule.
Let’s craft the Bicep.
We might need to handle the policy definition ID reference in the initiative. In Bicep, we can use existing or reference the resource by symbolic name. We’ll create the policy definition resource and then reference it in the policy set using its id. We’ll have to use resource declarations.
Plan:
param for allowed values for each tag (arrays).
resource for policyDefinition: e.g.,
requireTagAndValuePolicyof typeMicrosoft.Authorization/policyDefinitions.resource for policySetDefinition: type
Microsoft.Authorization/policySetDefinitions, withpolicyDefinitionsproperty containing an array of objects referencing the policy definition ID and parameters.
We need to ensure the policy definition ID is correctly formed: usually subscription(/subscriptions/{subscriptionId})/providers/Microsoft.Authorization/policyDefinitions/{name}. In Bicep, we can use requireTagAndValuePolicy.id.
We’ll also handle the policy rule expression with concat and field.
We’ll output the policy set definition ID if needed.
Let’s write the Bicep.
We might also provide an example of assignment, but the user asked to “enforce” which likely means creating the definition and initiative, then they can assign. We’ll show the initiative creation.
We should also mention that they need to deploy to a subscription or management group. Probably subscription scope.
Let’s write the code.
Below is a Bicep template that creates a custom Azure Policy Initiative (set) to enforce your mandatory tags Cost Centre, Environment, Owner, and ApplicationID with allowed values. The template defines:
One reusable policy definition for enforcing a tag with allowed values.
A policy set definition that references this policy four times, once per tag, with tag‑specific allowed values passed as parameters.
You can deploy this Bicep file to a subscription (or management group) to establish the foundation for your FinOps tagging governance.
// Parameters: Allowed values for each mandatory tag @description('List of allowed values for Cost Centre tag, e.g. [ "Marketing", "R&D", "Sales", "IT", "Finance" ]') param costCentreAllowedValues array @description('List of allowed values for Environment tag, e.g. [ "Prod", "Dev", "Test", "UAT", "DR" ]') param environmentAllowedValues array @description('List of allowed values for Owner tag, e.g. [ "TeamAlpha", "TeamBeta", "PlatformTeam", "DataTeam" ]') param ownerAllowedValues array @description('List of allowed values for ApplicationID tag, e.g. [ "ERP-SAP", "CRM-Dynamics", "Web-App", "Data-Lake" ]') param applicationIdAllowedValues array // Custom policy definition: Require a specific tag and its value resource requireTagAndValuePolicy 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { name: 'require-tag-and-value' properties: { displayName: 'Require a specific tag and its value on resources' policyType: 'Custom' mode: 'Indexed' // Evaluates resource types that support tags description: 'Denies creation or update of a resource if it does not have the specified tag with a value from the allowed list.' metadata: { version: '1.0.0' category: 'Tags' } parameters: { tagName: { type: 'String' metadata: { displayName: 'Tag Name' description: 'Name of the tag, such as Cost Centre' } } allowedTagValues: { type: 'Array' metadata: { displayName: 'Allowed Tag Values' description: 'List of allowed values for the tag' } } } policyRule: { if: { not: { field: '[concat(\'tags[\', parameters(\'tagName\'), \']\')]' in: '[parameters(\'allowedTagValues\')]' } } then: { effect: 'deny' } } } } // Policy set (initiative) that includes the four mandatory tags resource finOpsTagInitiative 'Microsoft.Authorization/policySetDefinitions@2021-06-01' = { name: 'finops-enforce-mandatory-tags' properties: { displayName: 'FinOps Enforce Mandatory Tags with Allowed Values' description: 'Enforces the presence and allowed values of Cost Centre, Environment, Owner, and ApplicationID tags.' policyType: 'Custom' metadata: { version: '1.0.0' category: 'Tags' } parameters: { costCentreAllowedValues: { type: 'Array' metadata: { displayName: 'Allowed values for Cost Centre' description: 'List of allowed Cost Centre codes' } } environmentAllowedValues: { type: 'Array' metadata: { displayName: 'Allowed values for Environment' description: 'List of allowed Environment types' } } ownerAllowedValues: { type: 'Array' metadata: { displayName: 'Allowed values for Owner' description: 'List of allowed Owner team names' } } applicationIdAllowedValues: { type: 'Array' metadata: { displayName: 'Allowed values for ApplicationID' description: 'List of allowed Application IDs' } } } policyDefinitions: [ { policyDefinitionId: requireTagAndValuePolicy.id parameters: { tagName: { value: 'Cost Centre' } allowedTagValues: { value: '[parameters(\'costCentreAllowedValues\')]' } } } { policyDefinitionId: requireTagAndValuePolicy.id parameters: { tagName: { value: 'Environment' } allowedTagValues: { value: '[parameters(\'environmentAllowedValues\')]' } } } { policyDefinitionId: requireTagAndValuePolicy.id parameters: { tagName: { value: 'Owner' } allowedTagValues: { value: '[parameters(\'ownerAllowedValues\')]' } } } { policyDefinitionId: requireTagAndValuePolicy.id parameters: { tagName: { value: 'ApplicationID' } allowedTagValues: { value: '[parameters(\'applicationIdAllowedValues\')]' } } } ] } }
Deployment Instructions
Save the code to a file, e.g.,
finops-tag-policy.bicep.Prepare a parameters file (optional) or pass values directly. Example parameters file (
finops-tag-policy.parameters.json):json{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "costCentreAllowedValues": { "value": [ "Marketing", "R&D", "Sales", "IT", "Finance" ] }, "environmentAllowedValues": { "value": [ "Prod", "Dev", "Test", "UAT", "DR" ] }, "ownerAllowedValues": { "value": [ "TeamAlpha", "TeamBeta", "PlatformTeam", "DataTeam" ] }, "applicationIdAllowedValues": { "value": [ "ERP-SAP", "CRM-Dynamics", "Web-App", "Data-Lake" ] } } }
Deploy to a subscription (or management group) using Azure CLI or PowerShell:
Azure CLI (subscription scope):
bashaz deployment sub create \ --name enforceFinOpsTags \ --location westus \ --template-file finops-tag-policy.bicep \ --parameters @finops-tag-policy.parameters.json
PowerShell:
powershellNew-AzSubscriptionDeployment ` -Name enforceFinOpsTags ` -Location westus ` -TemplateFile finops-tag-policy.bicep ` -TemplateParameterFile finops-tag-policy.parameters.json
For management group scope, use
az deployment mg createorNew-AzManagementGroupDeploymentand adjust the scope.
Next Steps
Assign the Initiative – After deployment, navigate to Azure Policy, find the initiative named FinOps Enforce Mandatory Tags with Allowed Values, and assign it to the desired scope (management group, subscription, or resource group). During assignment, you can again specify the allowed values (they will default to the ones provided during definition).
Consider audit‑first – If you are unsure about the impact, modify the underlying policy definition’s effect from
denytoauditbefore deploying. You can do this by changing thethen.effectinrequireTagAndValuePolicyto'audit'. After confirming no unexpected non‑compliant resources, change it back todeny.Combine with inheritance – To reduce manual tagging effort, add another policy that copies tags from the resource group to resources. This can be added as an extra definition inside the same initiative.
This Bicep template gives you a reusable, code‑first approach to enforce your FinOps tagging strategy consistently across your Azure environment.
We need to show how tags can be inherited from resource groups, complementing the previous enforcement policies. The user wants to see examples of inheritance, likely as part of the FinOps tagging strategy. We should provide Bicep code that adds a policy to inherit tags from the resource group. This can be a separate policy definition within the same initiative or a separate initiative.
We’ll explain the concept: using a policy with “modify” effect to add tags from the resource group to resources that are missing them. But careful: inheritance can be done with “modify” or “deployIfNotExists”. For tags, a common built-in policy is “Inherit a tag from the resource group” which uses modify effect to add the tag if missing. We can either reference the built-in definition or create a custom one.
The user wants to see examples, so we’ll provide Bicep code for adding such a policy to the initiative. Since the previous Bicep already defined an initiative, we can extend it to include a policy for tag inheritance.
We need to show how tags can be inherited from resource groups. We’ll create a separate policy definition for inheritance (or use built-in) and add it to the initiative. We’ll also discuss parameters for tag name.
We’ll provide an updated Bicep that includes the inheritance policy. But the user might want just an example, not necessarily merging with previous. We can show both.
We’ll also mention that inheritance can be used to reduce manual tagging effort, ensuring that resources automatically get the resource group’s tags. This is common in FinOps to ensure consistent tagging without burdening developers.
Let’s structure the response:
Introduction: Tag inheritance helps propagate tags from resource groups to resources.
Show a policy definition for inheritance (modify effect).
Show how to add it to the initiative (or as a separate assignment).
Provide Bicep code snippet.
Explain parameters and usage.
Mention caution: inheritance policies typically only add tags if missing, not overwrite existing ones.
Combine with enforcement policies to ensure all resources have required tags.
We’ll keep it concise but informative.
To complement the enforcement of mandatory tags, you can implement tag inheritance from resource groups. This ensures that any resource created in a properly tagged resource group automatically receives the required tags, reducing manual effort and preventing compliance gaps.
Below is a Bicep example that adds a tag‑inheritance policy to the previously created initiative. The policy uses the modify effect to copy a specified tag from the resource group to the resource if the resource does not already have that tag.
Updated Bicep Initiative with Tag Inheritance
This Bicep template extends the earlier initiative by including a built‑in policy definition for tag inheritance. The built‑in policy ID is:
/providers/Microsoft.Authorization/policyDefinitions/cd3aa116-8754-49c9-a813-ad46512ece54
If you prefer to define a custom inheritance policy, an example is also provided.
// Parameters (same as before) param costCentreAllowedValues array param environmentAllowedValues array param ownerAllowedValues array param applicationIdAllowedValues array // Optional: parameter to specify which tag to inherit (if using a custom inheritance policy) param inheritTagName string = 'Environment' // Example: inherit Environment tag // Reference to the built‑in policy for inheriting a tag from the resource group resource builtInInheritTagPolicy 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { name: 'cd3aa116-8754-49c9-a813-ad46512ece54' } // Custom policy definition: Require a specific tag and its value (same as before) resource requireTagAndValuePolicy 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { name: 'require-tag-and-value' properties: { displayName: 'Require a specific tag and its value on resources' policyType: 'Custom' mode: 'Indexed' description: 'Denies creation or update of a resource if it does not have the specified tag with a value from the allowed list.' metadata: { version: '1.0.0', category: 'Tags' } parameters: { tagName: { type: 'String', metadata: { displayName: 'Tag Name' } } allowedTagValues: { type: 'Array', metadata: { displayName: 'Allowed Tag Values' } } } policyRule: { if: { not: { field: '[concat(\'tags[\', parameters(\'tagName\'), \']\')]', in: '[parameters(\'allowedTagValues\')]' } } then: { effect: 'deny' } } } } // Policy set (initiative) with both enforcement and inheritance resource finOpsTagInitiative 'Microsoft.Authorization/policySetDefinitions@2021-06-01' = { name: 'finops-enforce-mandatory-tags' properties: { displayName: 'FinOps Enforce Mandatory Tags with Allowed Values' description: 'Enforces mandatory tags (Cost Centre, Environment, Owner, ApplicationID) and inherits a tag from the resource group.' policyType: 'Custom' metadata: { version: '1.0.0', category: 'Tags' } parameters: { costCentreAllowedValues: { type: 'Array', metadata: { displayName: 'Allowed values for Cost Centre' } } environmentAllowedValues: { type: 'Array', metadata: { displayName: 'Allowed values for Environment' } } ownerAllowedValues: { type: 'Array', metadata: { displayName: 'Allowed values for Owner' } } applicationIdAllowedValues: { type: 'Array', metadata: { displayName: 'Allowed values for ApplicationID' } } } policyDefinitions: [ // Four enforcement policies (same as before) { policyDefinitionId: requireTagAndValuePolicy.id parameters: { tagName: { value: 'Cost Centre' }, allowedTagValues: { value: '[parameters(\'costCentreAllowedValues\')]' } } } { policyDefinitionId: requireTagAndValuePolicy.id parameters: { tagName: { value: 'Environment' }, allowedTagValues: { value: '[parameters(\'environmentAllowedValues\')]' } } } { policyDefinitionId: requireTagAndValuePolicy.id parameters: { tagName: { value: 'Owner' }, allowedTagValues: { value: '[parameters(\'ownerAllowedValues\')]' } } } { policyDefinitionId: requireTagAndValuePolicy.id parameters: { tagName: { value: 'ApplicationID' }, allowedTagValues: { value: '[parameters(\'applicationIdAllowedValues\')]' } } } // Add inheritance policy (using built‑in) { policyDefinitionId: builtInInheritTagPolicy.id parameters: { tagName: { value: 'Environment' } // Specify which tag to inherit } } ] } }
Custom Inheritance Policy Definition (Optional)
If you prefer to create your own inheritance policy instead of using the built‑in one, here is a custom definition with the modify effect:
resource customInheritTagPolicy 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { name: 'inherit-tag-from-resourcegroup' properties: { displayName: 'Inherit a tag from the resource group if missing' policyType: 'Custom' mode: 'Indexed' description: 'Adds the specified tag from the resource group to a resource if the resource does not have that tag.' metadata: { version: '1.0.0', category: 'Tags' } parameters: { tagName: { type: 'String' metadata: { displayName: 'Tag Name', description: 'Name of the tag to inherit, e.g. Environment' } } } policyRule: { if: { allOf: [ { field: '[concat(\'tags[\', parameters(\'tagName\'), \']\')]' exists: 'false' } { value: '[resourceGroup().tags[parameters(\'tagName\')]]' notEquals: '' } ] } then: { effect: 'modify' details: { roleDefinitionIds: [ '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor ] operations: [{ operation: 'addOrReplace' field: '[concat(\'tags[\', parameters(\'tagName\'), \']\')]' value: '[resourceGroup().tags[parameters(\'tagName\')]]' }] } } } } }
Then you would reference customInheritTagPolicy.id in the initiative instead of the built‑in ID.
How It Works
Inheritance policy – When a resource is created or updated, the policy checks if the resource lacks the specified tag. If the resource group has that tag, the policy adds it to the resource (using the
modifyeffect).Enforcement policies – After inheritance, the enforcement policies validate that the resource now has the required tag with an allowed value. If not, the creation/update is denied.
Deployment and Assignment
Deploy the Bicep template as described previously. After deployment, assign the initiative to the desired scope. During assignment, you can also override the allowed values and the inherited tag name if you parameterized it.
Benefits for FinOps
Consistency – Resources automatically receive the same tags as their resource group, reducing manual errors.
Simplified onboarding – Teams only need to tag resource groups correctly; all resources inside inherit the tags.
Cost allocation – Ensures that all resources, even those created by automated processes, have the necessary tags for accurate cost reporting.
By combining inheritance with enforcement, you build a robust tagging governance framework that supports your FinOps practices.
We need to provide guidance on auditing tag hygiene in Azure, specifically in the context of FinOps. The user has already seen policy enforcement and inheritance. Now they want to know the best way to audit tag hygiene. This involves checking existing resources for compliance with tagging standards, identifying untagged or incorrectly tagged resources, and reporting.
We should cover:
Using Azure Policy’s compliance dashboard to see which resources are non-compliant with the tag policies.
Using Azure Resource Graph (ARG) queries to get a detailed inventory of tags across resources.
Creating custom workbooks in Azure Monitor to visualize tag coverage.
Using tools like Azure Cost Management + Billing to analyze costs by tags (which requires tags to be present).
Automating audits via scripts (PowerShell, CLI) and integrating with reporting tools.
Establishing a regular cadence for audits and remediation processes.
The answer should be practical, step-by-step, and include examples (ARG queries, PowerShell). Also mention best practices: start with audit effect, set compliance thresholds, involve stakeholders.
Let’s craft a comprehensive response.
To effectively audit tag hygiene in Azure, you need a combination of continuous compliance checks and ad‑hoc inventory queries. This allows you to identify untagged or incorrectly tagged resources, measure progress, and enforce accountability. Below are the best practices and tools for auditing tags as part of your FinOps practice.
1. Use Azure Policy Compliance Dashboard (Continuous Auditing)
If you have already assigned the tag enforcement policies (even with audit effect), the Azure Policy compliance dashboard gives you a real‑time view of non‑compliant resources.
Navigate to Azure Policy > Compliance.
Select your initiative (e.g., “FinOps Enforce Mandatory Tags”).
You’ll see the compliance state per policy and per resource.
Drill down to see exactly which resources are missing tags or have non‑allowed values.
Best Practice: Start with audit effect, review compliance regularly, and only switch to deny after the majority of resources are compliant.
2. Query Azure Resource Graph (ARG) for Detailed Tag Inventory
Azure Resource Graph enables fast, complex queries across your entire Azure estate. Use it to generate reports on tag coverage.
Example ARG Queries (run in Azure Portal, CLI, or PowerShell)
a) List all resources missing a specific tag (e.g., Cost Centre)
resources | where type !~ 'microsoft.resources/subscriptions/resourcegroups' | where tags has 'Cost Centre' == false | project subscriptionId, resourceGroup, name, type, location
b) Show all resources with their tags, including missing ones
resources | where type !~ 'microsoft.resources/subscriptions/resourcegroups' | extend costCentre = tags.['Cost Centre'], environment = tags.['Environment'], owner = tags.['Owner'], applicationId = tags.['ApplicationID'] | project subscriptionId, resourceGroup, name, type, costCentre, environment, owner, applicationId | order by subscriptionId, resourceGroup
c) Count compliance by tag
resources | where type !~ 'microsoft.resources/subscriptions/resourcegroups' | summarize total = count(), missingCostCentre = countif(tags.['Cost Centre'] == ''), missingEnvironment = countif(tags.['Environment'] == ''), missingOwner = countif(tags.['Owner'] == ''), missingAppId = countif(tags.['ApplicationID'] == '')
You can run these queries in:
Azure Portal (Search for “Azure Resource Graph Explorer”)
Azure CLI:
az graph query -q "your query"PowerShell:
Search-AzGraph -Query "your query"
3. Build a Tag Compliance Workbook in Azure Monitor
Create a reusable, interactive dashboard to visualize tag hygiene metrics.
Go to Azure Monitor > Workbooks > Create a new workbook.
Add a query step using Azure Resource Graph.
Use the queries above to create tables, charts, and KPIs (e.g., percentage of resources with each tag).
Set up parameters (e.g., subscription picker) to make it dynamic.
Share the workbook with finance and operations teams.
4. Integrate with Azure Cost Management
Azure Cost Management + Billing allows you to filter and group costs by tags – but only if the tags are applied to resources and inherit to cost data.
Go to Cost Management > Cost analysis.
Add a filter by tag (e.g., “Cost Centre”) to see costs per department.
Use the Group by feature to break down costs by tag values.
If you see costs that are not allocated (i.e., untagged resources), you’ve identified a hygiene gap. You can create anomaly alerts for unexpected spending that may be linked to untagged resources.
5. Automate Regular Audits with PowerShell or CLI
For recurring audits, script the process and output to CSV or integrate with a reporting system.
PowerShell Example (using Az.ResourceGraph module)
# Install module if needed Install-Module -Name Az.ResourceGraph # Query for all resources with their tags $query = @" resources | where type !~ 'microsoft.resources/subscriptions/resourcegroups' | extend costCentre = tags.['Cost Centre'], environment = tags.['Environment'], owner = tags.['Owner'], applicationId = tags.['ApplicationID'] | project subscriptionId, resourceGroup, name, type, costCentre, environment, owner, applicationId "@ $results = Search-AzGraph -Query $query $results | Export-Csv -Path "TagAudit_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
Schedule this script (e.g., via Azure Automation, Logic Apps, or a CI/CD pipeline) to run weekly and email the report to stakeholders.
6. Remediation Strategies
Auditing alone doesn’t fix non‑compliance. Combine audits with a clear remediation process:
Automated remediation – Use Azure Policy’s
deployIfNotExistsormodifyeffects to automatically add missing tags (e.g., inherit from resource group).Manual remediation – For resources that can’t be auto‑tagged, assign owners and track tickets.
Tag governance playbook – Document who is responsible for applying tags, how to handle exceptions, and the escalation path.
7. Establish a Tag Hygiene Scorecard
Create a monthly scorecard that shows:
Percentage of resources with all mandatory tags.
Percentage of cost covered by tagged resources.
Top untagged resource types.
Trends over time.
Share this with leadership to drive accountability and celebrate improvements.
Summary: Recommended Workflow
| Step | Tool / Method | Purpose |
|---|---|---|
| 1. Baseline | ARG query + Workbook | Understand current tag coverage |
| 2. Continuous audit | Azure Policy (audit effect) | Track new non‑compliant resources |
| 3. Cost impact | Cost Management + tags | Identify untagged spending |
| 4. Regular reporting | PowerShell + CSV / Power BI | Share with stakeholders |
| 5. Remediation | Policy modify effect / manual tasks | Fix gaps |
| 6. Governance | Scorecard + playbook | Maintain hygiene |
By combining these techniques, you ensure that your Azure environment maintains the tag hygiene required for accurate FinOps cost allocation, showback, and optimization.