Governance & Policy
How to implement Azure Policy, compliance, and cost management at scale.
Governance Framework
Azure Policy Deep Dive
Policy Effects
| Effect | Behavior | Use Case |
|---|---|---|
| Deny | Block non-compliant deployment | Hard guardrails |
| Audit | Allow but report non-compliance | Soft guardrails |
| AuditIfNotExists | Audit if related resource missing | Dependency check |
| Modify | Auto-fix configuration | Tag enforcement |
| Append | Add properties to resource | NSG rules |
| DeployIfNotExists | Deploy related resource | Diagnostic settings |
| Disabled | Policy not evaluated | Testing/rollback |
Policy Evaluation Flow
Policy Assignment Hierarchy
Core Policy Categories
Policy Initiatives (Policy Sets)
Landing Zone Initiative Structure
targetScope = 'managementGroup'
resource landingZoneInitiative 'Microsoft.Authorization/policySetDefinitions@2021-06-01' = {
name: 'landing-zone-policies'
properties: {
displayName: 'Landing Zone Governance Policies'
policyType: 'Custom'
metadata: {
category: 'Landing Zone'
version: '1.0.0'
}
policyDefinitions: [
// Security policies
{
policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/0a914e76-4921-4c19-b460-a2d36003525a'
policyDefinitionReferenceId: 'RequireStorageEncryption'
}
{
policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/404c3081-a854-4457-ae30-26a93ef643f9'
policyDefinitionReferenceId: 'RequireSecureTransfer'
}
// Network policies
{
policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/e71308d3-144b-4262-b144-efdc3cc90517'
policyDefinitionReferenceId: 'DenyPublicIP'
}
// Monitoring policies
{
policyDefinitionId: deployDiagnosticSettings.id
policyDefinitionReferenceId: 'DeployDiagnostics'
parameters: {
logAnalyticsWorkspaceId: {
value: '[parameters(\'logAnalyticsWorkspaceId\')]'
}
}
}
// Tagging policies
{
policyDefinitionId: requireTag.id
policyDefinitionReferenceId: 'RequireCostCenterTag'
parameters: {
tagName: {
value: 'CostCenter'
}
}
}
]
parameters: {
logAnalyticsWorkspaceId: {
type: 'String'
metadata: {
displayName: 'Log Analytics Workspace ID'
}
}
}
}
}
Common Policy Definitions
Require Tags
resource requireTag 'Microsoft.Authorization/policyDefinitions@2021-06-01' = {
name: 'require-tag'
properties: {
displayName: 'Require a tag on resources'
policyType: 'Custom'
mode: 'Indexed'
parameters: {
tagName: {
type: 'String'
metadata: {
displayName: 'Tag Name'
}
}
}
policyRule: {
if: {
field: '[concat(\'tags[\', parameters(\'tagName\'), \']\')]'
exists: false
}
then: {
effect: 'Deny'
}
}
}
}
Inherit Tag from Resource Group
resource inheritTag 'Microsoft.Authorization/policyDefinitions@2021-06-01' = {
name: 'inherit-tag-from-rg'
properties: {
displayName: 'Inherit tag from resource group'
policyType: 'Custom'
mode: 'Indexed'
parameters: {
tagName: {
type: 'String'
}
}
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'
]
operations: [
{
operation: 'addOrReplace'
field: '[concat(\'tags[\', parameters(\'tagName\'), \']\')]'
value: '[resourceGroup().tags[parameters(\'tagName\')]]'
}
]
}
}
}
}
}
Deploy Diagnostic Settings
resource deployDiagnostics 'Microsoft.Authorization/policyDefinitions@2021-06-01' = {
name: 'deploy-diagnostic-settings'
properties: {
displayName: 'Deploy diagnostic settings for storage accounts'
policyType: 'Custom'
mode: 'Indexed'
parameters: {
logAnalyticsWorkspaceId: {
type: 'String'
}
}
policyRule: {
if: {
field: 'type'
equals: 'Microsoft.Storage/storageAccounts'
}
then: {
effect: 'DeployIfNotExists'
details: {
type: 'Microsoft.Insights/diagnosticSettings'
name: 'setByPolicy'
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': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
contentVersion: '1.0.0.0'
parameters: {
resourceName: {
type: 'string'
}
workspaceId: {
type: 'string'
}
}
resources: [
{
type: 'Microsoft.Storage/storageAccounts/providers/diagnosticSettings'
apiVersion: '2021-05-01-preview'
name: '[concat(parameters(\'resourceName\'), \'/Microsoft.Insights/setByPolicy\')]'
properties: {
workspaceId: '[parameters(\'workspaceId\')]'
logs: []
metrics: [
{
category: 'AllMetrics'
enabled: true
}
]
}
}
]
}
parameters: {
resourceName: {
value: '[field(\'name\')]'
}
workspaceId: {
value: '[parameters(\'logAnalyticsWorkspaceId\')]'
}
}
}
}
}
}
}
}
}
Allowed VM SKUs
resource allowedVmSkus 'Microsoft.Authorization/policyDefinitions@2021-06-01' = {
name: 'allowed-vm-skus'
properties: {
displayName: 'Allowed VM SKUs'
policyType: 'Custom'
mode: 'Indexed'
parameters: {
listOfAllowedSKUs: {
type: 'Array'
metadata: {
displayName: 'Allowed SKUs'
}
defaultValue: [
'Standard_D2s_v5'
'Standard_D4s_v5'
'Standard_D8s_v5'
'Standard_E2s_v5'
'Standard_E4s_v5'
]
}
}
policyRule: {
if: {
allOf: [
{
field: 'type'
equals: 'Microsoft.Compute/virtualMachines'
}
{
not: {
field: 'Microsoft.Compute/virtualMachines/sku.name'
in: '[parameters(\'listOfAllowedSKUs\')]'
}
}
]
}
then: {
effect: 'Deny'
}
}
}
}
Cost Management
Cost Governance Architecture
Budget Configuration
resource budget 'Microsoft.Consumption/budgets@2023-05-01' = {
name: 'monthly-budget'
properties: {
category: 'Cost'
amount: 50000
timeGrain: 'Monthly'
timePeriod: {
startDate: '2024-01-01'
}
filter: {
dimensions: {
name: 'ResourceGroupName'
operator: 'In'
values: [
'rg-*-prod-*'
]
}
}
notifications: {
'50-percent': {
enabled: true
threshold: 50
operator: 'GreaterThanOrEqualTo'
contactEmails: ['finance@contoso.com']
thresholdType: 'Actual'
}
'80-percent': {
enabled: true
threshold: 80
operator: 'GreaterThanOrEqualTo'
contactEmails: ['finance@contoso.com', 'platform@contoso.com']
thresholdType: 'Actual'
}
'100-percent': {
enabled: true
threshold: 100
operator: 'GreaterThanOrEqualTo'
contactEmails: ['finance@contoso.com', 'platform@contoso.com', 'cfo@contoso.com']
thresholdType: 'Actual'
}
'110-percent-forecast': {
enabled: true
threshold: 110
operator: 'GreaterThanOrEqualTo'
contactEmails: ['finance@contoso.com']
thresholdType: 'Forecasted'
}
}
}
}
Cost Allocation Tags
| Tag | Purpose | Example |
|---|---|---|
| CostCenter | Billing code | CC-12345 |
| Department | Business unit | Finance |
| Project | Initiative | CloudMigration |
| Environment | Lifecycle | Production |
| Owner | Cost owner | john@contoso.com |
Cost Policy Examples
// Deny expensive VM SKUs in non-production
resource denyExpensiveVMs 'Microsoft.Authorization/policyDefinitions@2021-06-01' = {
name: 'deny-expensive-vms-nonprod'
properties: {
displayName: 'Deny expensive VMs in non-production'
policyType: 'Custom'
mode: 'Indexed'
policyRule: {
if: {
allOf: [
{
field: 'type'
equals: 'Microsoft.Compute/virtualMachines'
}
{
field: 'Microsoft.Compute/virtualMachines/sku.name'
in: [
'Standard_M*'
'Standard_L*'
'Standard_ND*'
]
}
]
}
then: {
effect: 'Deny'
}
}
}
}
Compliance Dashboard
Built-in Compliance Standards
| Standard | Scope | Use Case |
|---|---|---|
| Azure Security Benchmark | All | Default security baseline |
| CIS Microsoft Azure | All | Industry benchmark |
| NIST SP 800-53 | Government | US Federal |
| ISO 27001 | All | Information security |
| PCI DSS | Payment | Credit card data |
| HIPAA | Healthcare | Patient data |
| SOC 2 | All | Service organizations |
Compliance Assignment
resource cisCompliance 'Microsoft.Authorization/policyAssignments@2022-06-01' = {
name: 'cis-azure-benchmark'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/89c6cddc-1c73-4ac1-b19c-54d1a15a42f2'
displayName: 'CIS Microsoft Azure Foundations Benchmark'
enforcementMode: 'Default'
}
}
Policy Exemptions
When to Use Exemptions
Exemption Configuration
resource policyExemption 'Microsoft.Authorization/policyExemptions@2022-07-01-preview' = {
name: 'legacy-app-exemption'
properties: {
policyAssignmentId: policyAssignment.id
exemptionCategory: 'Waiver'
displayName: 'Legacy application exemption'
description: 'Legacy app requires public endpoint until migration completes'
expiresOn: '2024-12-31T23:59:59Z'
metadata: {
requestedBy: 'app-team@contoso.com'
approvedBy: 'security@contoso.com'
ticketNumber: 'SEC-2024-001'
}
}
}
Governance Checklist
✅ Policy
- Security baseline policies assigned at root
- Network policies at landing zone level
- Tagging policies enforced
- DeployIfNotExists for monitoring
- Exemption process documented
✅ Cost
- Budgets configured per subscription
- Cost allocation tags mandatory
- Expensive SKU restrictions
- Reserved instance strategy
- Monthly cost reviews
✅ Compliance
- Relevant standards assigned
- Compliance dashboard reviewed weekly
- Remediation tasks prioritized
- Exemptions documented and reviewed
Quick Reference Card
| Component | Configuration |
|---|---|
| Policy Scope | Assign at highest applicable MG |
| Enforcement | Deny for hard guardrails |
| Monitoring | DeployIfNotExists for diagnostics |
| Tags | Minimum 5 required tags |
| Budgets | Per subscription with alerts |
| Exemptions | Time-limited, documented |
Next Steps
Continue to Management & Operations to learn about monitoring, logging, and automation.