Compliance & Governance Audit
Purpose
Assess the governance posture of Azure subscriptions by auditing policies, RBAC assignments, tagging standards, resource locks, and regulatory alignment. Produce a compliance scorecard with remediation steps.
CRITICAL formatting rule
Use Unicode emoji characters directly (🟢 🟡 🔴) in ALL output — headers, tables, findings, bullet points, everywhere. NEVER use emoji shortcodes like :red_circle:, :yellow_circle:, :green_circle:, or any :name: syntax. This applies to every section of the report without exception.
When to use this skill
- User asks "are we compliant?"
- User asks about governance, policy violations, or audit readiness
- Pre-audit preparation (SOC2, ISO 27001, HIPAA, etc.)
- Monthly governance review
Pre-check
Confirm with the user:
- Scope: which subscriptions/management groups
- Compliance framework (if any): SOC2, ISO 27001, HIPAA, PCI-DSS, CIS Benchmarks, or general best practices
- Any known exceptions or waivers
Audit procedure
Step 1: Azure Policy compliance
Check overall policy compliance state.
az policy state summarize --query "value[].{policy:policyDefinitionName, nonCompliant:nonCompliantResources}" -o table
- List all non-compliant resources grouped by policy
- Identify policies in "audit" mode that should be "deny"
- Check for orphaned policy assignments (assigned but no effect)
- Verify initiative assignments for regulatory frameworks (CIS, NIST, etc.)
Report:
- Total policies assigned
- % compliant
- Top 5 violated policies with resource count
Step 2: RBAC review
Audit role assignments for least-privilege violations.
az role assignment list --all --query "[].{principal:principalName, role:roleDefinitionName, scope:scope}" -o table
- Owner count: Flag if > 3 Owners at subscription level
- Contributor sprawl: List all Contributor assignments — flag service principals with Contributor when a custom role would suffice
- Classic admins: Check for legacy co-administrators
az role assignment list --include-classic-administrators -o table - Guest users with privileged roles: Flag external identities with Owner/Contributor
- Stale assignments: Cross-reference with sign-in logs — flag principals that haven't signed in for 90+ days
- Custom roles: Review custom role definitions for overly broad permissions (e.g.,
*actions)
Step 3: Tagging compliance
Check mandatory tags across all resources.
Define expected mandatory tags (confirm with user or use defaults):
environment(prod/staging/dev/test)owner(team or individual)cost-center(billing code)application(workload name)
az resource list --query "[?tags.environment==null || tags.owner==null].{name:name, type:type, rg:resourceGroup, tags:tags}" -o table
Report:
- % of resources with all mandatory tags
- Top offending resource groups
- Resources with no tags at all
Step 4: Resource locks
Check critical resources for delete/read-only locks.
az lock list --query "[].{name:name, level:level, resource:resourceId}" -o table
- Verify production databases have delete locks
- Verify production storage accounts have delete locks
- Verify networking resources (VNets, ExpressRoute) have locks
- Flag production resources without any lock
Step 5: Naming conventions
Analyze resource naming patterns.
- Extract all resource names and types
- Check against Azure naming conventions (e.g.,
rg-,vnet-,vm-,st,kv-) - Flag resources that don't follow a consistent pattern
- Report % compliance with naming standards
Step 6: Network governance
- Check for resources with public endpoints that should be private
- Verify NSG flow logs are enabled
- Check for Network Watcher in all active regions
- Verify DDoS protection on VNets with public-facing resources
Step 7: Diagnostic settings
- Check that all critical resources have diagnostic settings enabled
- Verify logs flow to a central Log Analytics workspace
- Check Activity Log export at subscription level
az monitor diagnostic-settings subscription list --subscription <id> -o table
Scoring model
| Rating | Meaning |
|---|---|
| 🟢 Compliant | Meets standard, no action needed |
| 🟡 Partial | Partially implemented, needs improvement |
| 🔴 Non-compliant | Missing or misconfigured, action required |
Reminder: use the actual Unicode characters 🟢 🟡 🔴 above, never shortcodes.
Accepted exceptions (optional)
If the user provides a list of accepted exceptions, do not flag those items. Instead, note them in the report as Accepted Exception with the reason provided.
Example format the user may provide:
| Check | Reason |
|---|---|
| 2.1 Owner count | Founding engineers require Owner for break-glass access |
| 3.1 Tagging compliance | Legacy resource groups exempt until Q3 migration |
| 4.2 Production locks | Terraform-managed resources use state locking instead |
When exceptions are provided:
- Skip the flagged checks in scoring
- List them in a separate "Accepted Exceptions" section at the end of the report
- Recalculate the overall score excluding excepted checks
Expected output
Report header (mandatory — use this exact format)
Compliance & Governance Audit Report
| Field | Value |
|---|---|
| Subscription | (name + ID) |
| Assessment Date | YYYY-MM-DD |
| Overall Score | XX% |
Governance scorecard
| Area | Status | Compliant | Partial | Non-compliant | Score |
|---|---|---|---|---|---|
| Azure Policy | 🟡 | X | Y | Z | % |
| RBAC | 🔴 | ... | ... | ... | % |
| Tagging | 🟡 | ... | ... | ... | % |
| Resource Locks | 🔴 | ... | ... | ... | % |
| Naming | 🟢 | ... | ... | ... | % |
| Network Gov. | 🟡 | ... | ... | ... | % |
| Diagnostics | 🟡 | ... | ... | ... | % |
| Overall | % |
Critical findings (act now)
Items that represent immediate risk or audit failure.
Remediation plan
For each finding:
- What's wrong
- Why it matters
- How to fix it (with az cli command or portal steps)
- Use
GetAzCliHelpto validate the command syntax before suggesting - Include the official Microsoft Learn documentation link
- Estimated effort
- Priority (Critical/High/Medium/Low)
References
- Azure Policy: https://learn.microsoft.com/en-us/azure/governance/policy/overview
- RBAC Best Practices: https://learn.microsoft.com/en-us/azure/role-based-access-control/best-practices
- Resource Tagging: https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources
- Resource Locks: https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/lock-resources
- Naming Conventions: https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/naming-and-tagging
Regulatory mapping (if framework specified)
Map findings to specific controls (e.g., SOC2 CC6.1, ISO 27001 A.9.2.3).
Sample output
The following is a redacted example of what the report looks like when run against a subscription.
Compliance & Governance Audit Report
| Field | Value |
|---|---|
| Subscription | contoso-prod-001 (a1b2c3d4-e5f6-7890-abcd-ef1234567890) |
| Assessment Date | 2026-07-15 |
| Overall Score | 61% |
Governance scorecard
| Area | Status | Compliant | Partial | Non-compliant | Score |
|---|---|---|---|---|---|
| Azure Policy | 🟡 | 18 | 5 | 3 | 69% |
| RBAC | 🔴 | 2 | 1 | 3 | 33% |
| Tagging | 🟡 | 45 | 12 | 8 | 69% |
| Resource Locks | 🔴 | 1 | 0 | 3 | 25% |
| Naming | 🟢 | 52 | 6 | 2 | 87% |
| Network Gov. | 🟡 | 3 | 1 | 1 | 60% |
| Diagnostics | 🟡 | 4 | 2 | 1 | 57% |
| Overall | 61% |
Critical findings (sample)
| # | Finding | Area | Severity |
|---|---|---|---|
| 1 | 6 subscription-level Owners detected (limit: 3) | RBAC | 🔴 Critical |
| 2 | 2 guest users with Contributor role on production | RBAC | 🔴 Critical |
| 3 | SQL Server sql-contoso-prod has no delete lock |
Resource Locks | 🔴 High |
| 4 | 8 resources in rg-app-prod missing cost-center tag |
Tagging | 🟡 Medium |
Remediation guidance (sample)
# Remove excess Owner assignments
az role assignment delete --assignee user@external.com --role Owner --scope /subscriptions/a1b2c3d4-...
# Add delete lock to production SQL Server
az lock create --name CanNotDelete --resource-group rg-data-prod --resource sql-contoso-prod --resource-type Microsoft.Sql/servers --lock-type CanNotDelete
# Tag resources with missing cost-center
az resource tag --ids /subscriptions/.../resourceGroups/rg-app-prod/providers/Microsoft.Web/sites/app-api-prod --tags cost-center=CC-1234 environment=prod owner=platform-team