Compliance as Code — Azure Policy
Automating Governance at Scale
Introduction
Compliance as Code with Azure Policy enables you to define, enforce, and audit cloud resources programmatically. Instead of manual reviews and sporadic checks, policies continuously ensure your integration workloads adhere to organizational standards, security requirements, and regulatory compliance. This approach shifts compliance left—catching issues before they reach production.
This comprehensive guide covers:
- Policy fundamentals — Understanding Azure Policy
- Policy definition — Creating custom policies
- Initiatives — Grouping related policies
- Assignment — Applying policies to resources
- Remediation — Automatic issue fixing
- Enterprise governance — At scale management
Policy Fundamentals
How Azure Policy Works
┌─────────────────────────────────────────────────────────────────────┐
│ AZURE POLICY ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ POLICY DEFINITION │
│ (What rules to enforce) │
│ └─── "Storage accounts must use HTTPS" │
│ └─── "Functions must use managed identity" │
│ └─── "Service Bus must have firewall enabled" │
│ │
│ ↓ │
│ │
│ POLICY ASSIGNMENT │
│ (Where to apply) │
│ └─── Subscription: Production │
│ └─── Resource Group: rg-integration │
│ └─── Resource: specific-function-app │
│ │
│ ↓ │
│ │
│ EVALUATION │
│ (When to check) │
│ └─── On resource create/update │
│ └─── On assignment │
│ └─── Periodic (daily/weekly) │
│ └─── On demand │
│ │
│ ↓ │
│ │
│ EFFECTS │
│ (What happens) │
│ └─── Deny: Block non-compliant resources │
│ └─── Audit: Log non-compliance │
│ └─── DeployIfNotExists: Auto-remediation │
│ └─── Modify: Add/remove tags │
│ └─── AuditIfNotExists: Check nested resources │
│ │
└─────────────────────────────────────────────────────────────────────┘
Built-in Policies
# List policies for integration services
az policy definition list \
--query "[?contains(displayName, 'Function') || contains(displayName, 'Storage')]"
# Get specific policy
az policy definition show \
--name "Function App should use latest TLS version"
# List initiatives
az policy initiative list
Creating Custom Policies
Policy Structure
{
"name": "require-https-for-servicebus",
"type": "Microsoft.Authorization/policyDefinitions",
"properties": {
"displayName": "Service Bus should require HTTPS",
"description": "Enforce HTTPS for Service Bus namespace to ensure data in transit is encrypted",
"mode": "All",
"metadata": {
"version": "1.0.0",
"category": "Network Security"
},
"parameters": {
"effect": {
"type": "String",
"defaultValue": "Deny",
"allowedValues": ["Deny", "Audit", "Disabled"],
"metadata": {
"displayName": "Effect",
"description": "The effect determines what happens when the policy rule is evaluated"
}
}
},
"policyRule": {
"if": {
"anyOf": [
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.ServiceBus/namespaces"
},
{
"field": "Microsoft.ServiceBus/namespaces/requiresGuestAccessAPIs",
"equals": "true"
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
Integration-Specific Policies
{
"policies": [
{
"name": "functions-use-managed-identity",
"description": "Azure Functions should have managed identity enabled",
"effect": "deployIfNotExists",
"resourceType": "Microsoft.Web/sites",
"condition": "type == 'Microsoft.Web/sites' AND kind contains 'function'",
"deployment": {
"properties": {
"mode": "incremental",
"parameters": {
"functionAppName": {
"value": "[field('name')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"resources": [
{
"type": "Microsoft.Web/sites",
"identity": {
"type": "SystemAssigned"
}
}
]
}
}
}
},
{
"name": "servicebus-queue-lifecycle-policy",
"description": "Service Bus queues should have TTL set",
"effect": "auditIfNotExists",
"resourceType": "Microsoft.ServiceBus/namespaces/queues",
"condition": "type == 'Microsoft.ServiceBus/namespaces/queues'",
"existenceCondition": {
"field": "properties.defaultMessageTimeToLive",
"greater": "P1D"
}
}
]
}
Policy Initiatives
Initiative Definition
{
"name": "integration-security-baseline",
"type": "Microsoft.Authorization/policyInitiatives",
"properties": {
"displayName": "Integration Security Baseline",
"description": "Security baseline for integration workloads",
"metadata": {
"version": "1.0.0",
"category": "Security"
},
"policyDefinitions": [
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/function-app-should-use-managed-identity",
"parameters": {}
},
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/storage-uses-minimum-tls",
"parameters": {
"minimumTlsVersion": {
"value": "TLS1_2"
}
}
},
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/servicebus-enable-private-endpoint",
"parameters": {
"effect": {
"value": "Deny"
}
}
},
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/api-management-disallow-public-access",
"parameters": {}
}
]
}
}
Assign Initiative
# Assign initiative to subscription
az policy assignment create \
--name "integration-security-baseline" \
--display-name "Integration Security Baseline" \
--description "Security controls for integration workloads" \
--policy-set-definition "integration-security-baseline" \
--scope "/subscriptions/xxx" \
--params '{
"listOfResourceTypesToAudit": {
"value": ["Microsoft.Web/sites", "Microsoft.ServiceBus/namespaces", "Microsoft.Storage/storageAccounts"]
}
}'
# Assign to specific resource group
az policy assignment create \
--name "integration-compliance" \
--policy-set-definition "integration-security-baseline" \
--scope "/subscriptions/xxx/resourceGroups/rg-integration"
Remediation
Automatic Remediation
{
"remediationTask": {
"name": "enable-storage-https",
"properties": {
"policyAssignmentId": "/subscriptions/xxx/providers/Microsoft.Authorization/policyAssignments/storage-compliance",
"policyDefinitionGuid": "xxx-xxx-xxx",
"resourceDiscoveryMode": "ExistingNonCompliant"
}
}
}
# Create remediation task
az policy remediation create \
--name "fix-https-requirement" \
--policy-assignment "storage-compliance" \
--resource-group "rg-integration"
# List non-compliant resources
az policy state list \
--query "[?complianceState=='NonCompliant']"
# View remediation status
az policy remediation show \
--name "fix-https-requirement"
Enterprise Governance
Governance at Scale
{
"enterpriseGovernance": {
"managementGroups": {
"root": {
"displayName": "Contoso",
"children": [
{
"displayName": "Production",
"policyAssignments": ["prod-security-baseline"]
},
{
"displayName": "Development",
"policyAssignments": ["dev-security-baseline"]
}
]
}
},
"exemptions": {
"allowByDefault": false,
"requireJustification": true,
"maxDurationDays": 90,
"reviewRequired": true
}
}
}
Policy as Code
# GitHub workflow for policy management
name: Policy Pipeline
on:
push:
paths:
- 'policies/**'
branches:
- main
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Validate policy JSON
run: |
for file in policies/*.json; do
jq empty "$file" || exit 1
done
- name: Check policy structure
run: |
# Validate required fields
az deployment validate \
--location eastus \
--template-file policies/test-template.json
deploy:
needs: validate
runs-on: ubuntu-latest
steps:
- name: Deploy policies
run: |
for file in policies/definitions/*.json; do
az policy definition create \
--name $(basename "$file" .json) \
--mode All \
--policy "$file"
done
Best Practices
Implementation Checklist
| Practice | Description |
|---|---|
| Start with audit | Use audit effect before deny |
| Use initiatives | Group related policies |
| Enable remediation | Auto-fix where possible |
| Use exemptions wisely | Document and limit duration |
| Version policies | Track changes in source control |
| Review compliance | Regular compliance reports |
Policy Design Guidelines
┌─────────────────────────────────────────────────────────────────────┐
│ POLICY DESIGN GUIDELINES │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ✓ Name clearly: describe-what-where-when │
│ ✓ Document: displayName, description, category │
│ ✓ Version: track changes in metadata │
│ ✓ Test first: use audit mode before deny │
│ ✓ Keep simple: one policy, one purpose │
│ ✓ Parameterize: make policies configurable │
│ │
└─────────────────────────────────────────────────────────────────────┘
Related Topics
- Zero Trust Networking — Security architecture
- Key Vault Governance — Secrets management
- Defender for Cloud — Security monitoring
Azure Integration Hub - Architect Level Security Architecture & Zero Trust