Azure Policy allows you to create, assign, and manage policies in Azure (that definition feels a little like one of those awful definitions in Merriam Webster, right?). These policies enforce different rules over deployed resources, ensuring those resources stay compliant and adhere to corporate standards + service level agreements. IMO, Azure Policy often plays the part of the unsung hero in the governance toolkit for Azure customers. If you combine Azure Policy with Azure Tags, you start to see some really strong capabilities related to managing, organizing, and governing Azure resources. Azure Tags are key-value pairs that you can attach to Azure resources. They are used for organizing resources, managing costs, and enforcing governance across your Azure environment. In a cloud-first world, maintaining consistency and compliance across your resources is crucial.
How Azure Policy Works with Tags
Azure Policy can enforce tagging rules and conventions. By creating a policy, you can prevent the deployment of resources that don’t have the expected tags for your organization. I talk to customers most commonly about this very topic (hence the blog post). Making use of Azure Policy in this instance helps you build the right cost visibility and reporting so you can tackle FinOps most effectively for your organization. I can't tell you how many customers have the following keys in their key-value pair configuration: "Application", "application", "app", "Appilcation", etc. If there's one thing I can impart you with, it's that Azure (similar to other hyperscalers) see those as different keys, which makes tracking cost a bit trickier. Using Azure Policy in this manner ensures all resources are tagged according to the predefined design and taxonomy.
Example Policy for Azure Tag Enforcement
Here’s an example of a policy definition that enforces the presence of an AppId tag on all resource groups. Without the AppId tag, the deployment fails. Pretty handy, aye?
{
"if": {
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
"then": {
"effect": "deny",
"details": {
"type": "Required",
"existenceCondition": {
"field": "tags['AppId']",
"exists": true
}
}
}
}
I've worked with customers who were fearful of configuring Azure Policy this way, due to internal political backlash. These customers started with a people/process policy vs. technical enforcement. When no one added in the right tags and a few months passed post the people/process policy creation, they looked toward technical enforcement to bring about best practice configuration for their Azure resources. Cost containment is paramount and visibility into that spend becomes the most critical aspect in any customer's FinOps maturity journey.
Implementing Tag Inheritance
Azure Policy’s Modify effect can be used to inherit tags from parent resources. The Modify effect becomes invaluable for anyone who needs to quickly fix inconsistent tags or tag a LOT of resources in a fast fashion. For example, you can create a policy that automatically applies a tag from a resource group to all its resources:
{
"mode": "All",
"policyRule": {
"if": {
"field": "type",
"in": [
"Microsoft.Compute/virtualMachines",
"Microsoft.Storage/storageAccounts"
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/roleDefinitionId"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['AppId']",
"value": "[resourceGroup().tags['AppId']]"
}
]
}
}
}
}
I've found this most helpful in really large environments, as it makes configuring tags easier at scale!
By integrating Azure Policy with Azure Tags, you can automate the enforcement of tagging rules, ensuring resources are always in line with design and governance requirements. This not only simplifies management, but it also enhances security and compliance across your Azure environment.
Taking it One Step Farther: Logical Operators
From there, Logical Operators in Azure Policy allow for more precise control over resource configurations, ensuring only resources that meet specific criteria are deployed or are affected by policies. Logical operators are the building blocks of Azure Policy rules. They dictate how different conditions within a policy rule are evaluated together. The primary logical operators used in Azure Policy are not, allOf, and anyOf:
not: This operator negates the result of a single condition or another logical operator.
allOf: This requires all the nested conditions or operators to evaluate to true for the overall condition to be considered true.
anyOf: This requires at least one of the nested conditions or operators to be true for the overall condition to be true.
These operators can be nested within each other to create more complex policy definitions. The importance of conditional matching is something I think consumers of Azure forget about. Why does it matter though? Well, it enables granular control over the deployment of resources, making certain that everything deployed complies with established corporate standards.
Let's consider a scenario where you want to audit all Azure Cosmos DB accounts to ensure they have automatic failovers and multiple write locations configured. The policy definition might look something like this:
{
"properties": {
"mode": "all",
"displayName": "Audit Automatic Failover for CosmosDB accounts",
"description": "This policy audits Automatic Failover for CosmosDB accounts",
"policyRule": {
"if": {
"allOf": [{
"field": "type",
"equals": "Microsoft.DocumentDB/databaseAccounts"},
{
"field": "Microsoft.DocumentDB/databaseAccounts/enableAutomaticFailover",
"equals": "false"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/enableMultipleWriteLocations",
"equals": "false"
}
]
},
"then": {
"effect": "audit"
}
}
}
}
In this example, the allOf operator is used to specify that all conditions must be true for the policy to take effect. If any of the conditions are not met, the policy will not trigger. Additionally, this policy is just auditing...it's not affecting any change in the environment.
Another example could involve combining not and allOf. In the example below, the allOf operator is combined with not to deny resources that do not match certain naming patterns. The not operator negates the condition, so if the resource name does not match the patterns specifice (and note this is NOT RegEx), the policy will deny the creation or an update of the resource:
{
"properties": {
"displayName": "Match multiple name patterns.",
"description": "Allows one of multiple naming patterns for resources.",
"mode": "Indexed",
"policyRule": {
"if": {
"allOf": [{
"not": {
"field": "name",
"match": "shannon-$$"
}
},
{
"not": {
"field": "name",
"match": "shannon-##"
}
}
]
},
"then": {
"effect": "deny"
}
}
}
}
Here, the allOf operator is combined with the not logical operator to deny resources that do not follow the specified naming conventions.
These examples demonstrate how Azure Policy's conditional matching provides the tools necessary to implement and enforce governance across your Azure environments effectively. By making use of these capabilities, organizations can automate compliance, streamline operations, and secure cloud resources against misconfigurations and non-compliance.
Embracing Azure Policy and its conditional matching features is not just about compliance; it's about really embracing a culture of security and excellence, ensuring that every resource deployed in the cloud contributes to the organization's objectives and standards. It's a step towards a more secure, efficient, and compliant cloud environment.
Take a read through further documentation if you're curious and would like to explore:
Tutorial: Manage tag governance - Azure Policy | Microsoft Learn Create An Azure Policy To Enforce Resource Tags (techpress.net)
Enforcing Mandatory Tags Across Your Azure Resources - Blink (blinkops.com) Enforce Tags On Microsoft Azure Cloud Resources Using Policies | by Sumit | Medium
Stay tuned! More is on the way!
Comments