Azure Policy Compliance Monitoring: A Solution in Bicep


This bicep code is developed to automate deployment of a Azure Non-Compliance resource monitoring solution. The solution is a split solution with bicep code creating the solution with the following sequence

  1. Create all resources except Event Grid Topic and Subscription
  2. Deploy the Azure Function (Manual or via AZ CLI / Azure Pipeline / VSCode)
  3. Create the Event Grid Topic and Subscription

Resources details

The list of resources created by this Bicep Project are as follows : -

  • Log Analytics Workspace
  • Event Grid Topic and Subscription
  • Function App (Triggered Manually using AZ CLI or from VSCode)
  • Azure Monitor Alert Rule
  • Storage Account
  • Azure Monitor Metrics
  • Key Vault


Here’s a rough diagram of the resources it creates

Understanding the Code

The main.bicep file targets the scope

targetScope = 'subscription'
param policyMonitorData object
module PolicyMonitorFunctionAppDep 'deploymentZone.bicep' = [for (rg, i) in policyMonitorData.resourceGroupArray: {
name: '${policyMonitorData.client}-PolicyMonitorFunctionAppDeployment-${i}'
params: {
commonTags: policyMonitorData.commonTagsForResources
customer: policyMonitorData.client
resourceGroup: rg
"storageAccountArray": [
"name": "logs",
"skuName": "Standard_LRS",
"logAnalytics": {
"logStorageAccountNameRef": "logs",
"logWorkSpaceNameRef": "PolicyMonitor"
"tags": {
"App": "Storage"
"name": "pmfn",
"skuName": "Standard_LRS",
"logAnalytics": {
"logStorageAccountNameRef": "logs",
"logWorkSpaceNameRef": "PolicyMonitor"
"tags": {
"App": "Storage"
resource rgs 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: 'RG-${customer}-${resourceGroup.rgName}'
location: resourceGroup.rgLocation
tags: union(commonTags, resourceGroup.tags)

Deploying the Function app

Deploying using Azure DevOps Pipeline

Define the variable. Change the functionAppName as per your requirement

functionWorkingDirectory: 'function'
functionAppName: 'FN-PolicyMonitor'
- task: ArchiveFiles@2
displayName: 'Archive Function directory'
rootFolderOrFile: $(functionWorkingDirectory)
includeRootFolder: false
archiveType: zip
archiveFile: $(Build.ArtifactStagingDirectory)/
replaceExistingArchive: true
- publish: $(Build.ArtifactStagingDirectory)/
artifact: drop
- task: AzureFunctionApp@1
displayName: 'Azure functions app deploy'
appType: functionAppLinux
appName: $(functionAppName)
package: '$(Pipeline.Workspace)/drop/'

Deploy using AZ cli

az functionapp deploy --resource-group <Reosurce group Name> --name <Function App Name> --src-path <Path to the zip file> --type zip

Deploy using Powershell

$creds = Invoke-AzureRmResourceAction -ResourceGroupName <Reosurce group Name> -ResourceType Microsoft.Web/sites/config -ResourceName <App Name>/publishingcredentials -Action list -ApiVersion 2015-08-01 -Force$username = $creds.Properties.PublishingUserName$password = $creds.Properties.PublishingPassword$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))$apiUrl = "https://<yourFunctionApp>"$filePath = "<yourFunctionName>.zip"Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method PUT -InFile $filePath -ContentType "multipart/form-data"

Install Azure CLI

You can install Azure CLI from here

Authenticate Azure CLI

Hit the command az login from Comamnd Prompt or Terminal depending upon your OS. More details can be found here

Trigger Manually

Fire the below command to create the resources using Bicep script



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store