Azure Policy Compliance Monitoring: A Solution in Bicep


  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

  • 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


Understanding the Code

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

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

Authenticate Azure CLI

Trigger Manually




Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Exploring the IOTA signing process

The Observer Pattern

Do you know what .Net framework is ?

Why Software Engineering is really hard for introverts/socially anxious

Debugging is an Art

CyberKongz Weekly: November 15, 2021

Useful OSCP Notes & Commands

Value Type Vs Reference Type(Dive Deep) — Swift

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
Arlan Nugara

Arlan Nugara

More from Medium

Luigi Manzi — Senior editor and director

Azure VPN P2S (OpenVPN with Azure AD) unable to resolve hostnames while connected to Azure VPN…

Add a Custom Domain to Azure Website