OBED OWUSU
Engineering deep dive · Real Bicep · Real KQL · Real CLI evidence

Cloud Policy Compliance Dashboard. Real implementation details behind the Azure governance observability platform.

This page documents the live implementation used in the project: custom Azure Policy definitions, management-group initiative assignment, workbook deployment, Log Analytics KQL, alert rule construction, remediation identity and RBAC, and the exact CLI path used to validate detection, alerting, and remediation end to end.

Bicep Azure Policy Workbook JSON KQL Azure Monitor alerts CLI validation evidence
← Back to project overview
Policy states queried from arg("").PolicyResources Assignment identity used for remediation Final validation proved automatic hardening + restored compliance
Sections
Implementation summary
Management scope
Custom policy initiative assigned at mg-platform
Subscription layer
rg-governance-core with workspace, workbook, alerts
Detection query
arg("").PolicyResources + policy state filtering
Final remediation
allowBlobPublicAccess = false via Azure Policy modify
GitHub / local repo → Bicep deployment → mg-platform policy baseline
→ workbook + alerts in rg-governance-core
→ non-compliance detected → alert email
→ remediation task → storage hardened → policy compliant

Explore the real implementation

These tabs use the same structure as the project build itself: policy definitions and initiative wiring, workbook and KQL layer, alerting logic, remediation configuration, and the CLI validation path that proved the platform worked in practice.

Bicep – management-group baseline deployment

The main management-group template orchestrates the baseline: audit policy, remediation policy, initiative wiring, and assignment. This is the central entry point that turned the project into a reusable governance platform instead of a manual portal build.

mg/main-mg-platform.bicep managementGroup scope initiative + assignment
mg/main-mg-platform.bicep
targetScope = 'managementGroup'

@description('Management group ID where the governance baseline will be deployed.')
param mgId string

module policyPublicNetworkAccess './policy-public-network-access.bicep' = {
  name: 'policy-public-network-access'
  scope: managementGroup(mgId)
  params: {}
}

module policyRemediateStorage './policy-remediate-storage-network-default-deny.bicep' = {
  name: 'policy-remediate-storage-disable-blob-public-access'
  scope: managementGroup(mgId)
  params: {}
}

module initiativeCloudGovernance './initiative-cloud-governance.bicep' = {
  name: 'initiative-cloud-governance'
  scope: managementGroup(mgId)
  params: {
    publicNetworkAuditPolicyDefinitionId: policyPublicNetworkAccess.outputs.policyDefinitionId
    publicNetworkRemediationPolicyDefinitionId: policyRemediateStorage.outputs.policyDefinitionId
  }
}

module assignmentCloudGovernance './assignment-cloud-governance.bicep' = {
  name: 'assignment-cloud-governance'
  scope: managementGroup(mgId)
  params: {
    initiativeDefinitionId: initiativeCloudGovernance.outputs.initiativeDefinitionId
  }
}

output policyDefinitionId string = policyPublicNetworkAccess.outputs.policyDefinitionId
output remediationPolicyDefinitionId string = policyRemediateStorage.outputs.policyDefinitionId
output initiativeDefinitionId string = initiativeCloudGovernance.outputs.initiativeDefinitionId
output assignmentId string = assignmentCloudGovernance.outputs.assignmentId
output assignmentPrincipalId string = assignmentCloudGovernance.outputs.assignmentPrincipalId

Bicep – final remediation policy definition

The final working remediation path used Azure Policy modify against Storage Account blob public access. This replaced an earlier remediation approach that did not produce a reliable remediable target.

modify effect allowBlobPublicAccess roleDefinitionIds
mg/policy-remediate-storage-network-default-deny.bicep
targetScope = 'managementGroup'

@description('Name of the remediation policy definition.')
param policyName string = 'modify-storage-disable-blob-public-access'

@description('Display name shown in Azure Policy.')
param policyDisplayName string = 'Remediate Storage Accounts to disable blob public access'

@description('Description for the remediation policy.')
param policyDescription string = 'Modifies Storage Accounts so allowBlobPublicAccess is set to false when found non-compliant.'

resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2025-03-01' = {
  name: policyName
  properties: {
    policyType: 'Custom'
    mode: 'Indexed'
    displayName: policyDisplayName
    description: policyDescription
    metadata: {
      category: 'Storage'
      version: '2.0.0'
    }
    parameters: {}
    policyRule: {
      if: {
        allOf: [
          {
            field: 'type'
            equals: 'Microsoft.Storage/storageAccounts'
          }
          {
            field: 'Microsoft.Storage/storageAccounts/allowBlobPublicAccess'
            notEquals: false
          }
        ]
      }
      then: {
        effect: 'modify'
        details: {
          roleDefinitionIds: [
            '/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab'
          ]
          conflictEffect: 'audit'
          operations: [
            {
              operation: 'addOrReplace'
              field: 'Microsoft.Storage/storageAccounts/allowBlobPublicAccess'
              value: false
            }
          ]
        }
      }
    }
  }
}

output policyDefinitionId string = policyDefinition.id
output policyDefinitionName string = policyDefinition.name

Bicep – workbook resource module

The workbook is also deployed as code. That matters because the visual layer stays versioned in the same repo as the policy and alert logic.

infra/modules/workbook.bicep
targetScope = 'resourceGroup'

@description('Location for the workbook resource.')
param location string

@description('Name of the workbook.')
param workbookDisplayName string = 'Cloud Policy Compliance Dashboard'

@description('Resource ID of the Log Analytics workspace.')
param logAnalyticsWorkspaceId string

@description('Serialized workbook data JSON.')
param workbookData string

resource workbook 'Microsoft.Insights/workbooks@2023-06-01' = {
  name: guid(workbookDisplayName, resourceGroup().id)
  location: location
  kind: 'shared'
  properties: {
    displayName: workbookDisplayName
    sourceId: logAnalyticsWorkspaceId
    category: 'workbook'
    serializedData: workbookData
  }
}

output workbookId string = workbook.id
output workbookName string = workbook.name

Workbook JSON – non-compliance donut and summary table

The workbook was reworked to align with the live query source. The final JSON uses arg("").PolicyResources for policy state data and includes the visual donut/table combination used in the final screenshots.

workbooks/policy-dashboard.json (core fragments)
{
  "version": "Notebook/1.0",
  "items": [
    {
      "type": 1,
      "content": {
        "json": "# Cloud Policy Compliance Dashboard\n\nThis workbook provides a governance-focused view of Azure Policy compliance, non-compliant resources, and policy-related activity across environments."
      },
      "name": "text-intro"
    },
    {
      "type": 3,
      "content": {
        "version": "KqlItem/1.0",
        "query": "arg(\"\").PolicyResources\n| where type =~ \"microsoft.policyinsights/policystates\"\n| extend complianceState = tostring(properties.complianceState)\n| where complianceState == \"NonCompliant\"\n| extend policyDefinitionName = tostring(properties.policyDefinitionName)\n| summarize nonCompliantResources = count() by policyDefinitionName\n| order by nonCompliantResources desc",
        "title": "Non-Compliance by Policy Definition",
        "resourceType": "microsoft.operationalinsights/workspaces",
        "visualization": "piechart"
      },
      "name": "noncompliance-donut"
    }
  ]
}

KQL – final policy state query used for workbook and alerts

This was the decisive query change in the build. Using arg("").PolicyResources fixed the workbook and alert path after earlier attempts using the wrong table name failed.

arg("").PolicyResources Policy states Reusable for workbook + alerts
Core policy state detection query
arg("").PolicyResources
| where type =~ "microsoft.policyinsights/policystates"
| extend complianceState = tostring(properties.complianceState)
| where complianceState == "NonCompliant"

KQL files stored in repo

The project kept its operational queries as source files in the repository so that workbook logic and alert logic stayed aligned with the codebase.

kql/non-compliance-summary.kql
PolicyResources
| where type =~ 'Microsoft.PolicyInsights/PolicyStates'
| where tostring(properties.complianceState) == 'NonCompliant'
| extend
    assignmentName = tostring(properties.policyAssignmentName),
    definitionName = tostring(properties.policyDefinitionName),
    initiativeName = tostring(properties.policySetDefinitionName),
    resourceId = tostring(properties.resourceId),
    resourceType = tostring(properties.resourceType),
    resourceLocation = tostring(properties.resourceLocation),
    timestamp = todatetime(properties.timestamp)
| summarize nonCompliantResources = count() by assignmentName, initiativeName, definitionName, resourceType, resourceLocation
| order by nonCompliantResources desc
kql/policy-deny-events.kql
AzureActivity
| where CategoryValue =~ 'Policy'
| where ActivityStatusValue in~ ('Failure', 'Succeeded')
| where OperationNameValue has 'policy'
| extend
    resourceId = _ResourceId,
    caller = Caller,
    operationName = OperationNameValue,
    activityStatus = ActivityStatusValue,
    subscriptionId = SubscriptionId,
    resourceGroup = ResourceGroup,
    eventTime = TimeGenerated
| project eventTime, caller, operationName, activityStatus, subscriptionId, resourceGroup, resourceId
| order by eventTime desc

Alerting – non-compliance query and validation path

The production-proof alert path was the non-compliance alert. It fired successfully, showed up in alert history, and delivered an email notification via the action group. The activity-based alert path was explored but not kept as the primary evidence path because the live behavior did not validate consistently enough for the final story.

Working alert query
arg("").PolicyResources
| where type =~ "microsoft.policyinsights/policystates"
| extend complianceState = tostring(properties.complianceState)
| where complianceState == "NonCompliant"

This query crossed a threshold greater than zero and fired the alert-policy-noncompliance rule, which was then visible in alert history and email evidence.

Diagnostic settings – why they mattered

Alert validation also required the subscription Activity Log to be streamed into Log Analytics. Without that, activity investigations and some query experiments had no underlying data to work from.

Portal configuration validated during build
Name: diag-activity-to-law

Categories selected:
- Administrative
- Policy
- Security
- ServiceHealth
- Recommendation
- ResourceHealth

Destination:
- Send to Log Analytics workspace
- Workspace: law-governance-core

Remediation design – final working pattern

Remediation only became reliable after two changes: the initiative assignment was recreated with a system-assigned managed identity, and the remediation policy was redesigned to target a supported Storage Account property that produced a clean modify-based correction.

System-assigned identity Contributor RBAC Modify effect allowBlobPublicAccess
Assignment identity and RBAC (live CLI)
ASSIGNMENT_PRINCIPAL_ID="223eac89-e62f-426c-8aea-99c252c3112a"
SUB_ID=$(az account show --query id -o tsv)

az role assignment create \
  --assignee-object-id "$ASSIGNMENT_PRINCIPAL_ID" \
  --assignee-principal-type ServicePrincipal \
  --role Contributor \
  --scope /subscriptions/$SUB_ID

Remediation task – management-group execution

The remediation task was created directly against the management-group assignment and the initiative reference ID. The final successful run executed two deployments and returned the environment to compliant state.

Remediation task creation (live CLI)
az policy remediation create \
  --management-group mg-platform \
  --name remediate-storage-default-deny \
  --policy-assignment /providers/Microsoft.Management/managementGroups/mg-platform/providers/Microsoft.Authorization/policyAssignments/asg-cloud-gov-base \
  --definition-reference-id remediateStorageDefaultDeny
Successful remediation result (live CLI)
{
  "deploymentStatus": {
    "failedDeployments": 0,
    "successfulDeployments": 2,
    "totalDeployments": 2
  },
  "provisioningState": "Succeeded"
}

CLI evidence – deployment sequence used in the live build

These are the exact command patterns used repeatedly through the build to deploy the subscription governance layer, deploy the management-group baseline, and validate outputs.

Subscription governance deployment
az deployment sub create \
  --name governance-core-sub-deploy \
  --location uksouth \
  --template-file infra/governance-core-subscription.bicep \
  --parameters alertEmailAddress=owusuobed15@yahoo.com
Management-group baseline deployment
az deployment mg create \
  --name mg-platform-baseline-deploy \
  --management-group-id mg-platform \
  --location uksouth \
  --template-file mg/main-mg-platform.bicep \
  --parameters mgId=mg-platform

CLI evidence – final verification commands

These commands were the final proof that the platform completed the remediation story and restored compliance.

Final property + compliance verification
az storage account show \
  --name stnoncompliance7348 \
  --resource-group rg-governance-core \
  --query "allowBlobPublicAccess" \
  -o tsv

az policy state list \
  --resource-group rg-governance-core \
  --query "[?contains(resourceId, 'stnoncompliance7348')].{definition:policyDefinitionName, referenceId:policyDefinitionReferenceId, compliance:complianceState}" \
  -o table
Observed live result
false

Definition                                 ReferenceId                      Compliance
-----------------------------------------  -------------------------------  ------------
modify-storage-disable-blob-public-access  remediatestoragedefaultdeny      Compliant
audit-storage-public-network-access        auditstoragepublicnetworkaccess  Compliant
modify-storage-network-default-deny        remediatestoragedefaultdeny      Compliant

CLI evidence screenshots included in package

The project package also includes rendered terminal screenshots for the final remediation run and the final verification output so the website can show the live command evidence visually.

images/cli-remediation-succeeded.png images/cli-final-verification.png