Governance Overview
What is Azure Governance?
Azure Governance is a framework of tools and practices that help organizations manage their Azure environment at scale with consistency, compliance, and cost control. It encompasses:
- Organizational Structure: Management groups for hierarchical organization
- Policy Enforcement: Azure Policy for compliance and standards
- Cost Control: Budgets, alerts, and cost optimization
- Resource Organization: Naming conventions, tagging, and resource groups
- Security & Compliance: Regulatory compliance tracking and reporting
Key Services
| Service | Purpose | Team Owner |
|---|---|---|
| Management Groups | Hierarchical organization of subscriptions | Governance Team |
| Azure Policy | Compliance automation and standards enforcement | Governance Team |
| Azure Blueprints | Repeatable environment definitions | Governance Team |
| Cost Management | Budget tracking and cost optimization | Governance & Finance Teams |
| Resource Graph | Query and analyze resources at scale | Operations Team |
| Azure Advisor | Best practice recommendations | All Teams |
Governance Framework Components
1. Management Group Hierarchy
Organize subscriptions into a logical hierarchy for centralized management:
Root Management Group (Tenant)
├── Production
│ ├── Subscription: Prod-App1
│ └── Subscription: Prod-App2
├── Non-Production
│ ├── Development
│ │ └── Subscription: Dev-Shared
│ └── Testing
│ └── Subscription: Test-Shared
└── Sandbox
└── Subscription: Innovation-Lab
Benefits:
- Apply policies at scale
- Centralized RBAC management
- Inheritance of policies and access
- Clear organizational structure
# Create management group hierarchy
az account management-group create \
--name Production \
--display-name "Production Environments"
az account management-group create \
--name Non-Production \
--display-name "Non-Production Environments" \
--parent Production
# Move subscription to management group
az account management-group subscription add \
--name Production \
--subscription "Prod-App1"
2. Azure Policy
Enforce organizational standards and compliance:
Common Policy Use Cases:
- Allowed Azure regions
- Required tags on resources
- Allowed VM SKU sizes
- Enforce encryption
- Network security requirements
- Naming conventions
# Assign built-in policy: Allowed locations
az policy assignment create \
--name 'allowed-locations' \
--display-name 'Allowed Azure Regions' \
--policy '/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c' \
--params '{"listOfAllowedLocations":{"value":["eastus","westus","centralus"]}}' \
--scope /subscriptions/{subscription-id}
# Assign built-in policy: Require tag on resources
az policy assignment create \
--name 'require-environment-tag' \
--policy '/providers/Microsoft.Authorization/policyDefinitions/96670d01-0a4d-4649-9c89-2d3abc0a5025' \
--params '{"tagName":{"value":"Environment"}}' \
--scope /subscriptions/{subscription-id}
3. Naming Conventions
Establish consistent naming across all resources:
Recommended Pattern:
{resource-type}-{workload}-{environment}-{region}-{instance}
Examples:
rg-app1-prod-eastus-01 # Resource Group
kv-app1-prod-eastus-01 # Key Vault
st-app1prodeastus01 # Storage Account (no hyphens)
vm-app1-prod-eastus-01 # Virtual Machine
vnet-hub-prod-eastus-01 # Virtual Network
aks-app1-prod-eastus-01 # AKS Cluster
Abbreviation Reference:
rg- Resource Groupkv- Key Vaultst- Storage Accountvm- Virtual Machinevnet- Virtual Networksnet- Subnetnsg- Network Security Groupaks- Azure Kubernetes Servicesql- SQL Serversqldb- SQL Databaseapp- App Service
4. Tagging Strategy
Tags enable resource organization, cost allocation, and automation:
Required Tags (Example):
{
"Environment": "Production|Development|Testing|Sandbox",
"Owner": "team-email@contoso.com",
"CostCenter": "CC-12345",
"Application": "MyApp",
"Criticality": "High|Medium|Low"
}
Optional Tags:
{
"MaintenanceWindow": "Saturday 02:00-04:00 UTC",
"DataClassification": "Confidential|Internal|Public",
"Compliance": "HIPAA|PCI-DSS|SOC2",
"BackupPolicy": "Daily|Weekly|None",
"AutoShutdown": "true|false"
}
Terraform Example
# Management Group
resource "azurerm_management_group" "production" {
display_name = "Production"
}
# Azure Policy Assignment
resource "azurerm_subscription_policy_assignment" "allowed_locations" {
name = "allowed-locations"
subscription_id = data.azurerm_subscription.current.id
policy_definition_id = "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c"
description = "Restrict deployments to allowed regions"
display_name = "Allowed Locations"
parameters = jsonencode({
listOfAllowedLocations = {
value = ["eastus", "westus", "centralus"]
}
})
}
# Custom Policy Definition
resource "azurerm_policy_definition" "require_tags" {
name = "require-tags"
policy_type = "Custom"
mode = "Indexed"
display_name = "Require Tags on Resources"
policy_rule = jsonencode({
if = {
allOf = [
{
field = "tags"
exists = "false"
}
]
}
then = {
effect = "deny"
}
})
}
# Resource Group with Governance Tags
resource "azurerm_resource_group" "app" {
name = "rg-${var.application}-${var.environment}-${var.region}-01"
location = var.region
tags = {
Environment = var.environment
Owner = var.owner_email
CostCenter = var.cost_center
Application = var.application
Criticality = var.criticality
ManagedBy = "Terraform"
DataClassification = var.data_classification
}
}
# Budget Alert
resource "azurerm_consumption_budget_subscription" "monthly" {
name = "budget-${var.application}-monthly"
subscription_id = data.azurerm_subscription.current.id
amount = 10000
time_grain = "Monthly"
time_period {
start_date = "2024-01-01T00:00:00Z"
}
notification {
enabled = true
threshold = 80
operator = "GreaterThan"
contact_emails = [
var.owner_email,
"finance@contoso.com"
]
}
notification {
enabled = true
threshold = 100
operator = "GreaterThan"
contact_emails = [
var.owner_email,
"finance@contoso.com",
"executives@contoso.com"
]
}
}
CI/CD Integration
Policy as Code with GitHub Actions
name: Azure Policy Compliance
on:
schedule:
- cron: '0 0 * * *' # Daily
workflow_dispatch:
jobs:
compliance-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Check Policy Compliance
run: |
# Get compliance state
az policy state list \
--filter "ComplianceState eq 'NonCompliant'" \
-o table
# Trigger policy scan
az policy state trigger-scan \
--resource-group rg-app-prod
- name: Report Non-Compliance
if: failure()
uses: actions/github-script@v6
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Azure Policy Non-Compliance Detected',
body: 'Non-compliant resources found. Check workflow logs.'
})
Terraform with Governance Validation
name: Terraform Governance Check
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Terraform Init
run: terraform init
- name: Terraform Validate
run: terraform validate
- name: Check Naming Conventions
run: |
# Validate resource names follow convention
terraform show -json tfplan | \
jq -r '.planned_values.root_module.resources[] | select(.name | test("^(rg|kv|st|vm)-") | not) | .address' | \
while read resource; do
echo "::error::Resource $resource does not follow naming convention"
exit 1
done
- name: Check Required Tags
run: |
# Ensure all resources have required tags
terraform show -json tfplan | \
jq -r '.planned_values.root_module.resources[] | select(.values.tags.Environment == null or .values.tags.Owner == null) | .address' | \
while read resource; do
echo "::error::Resource $resource missing required tags"
exit 1
done
Best Practices
Establish a clear governance framework before deploying resources at scale.
Design Management Group Hierarchy Carefully
- Keep hierarchy simple (3-4 levels maximum)
- Plan for future growth
- Align with organizational structure
- Document the hierarchy and rationale
Implement Policy Gradually
❌ Don't: Apply strict deny policies to existing environments without testing ✅ Do: Start with audit mode, analyze results, then enforce
# Step 1: Create policy in audit mode
az policy assignment create \
--name 'audit-vm-sizes' \
--policy <policy-id> \
--params '{"effect":{"value":"Audit"}}'
# Step 2: Review compliance for 30 days
# Step 3: Switch to deny mode after stakeholder agreement
az policy assignment update \
--name 'audit-vm-sizes' \
--params '{"effect":{"value":"Deny"}}'
Use Policy Initiatives (Policy Sets)
Group related policies for easier management:
# Create policy initiative
az policy set-definition create \
--name 'production-governance' \
--display-name 'Production Environment Governance' \
--definitions @policy-set.json
Implement Cost Controls
- Set budgets at subscription and resource group levels
- Use alerts at 50%, 80%, and 100% thresholds
- Review cost trends weekly
- Tag resources for cost allocation
- Use Azure Advisor cost recommendations
Regular Governance Reviews
- Monthly: Review policy compliance
- Monthly: Analyze cost trends and budgets
- Quarterly: Review and update tagging strategy
- Quarterly: Audit management group structure
- Annually: Review entire governance framework
Things to Avoid
❌ Don't create overly complex management group hierarchies (>4 levels) ❌ Don't apply untested policies directly to production ❌ Don't use inconsistent naming conventions across teams ❌ Don't skip tagging strategy implementation ❌ Don't ignore policy non-compliance reports ❌ Don't grant Management Group Contributor role widely ❌ Don't create hundreds of custom policies (use built-in when possible) ❌ Don't set unrealistic budgets that trigger constant alerts ❌ Don't deploy resources without required tags
✅ Do test policies in audit mode first ✅ Do document your governance decisions ✅ Do use Azure Blueprints for repeatable environments ✅ Do implement automated compliance scanning ✅ Do establish clear ownership for governance tasks ✅ Do use Resource Graph for large-scale queries ✅ Do align governance with business requirements ✅ Do educate teams on governance standards
Compliance & Regulatory Standards
Built-in Compliance Initiatives
Azure Policy includes initiatives for:
- HIPAA/HITRUST: Healthcare compliance
- PCI DSS 3.2.1: Payment card industry
- ISO 27001: Information security
- NIST SP 800-53: Federal security controls
- SOC 2: Service organization controls
- CIS Benchmarks: Security best practices
# Assign regulatory compliance initiative
az policy assignment create \
--name 'hipaa-compliance' \
--policy-set-definition '/providers/Microsoft.Authorization/policySetDefinitions/a169a624-5599-4385-a696-c8d643089fab' \
--scope /subscriptions/{subscription-id}
Monitoring & Reporting
Query Resources with Azure Resource Graph
// Find all non-compliant resources
PolicyResources
| where type == "microsoft.policyinsights/policystates"
| where properties.complianceState == "NonCompliant"
| project resourceId, policyDefinitionName, complianceState = properties.complianceState
// Find resources missing required tags
Resources
| where tags !has "Environment" or tags !has "Owner"
| project name, type, resourceGroup, location, tags
// Cost by tag
Resources
| where tags has "CostCenter"
| summarize count() by tostring(tags.CostCenter)
Cost Management Reports
# Get cost by resource group
az consumption usage list \
--start-date 2024-01-01 \
--end-date 2024-01-31 \
--query "[].{ResourceGroup:resourceGroup, Cost:pretaxCost}" \
-o table
# Get cost forecast
az consumption forecast list \
--start-date 2024-02-01 \
--end-date 2024-02-28
Related Resources
- Management Group Hierarchy
- Azure Policy Built-in Policies
- Cost Management & Budgets
- Azure Blueprints
- Resource Naming Conventions
- Set up budgets and alerts
- Regular policy compliance reviews