Azure Policy Deep Dive
Master Azure Policy definitions, initiatives, and compliance assessments for enterprise governance
What You'll Learn
- Azure Policy Definition Examples: Complete Governance Guide
- Azure Policy Initiatives Tutorial: Step-by-Step Creation Guide
- Azure Policy Compliance Assessment: Initiative Best Practices
- Azure Policy JSON Examples: Monitoring and Compliance Automation
- Azure Resource Governance Policies: Automated Remediation Guide
- Azure Policy Best Practices: DevOps Pipeline Integration
- Azure Policy Best Practices
- Troubleshooting Common Issues
- Your Achievement Summary
๐ Prerequisites
- Azure subscription with appropriate permissions
- Azure CLI or PowerShell installed
- Basic understanding of ARM templates or Bicep
- Familiarity with JSON and PowerShell/CLI
- Read: What is Policy-as-Code?
๐ฏ What You'll Learn
- Creating and managing Azure Policy definitions
- Building policy initiatives for comprehensive governance
- Implementing compliance assessments and remediation
- Using Azure Policy for cost management
- Integrating policies with Azure DevOps pipelines
- Best practices for enterprise-scale policy governance
๐ท๏ธ Topics Covered
Azure Policy Definition Examples: Complete Governance Guide
Azure Policy is Microsoft's native governance service that enables you to create, assign, and manage policies to enforce rules and effects over your Azure resources. It provides centralized policy management, compliance reporting, and automated remediation capabilities.
๐ Policy Definitions
Individual rules that define what you want to evaluate and what action to take
๐ Policy Initiatives
Collections of policy definitions grouped together for comprehensive governance
๐ฏ Policy Assignments
Application of policies or initiatives to specific scopes with enforcement parameters
Azure Policy Initiatives Tutorial: Step-by-Step Creation Guide
Policy definitions are the building blocks of Azure Policy. They define the conditions to evaluate and the actions to take when those conditions are met.
Basic Policy Structure
Basic Policy Definition Structure
{
"properties": {
"displayName": "Policy Display Name",
"description": "Detailed description of what this policy does",
"policyType": "Custom",
"mode": "All",
"parameters": {
// Parameter definitions
},
"policyRule": {
"if": {
// Conditions to evaluate
},
"then": {
"effect": "deny|audit|append|modify|deployIfNotExists"
}
}
}
}Example: Require Resource Tags
require-tags-policy.json
{
"properties": {
"displayName": "Require specific tags on resources",
"description": "Enforces the existence of specific tags on all resources",
"policyType": "Custom",
"mode": "Indexed",
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'Environment'"
}
},
"tagValues": {
"type": "Array",
"metadata": {
"displayName": "Tag Values",
"description": "List of allowed values for the tag"
}
}
},
"policyRule": {
"if": {
"anyOf": [
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": "false"
},
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"notIn": "[parameters('tagValues')]"
}
]
},
"then": {
"effect": "deny"
}
}
}
}Example: Storage Account Security Policy
storage-security-policy.json
{
"properties": {
"displayName": "Storage accounts should use HTTPS traffic only",
"description": "Audit requirement of Secure transfer in your storage account",
"policyType": "Custom",
"mode": "Indexed",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"field": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly",
"notEquals": "true"
}
]
},
"then": {
"effect": "audit"
}
}
}
}Creating Policies with Azure CLI
Create Policy Definition
# Create a custom policy definition
az policy definition create \
--name "require-tags-policy" \
--display-name "Require specific tags on resources" \
--description "Enforces the existence of specific tags on all resources" \
--rules require-tags-policy.json \
--mode Indexed
# List all policy definitions
az policy definition list --query "[?policyType=='Custom']" --output table
# Get specific policy definition
az policy definition show --name "require-tags-policy"Advanced Policy Examples
๐ง 1. VM Size Restriction Policy
vm-size-restriction.json
{
"properties": {
"displayName": "Allowed virtual machine size SKUs",
"description": "This policy enables you to specify a set of VM size SKUs that your organization can deploy",
"policyType": "Custom",
"mode": "Indexed",
"parameters": {
"allowedSKUs": {
"type": "Array",
"metadata": {
"description": "The list of size SKUs that can be specified for virtual machines",
"displayName": "Allowed Size SKUs",
"strongType": "VMSKUs"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"not": {
"field": "Microsoft.Compute/virtualMachines/sku.name",
"in": "[parameters('allowedSKUs')]"
}
}
]
},
"then": {
"effect": "Deny"
}
}
}
}๐ง 2. Network Security Group Rule Policy
nsg-rdp-restriction.json
{
"properties": {
"displayName": "Network Security Groups should not allow unrestricted access on port 3389",
"description": "This policy audits any network security group with unrestricted access on port 3389",
"policyType": "Custom",
"mode": "All",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkSecurityGroups/securityRules"
},
{
"allOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/access",
"equals": "Allow"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/direction",
"equals": "Inbound"
},
{
"anyOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange",
"equals": "*"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange",
"equals": "3389"
}
]
},
{
"anyOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix",
"equals": "*"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix",
"equals": "Internet"
}
]
}
]
}
]
},
"then": {
"effect": "audit"
}
}
}
}๐ง 3. Automatic Tagging with Modify Effect
auto-tag-policy.json
{
"properties": {
"displayName": "Add or replace a tag on resources",
"description": "Adds or replaces the specified tag and value when any resource is created or updated",
"policyType": "Custom",
"mode": "Indexed",
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'Environment'"
}
},
"tagValue": {
"type": "String",
"metadata": {
"displayName": "Tag Value",
"description": "Value of the tag, such as 'Production'"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"notEquals": "[parameters('tagValue')]"
},
{
"field": "type",
"notEquals": "Microsoft.Resources/subscriptions/resourceGroups"
}
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "[concat('tags[', parameters('tagName'), ']')]",
"value": "[parameters('tagValue')]"
}
]
}
}
}
}
}Azure Policy Compliance Assessment: Initiative Best Practices
Policy initiatives group related policy definitions together for easier management and assignment. They're essential for implementing comprehensive compliance frameworks.
Security Baseline Initiative
security-baseline-initiative.json
{
"properties": {
"displayName": "Security Baseline Initiative",
"description": "Collection of security policies for baseline compliance",
"metadata": {
"version": "1.0.0",
"category": "Security Center"
},
"parameters": {
"allowedLocations": {
"type": "Array",
"metadata": {
"description": "The list of locations that can be specified when deploying resources",
"displayName": "Allowed locations",
"strongType": "location"
}
},
"requiredTagName": {
"type": "String",
"metadata": {
"description": "Required tag name",
"displayName": "Required Tag Name"
},
"defaultValue": "Environment"
}
},
"policyDefinitions": [
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c",
"parameters": {
"listOfAllowedLocations": {
"value": "[parameters('allowedLocations')]"
}
},
"groupNames": ["LocationCompliance"]
},
{
"policyDefinitionId": "/subscriptions/{subscription-id}/providers/Microsoft.Authorization/policyDefinitions/require-tags-policy",
"parameters": {
"tagName": {
"value": "[parameters('requiredTagName')]"
}
},
"groupNames": ["TagCompliance"]
},
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/404c3081-a854-4457-ae30-26a93ef643f9",
"parameters": {},
"groupNames": ["StorageSecurity"]
}
],
"policyDefinitionGroups": [
{
"name": "LocationCompliance",
"displayName": "Location Compliance",
"description": "Policies related to allowed locations"
},
{
"name": "TagCompliance",
"displayName": "Tagging Compliance",
"description": "Policies related to required tags"
},
{
"name": "StorageSecurity",
"displayName": "Storage Security",
"description": "Policies related to storage account security"
}
]
}
}Creating Initiatives with Azure CLI
Create and Assign Initiative
# Create policy initiative
az policy set-definition create \
--name "security-baseline" \
--display-name "Security Baseline Initiative" \
--description "Collection of security policies for baseline compliance" \
--definitions security-baseline-initiative.json
# Assign initiative to subscription
az policy assignment create \
--name "security-baseline-assignment" \
--display-name "Security Baseline Assignment" \
--policy-set-definition "security-baseline" \
--scope "/subscriptions/{subscription-id}" \
--params '{
"allowedLocations": {
"value": ["eastus", "westus2", "centralus"]
},
"requiredTagName": {
"value": "Environment"
}
}'
# List policy assignments
az policy assignment list --scope "/subscriptions/{subscription-id}" --output tableAzure Policy JSON Examples: Monitoring and Compliance Automation
Azure Policy provides comprehensive compliance monitoring and reporting capabilities to track your governance posture across all resources.
Viewing Compliance Status
Compliance Commands
# Get compliance summary for a subscription
az policy state summarize --scope "/subscriptions/{subscription-id}"
# Get detailed compliance for specific assignment
az policy state list \
--assignment-name "security-baseline-assignment" \
--scope "/subscriptions/{subscription-id}" \
--filter "ComplianceState eq 'NonCompliant'" \
--output table
# Get compliance for a specific resource
az policy state list \
--resource "/subscriptions/{sub-id}/resourceGroups/{rg-name}/providers/{provider}/{resource-name}" \
--output table
# Trigger compliance evaluation
az policy state trigger-scan --scope "/subscriptions/{subscription-id}"PowerShell Compliance Reporting
compliance-report.ps1
# Connect to Azure
Connect-AzAccount
# Get compliance summary
$complianceSummary = Get-AzPolicyStateSummary -SubscriptionId "{subscription-id}"
# Display compliance by policy assignment
$complianceSummary.PolicyAssignments | ForEach-Object {
Write-Host "Assignment: $($_.PolicyAssignmentId)"
Write-Host "Compliant Resources: $($_.Results.ResourceDetails.ComplianceState.Compliant)"
Write-Host "Non-Compliant Resources: $($_.Results.ResourceDetails.ComplianceState.NonCompliant)"
Write-Host "---"
}
# Get detailed non-compliant resources
$nonCompliantResources = Get-AzPolicyState -SubscriptionId "{subscription-id}" |
Where-Object { $_.ComplianceState -eq "NonCompliant" }
# Export to CSV
$nonCompliantResources | Export-Csv -Path "compliance-report.csv" -NoTypeInformation
# Generate summary report
$report = @{
TotalResources = $complianceSummary.Results.ResourceDetails.TotalResources
CompliantResources = $complianceSummary.Results.ResourceDetails.ComplianceState.Compliant
NonCompliantResources = $complianceSummary.Results.ResourceDetails.ComplianceState.NonCompliant
CompliancePercentage = [math]::Round(($complianceSummary.Results.ResourceDetails.ComplianceState.Compliant / $complianceSummary.Results.ResourceDetails.TotalResources) * 100, 2)
}
Write-Host "Compliance Summary:"
Write-Host "Total Resources: $($report.TotalResources)"
Write-Host "Compliant: $($report.CompliantResources)"
Write-Host "Non-Compliant: $($report.NonCompliantResources)"
Write-Host "Compliance Rate: $($report.CompliancePercentage)%"Azure Resource Governance Policies: Automated Remediation Guide
Azure Policy can automatically remediate non-compliant resources using remediation tasks and policies with modify or deployIfNotExists effects.
Creating Remediation Tasks
Create Remediation Task
# Create remediation task for non-compliant resources
az policy remediation create \
--name "tag-remediation-task" \
--policy-assignment "/subscriptions/{sub-id}/providers/Microsoft.Authorization/policyAssignments/require-tags" \
--scope "/subscriptions/{subscription-id}" \
--resource-discovery-mode "ExistingNonCompliant"
# Monitor remediation progress
az policy remediation show \
--name "tag-remediation-task" \
--scope "/subscriptions/{subscription-id}"
# List all remediation tasks
az policy remediation list --scope "/subscriptions/{subscription-id}"DeployIfNotExists Policy Example
deploy-diagnostic-settings.json
{
"properties": {
"displayName": "Deploy Diagnostic Settings for Storage Accounts",
"description": "Deploys diagnostic settings for storage accounts to a Log Analytics workspace",
"policyType": "Custom",
"mode": "Indexed",
"parameters": {
"logAnalyticsWorkspaceId": {
"type": "String",
"metadata": {
"displayName": "Log Analytics Workspace ID",
"description": "Resource ID of the Log Analytics workspace"
}
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "deployIfNotExists",
"details": {
"type": "Microsoft.Insights/diagnosticSettings",
"name": "storageAccountDiagnosticSettings",
"existenceCondition": {
"field": "Microsoft.Insights/diagnosticSettings/workspaceId",
"equals": "[parameters('logAnalyticsWorkspaceId')]"
},
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa",
"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293"
],
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string"
},
"workspaceId": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts/providers/diagnosticSettings",
"apiVersion": "2017-05-01-preview",
"name": "[concat(parameters('storageAccountName'), '/Microsoft.Insights/storageAccountDiagnosticSettings')]",
"properties": {
"workspaceId": "[parameters('workspaceId')]",
"logs": [
{
"category": "StorageRead",
"enabled": true
},
{
"category": "StorageWrite",
"enabled": true
}
],
"metrics": [
{
"category": "Transaction",
"enabled": true
}
]
}
}
]
},
"parameters": {
"storageAccountName": {
"value": "[field('name')]"
},
"workspaceId": {
"value": "[parameters('logAnalyticsWorkspaceId')]"
}
}
}
}
}
}
}
}
}Azure Policy Best Practices: DevOps Pipeline Integration
Integrate Azure Policy validation into your CI/CD pipelines to ensure infrastructure compliance before deployment.
Azure DevOps Pipeline
azure-pipelines.yml
trigger:
branches:
include:
- main
- develop
paths:
include:
- infrastructure/*
- policies/*
variables:
azureSubscription: 'your-service-connection'
resourceGroupName: 'policy-governance-rg'
stages:
- stage: PolicyValidation
displayName: 'Policy Validation'
jobs:
- job: ValidatePolicies
displayName: 'Validate Policy Definitions'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: AzureCLI@2
displayName: 'Validate Policy Definitions'
inputs:
azureSubscription: $(azureSubscription)
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
echo "Validating policy definitions..."
# Validate JSON syntax
find policies/ -name "*.json" | while read policy; do
echo "Validating $policy"
if ! jq empty "$policy"; then
echo "Invalid JSON in $policy"
exit 1
fi
done
# Test create policy definitions (dry run)
find policies/definitions/ -name "*.json" | while read policy; do
policyName=$(basename "$policy" .json)
echo "Testing policy definition: $policyName"
az policy definition create \
--name "test-$policyName" \
--rules "$policy" \
--mode Indexed \
--subscription $(az account show --query id -o tsv) \
--only-show-errors || exit 1
# Clean up test policy
az policy definition delete \
--name "test-$policyName" \
--subscription $(az account show --query id -o tsv)
done
- stage: InfrastructureValidation
displayName: 'Infrastructure Validation'
dependsOn: PolicyValidation
jobs:
- job: ValidateTemplates
displayName: 'Validate ARM Templates'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: AzureCLI@2
displayName: 'Deploy and Test Infrastructure'
inputs:
azureSubscription: $(azureSubscription)
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
# Create test resource group
az group create \
--name "test-$(resourceGroupName)" \
--location "East US"
# Validate ARM template
az deployment group validate \
--resource-group "test-$(resourceGroupName)" \
--template-file infrastructure/main.bicep \
--parameters infrastructure/parameters.json
# Deploy with what-if to see policy impact
az deployment group what-if \
--resource-group "test-$(resourceGroupName)" \
--template-file infrastructure/main.bicep \
--parameters infrastructure/parameters.json
# Clean up test resource group
az group delete \
--name "test-$(resourceGroupName)" \
--yes --no-wait
- stage: PolicyDeployment
displayName: 'Deploy Policies'
dependsOn: InfrastructureValidation
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployPolicies
displayName: 'Deploy Policy Definitions and Assignments'
environment: 'Production'
pool:
vmImage: 'ubuntu-latest'
strategy:
runOnce:
deploy:
steps:
- task: AzureCLI@2
displayName: 'Deploy Policy Definitions'
inputs:
azureSubscription: $(azureSubscription)
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
# Deploy policy definitions
find policies/definitions/ -name "*.json" | while read policy; do
policyName=$(basename "$policy" .json)
echo "Deploying policy definition: $policyName"
az policy definition create \
--name "$policyName" \
--rules "$policy" \
--mode Indexed \
--subscription $(az account show --query id -o tsv)
done
# Deploy policy initiatives
find policies/initiatives/ -name "*.json" | while read initiative; do
initiativeName=$(basename "$initiative" .json)
echo "Deploying policy initiative: $initiativeName"
az policy set-definition create \
--name "$initiativeName" \
--definitions "$initiative" \
--subscription $(az account show --query id -o tsv)
done
# Deploy policy assignments
find policies/assignments/ -name "*.json" | while read assignment; do
assignmentName=$(basename "$assignment" .json)
echo "Deploying policy assignment: $assignmentName"
az deployment sub create \
--location "East US" \
--template-file "$assignment" \
--parameters subscriptionId=$(az account show --query id -o tsv)
done
- task: AzureCLI@2
displayName: 'Generate Compliance Report'
inputs:
azureSubscription: $(azureSubscription)
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
# Wait for policy evaluation
echo "Waiting for policy evaluation..."
sleep 300
# Generate compliance report
az policy state summarize \
--scope "/subscriptions/$(az account show --query id -o tsv)" \
--output table
# Trigger compliance scan
az policy state trigger-scan \
--scope "/subscriptions/$(az account show --query id -o tsv)"Azure Policy Best Practices
Policy Design Principles
Start with audit effects before enforcement, use meaningful names and descriptions, implement parameterized policies for flexibility, and group related policies into initiatives.
Scope Management
Assign at appropriate scope (subscription/RG), use exclusions judiciously, test at smaller scopes first, and document scope decisions and rationale.
Testing Strategy
Validate JSON syntax automatically, test with representative resources, use What-If deployments, and monitor compliance after deployment.
Lifecycle Management
Version control all policy definitions, use systematic naming conventions, regular review and cleanup, and plan for policy deprecation.
Documentation
Clear business justification, remediation guidance, exception handling process, and contact information for questions.
Performance
Optimize policy rule complexity, monitor evaluation performance, use appropriate policy modes, and consider resource provider limits.
Troubleshooting Common Issues
Policy Definition Issues
โ Policy not evaluating resources
Problem: Policy assignment exists but compliance shows no resources evaluated.
Solutions:
- Check policy mode (All vs Indexed)
- Verify resource types in scope
- Check assignment scope and exclusions
- Wait for evaluation cycle (can take up to 30 minutes)
โ Remediation task failing
Problem: Remediation tasks fail with permission or template errors.
Solutions:
- Verify managed identity has required permissions
- Check ARM template syntax in policy
- Review activity logs for detailed error messages
- Test template deployment separately
Assignment Issues
โ Unexpected policy violations
Problem: Resources showing as non-compliant unexpectedly.
Solutions:
- Review policy rule logic carefully
- Check for case sensitivity in field values
- Verify parameter values in assignment
- Use compliance details to understand violations
๐ Congratulations!
Azure Policy Governance Mastery
You now have comprehensive knowledge of Azure Policy implementation including:
Custom Policy Definitions
Create and manage custom policy definitions and initiatives for comprehensive governance.
Compliance Monitoring
Implement compliance monitoring and reporting to track your governance posture.
Automated Remediation
Set up automated remediation for non-compliant resources using policy effects.
DevOps Integration
Integrate policies into DevOps pipelines for continuous compliance validation.
Enterprise Best Practices
Apply proven patterns for enterprise-scale Azure governance and policy management.
Troubleshooting Skills
Debug and resolve common policy issues with systematic approaches.