Skip to main content

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

ServicePurposeTeam Owner
Management GroupsHierarchical organization of subscriptionsGovernance Team
Azure PolicyCompliance automation and standards enforcementGovernance Team
Azure BlueprintsRepeatable environment definitionsGovernance Team
Cost ManagementBudget tracking and cost optimizationGovernance & Finance Teams
Resource GraphQuery and analyze resources at scaleOperations Team
Azure AdvisorBest practice recommendationsAll 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 Group
  • kv - Key Vault
  • st - Storage Account
  • vm - Virtual Machine
  • vnet - Virtual Network
  • snet - Subnet
  • nsg - Network Security Group
  • aks - Azure Kubernetes Service
  • sql - SQL Server
  • sqldb - SQL Database
  • app - 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

Governance Framework

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