Framework/Configurations/PolicySetup/MonitoringDashboard.json
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "SubscriptionId": { "type": "string", "metadata": { "description": "Subscrption Id where Org Policy is setup and monitoring dashboard needs to be setup." } }, "ResourceGroups": { "type": "string", "metadata": { "description": "ResourceGroup name where Org Policy is present and monitoring dashboard resource need to be setup." } }, "AIName": { "type": "string", "metadata": { "description": "Org Policy application insight Resource name." } }, "DashboardName":{ "type": "string", "metadata": { "description": "Monitoring dashboard resource name" }, "defaultValue" : "DevOpsKitMonitoring" }, "DashboardTitle":{ "type": "string", "metadata": { "description": "Monitoring dashboard Title" }, "defaultValue" : "DevOps Kit Monitoring Dashboard" }, "Location":{ "type": "string", "metadata": { "description": "Monitoring dashboard resource location" }, "defaultValue" : "DevOps Kit Monitoring Dashboard" } }, "resources": [ { "properties": { "lenses": { "0": { "order": 0, "parts": { "0": { "position": { "x": 0, "y": 0, "colSpan": 5, "rowSpan": 4 }, "metadata": { "inputs": [], "type": "Extension[azure]/HubsExtension/PartType/MarkdownPart", "settings": { "content": { "settings": { "content": "__How to use this dashboard:__\n\nThis dashboard lets you monitor the operations for various DevOps Kit workflows at your org. Each blade lets you monitor the health of some aspect of your DevOps Kit deployment (e.g., CA issues, anomalous control drifts, evaluation errors, etc.). You can click on the 'Open Chart in Analytics' link at the top right corner of any view to see the underlying data/query. (Note that some views will show 'error retrieving data' initially.)\n\n__Useful Links__: \n<br>\n[Updates on Org Policy](https://aka.ms/devopskit/orgpolicy/updates)\n<br>[Release Notes](https://aka.ms/devopskit/releasenotes)\n<br>[Org Policy Docs](https://aka.ms/devopskit/orgpolicy/docs)\n<br>[DevOps Kit Docs](http://aka.ms/devopskit/docs)\n<br>[Support](mailto:azsksup@microsoft.com)\n\n", "title": "Monitoring your Org AzSK Setup", "subtitle": "Instructions" } } } } }, "1": { "position": { "x": 5, "y": 0, "colSpan": 6, "rowSpan": 4 }, "metadata": { "inputs": [ { "name": "ComponentId", "value": { "SubscriptionId": "[parameters('SubscriptionId')]", "ResourceGroup": "[parameters('ResourceGroups')]", "Name": "[parameters('AIName')]" } }, { "name": "Query", "value": "customEvents\r\n| where timestamp > ago(15d) and name == \"Control Scanned\" and customDimensions.ScanSource== \"Runbook\"\r\n| summarize count() by bin(timestamp, 1d),tostring(customDimensions.SubscriptionId)\r\n| summarize TotalCount=count() by timestamp\r\n| render barchart\n" }, { "name": "Dimensions", "value": { "xAxis": { "name": "timestamp", "type": "DateTime" }, "yAxis": [ { "name": "TotalCount", "type": "Int64" } ], "splitBy": [], "aggregation": "Sum" } }, { "name": "Version", "value": "1.0" }, { "name": "DashboardId", "value": "[resourceId(parameters('ResourceGroups'),'Microsoft.Portal/dashboards', parameters('DashboardName'))]" }, { "name": "resourceTypeMode", "value": "components" } ], "type": "Extension/AppInsightsExtension/PartType/AnalyticsBarChartPart", "settings": { "content": { "dashboardPartTitle": "CA - Subs Reporting Scans", "dashboardPartSubTitle": "Number of subscriptions reporting CA scans" } }, "asset": { "idInputName": "ComponentId", "type": "ApplicationInsights" } } }, "2": { "position": { "x": 11, "y": 0, "colSpan": 6, "rowSpan": 4 }, "metadata": { "inputs": [ { "name": "ComponentId", "value": { "SubscriptionId": "[parameters('SubscriptionId')]", "ResourceGroup": "[parameters('ResourceGroups')]", "Name": "[parameters('AIName')]" } }, { "name": "Query", "value": "//Negative Drift\nlet ControlResults = customEvents\n| where timestamp < ago(2d) and timestamp >= ago(4d)\n| where name == \"Control Scanned\" and customDimensions.HasAttestationReadPermissions == \"True\" and customDimensions.HasRequiredAccess == \"True\"\n| summarize arg_max(timestamp, *) by tostring(customDimensions.SubscriptionId), tostring(customDimensions.SubscriptionName), tostring(customDimensions.ControlId)\n| project tostring(customDimensions.SubscriptionId), tostring(customDimensions.SubscriptionName),tostring(customDimensions.ResourceId), tostring(customDimensions.ControlId), Oldresult =tostring(customDimensions.VerificationResult)\n| join\n(\n customEvents\n | where timestamp >= ago(2d)\n | where name == \"Control Scanned\" and customDimensions.HasAttestationReadPermissions == \"True\" and customDimensions.HasRequiredAccess == \"True\"\n | summarize arg_max(timestamp, *) by tostring(customDimensions.SubscriptionId), tostring(customDimensions.SubscriptionName), tostring(customDimensions.ControlId)\n | project tostring(customDimensions.SubscriptionId), tostring(customDimensions.SubscriptionName),tostring(customDimensions.ResourceId), tostring(customDimensions.ControlId), Latestresult = tostring(customDimensions.VerificationResult)\n)\non customDimensions_SubscriptionId, customDimensions_SubscriptionName,customDimensions_ResourceId, customDimensions_ControlId\n| project tostring(customDimensions_SubscriptionId), tostring(customDimensions_SubscriptionName),tostring(customDimensions_ResourceId), tostring(customDimensions_ControlId),Oldresult,Latestresult;\nlet OldScan = ControlResults\n| where Oldresult == \"Passed\"\n| summarize OldScanCount = count() by tostring(customDimensions_ControlId);\nlet LatestScan = ControlResults\n| where Latestresult == \"Passed\"\n| summarize LatestScanCount = count() by tostring(customDimensions_ControlId);\nOldScan\n| join\n(\n LatestScan\n)\non customDimensions_ControlId\n| project ControlId=tostring(customDimensions_ControlId),OldStatusCount=OldScanCount,LatestStatusCount=LatestScanCount\n| where OldStatusCount != LatestStatusCount and LatestStatusCount < OldStatusCount\n| extend Change =OldStatusCount-LatestStatusCount\n| order by Change desc\n| project ControlId,OldStatusCount,LatestStatusCount,Change\n" }, { "name": "Version", "value": "1.0" }, { "name": "DashboardId", "value": "[resourceId(parameters('ResourceGroups'),'Microsoft.Portal/dashboards', parameters('DashboardName'))]" }, { "name": "PartId", "value": "038d1915-4387-402f-88e1-0b0f029afc36" }, { "name": "PartTitle", "value": "Analytics" }, { "name": "PartSubTitle", "value": "azsdkappinsightsms" }, { "name": "resourceTypeMode", "value": "components" } ], "type": "Extension/AppInsightsExtension/PartType/AnalyticsGridPart", "settings": { "content": { "dashboardPartTitle": "Negative Drift for Controls", "dashboardPartSubTitle": "Shows controls drifting from 'passed' to 'not passed' in the 2 Days" } }, "asset": { "idInputName": "ComponentId", "type": "ApplicationInsights" } } }, "3": { "position": { "x": 17, "y": 0, "colSpan": 6, "rowSpan": 4 }, "metadata": { "inputs": [ { "name": "ComponentId", "value": { "SubscriptionId": "[parameters('SubscriptionId')]", "ResourceGroup": "[parameters('ResourceGroups')]", "Name": "[parameters('AIName')]" } }, { "name": "Query", "value": "exceptions\n| where timestamp > ago(7d)\n| summarize Count=count() by tostring(outerMessage),Date=bin(timestamp,1d)\n" }, { "name": "Dimensions", "value": { "xAxis": { "name": "Date", "type": "DateTime" }, "yAxis": [ { "name": "Count", "type": "Int64" } ], "splitBy": [ { "name": "outerMessage", "type": "String" } ], "aggregation": "Sum" } }, { "name": "Version", "value": "1.0" }, { "name": "DashboardId", "value": "[resourceId(parameters('ResourceGroups'),'Microsoft.Portal/dashboards', parameters('DashboardName'))]" }, { "name": "resourceTypeMode", "value": "components" } ], "type": "Extension/AppInsightsExtension/PartType/AnalyticsBarChartPart", "settings": { "content": { "dashboardPartTitle": "Exceptions Summary", "dashboardPartSubTitle": "Errors during DevOps Kit cmdlet execution" } }, "asset": { "idInputName": "ComponentId", "type": "ApplicationInsights" } } }, "4": { "position": { "x": 23, "y": 0, "colSpan": 6, "rowSpan": 4 }, "metadata": { "inputs": [ { "name": "ComponentId", "value": { "SubscriptionId": "[parameters('SubscriptionId')]", "ResourceGroup": "[parameters('ResourceGroups')]", "Name": "[parameters('AIName')]" } }, { "name": "Query", "value": "customEvents\r\n| where timestamp > ago(2d) and name == \"Control Scanned\" \r\n| summarize arg_max(timestamp, *) \r\n| project OrgAzSKVersion=tostring(customDimensions.OrgVersion),LatestAzSKVersion=tostring(tostring(customDimensions.LatestVersion))\r\n" }, { "name": "Version", "value": "1.0" }, { "name": "DashboardId", "value": "[resourceId(parameters('ResourceGroups'),'Microsoft.Portal/dashboards', parameters('DashboardName'))]" }, { "name": "resourceTypeMode", "value": "components" } ], "type": "Extension/AppInsightsExtension/PartType/AnalyticsGridPart", "settings": { "content": { "PartTitle": "Current Org AzSK Version Vs Latest AzSK Version", "PartSubTitle": "To update org version refer: http://aka.ms/deveopskit/updateOrgAzSKVersion" } }, "asset": { "idInputName": "ComponentId", "type": "ApplicationInsights" } } }, "5": { "position": { "x": 0, "y": 4, "colSpan": 5, "rowSpan": 4 }, "metadata": { "inputs": [ { "name": "resourceGroup", "isOptional": true }, { "name": "id", "value": "[concat(subscription().id,'/resourceGroups/',parameters('ResourceGroups'))]", "isOptional": true } ], "type": "Extension/HubsExtension/PartType/ResourceGroupMapPinnedPart" } }, "6": { "position": { "x": 5, "y": 4, "colSpan": 6, "rowSpan": 4 }, "metadata": { "inputs": [ { "name": "ComponentId", "value": { "SubscriptionId": "[parameters('SubscriptionId')]", "ResourceGroup": "[parameters('ResourceGroups')]", "Name": "[parameters('AIName')]" } }, { "name": "Query", "value": "customEvents\r\n| where timestamp > ago(90d) \r\n| where customDimensions.ScanSource ==\"Runbook\" and name == \"Control Scanned\"\r\n| summarize LastScanDate = max(timestamp) by tostring(customDimensions.SubscriptionId),tostring(customDimensions.SubscriptionName)\r\n| where LastScanDate <= ago(2d)\r\n| order by LastScanDate desc \r\n| project SubId = customDimensions_SubscriptionId,SubName= customDimensions_SubscriptionName,LastScanDate\n" }, { "name": "Version", "value": "1.0" }, { "name": "DashboardId", "value": "[resourceId(parameters('ResourceGroups'),'Microsoft.Portal/dashboards', parameters('DashboardName'))]" }, { "name": "resourceTypeMode", "value": "components" } ], "type": "Extension/AppInsightsExtension/PartType/AnalyticsGridPart", "settings": { "content": { "dashboardPartTitle": "CA - No Recent Scans", "dashboardPartSubTitle": "Subscriptions that have not reported scan events in last the 2 days" } }, "asset": { "idInputName": "ComponentId", "type": "ApplicationInsights" } } }, "7": { "position": { "x": 11, "y": 4, "colSpan": 6, "rowSpan": 4 }, "metadata": { "inputs": [ { "name": "ComponentId", "value": { "SubscriptionId": "[parameters('SubscriptionId')]", "ResourceGroup": "[parameters('ResourceGroups')]", "Name": "[parameters('AIName')]" } }, { "name": "Query", "value": "//Positive Drift\nlet ControlResults = customEvents\n| where timestamp < ago(2d) and timestamp >= ago(4d)\n| where name == \"Control Scanned\" and customDimensions.HasAttestationReadPermissions == \"True\" and customDimensions.HasRequiredAccess == \"True\"\n| summarize arg_max(timestamp, *) by tostring(customDimensions.SubscriptionId), tostring(customDimensions.SubscriptionName), tostring(customDimensions.ControlId)\n| project tostring(customDimensions.SubscriptionId), tostring(customDimensions.SubscriptionName),tostring(customDimensions.ResourceId), tostring(customDimensions.ControlId), oldresult =tostring(customDimensions.VerificationResult)\n| join\n(\n customEvents\n | where timestamp >= ago(2d)\n | where name == \"Control Scanned\" and customDimensions.HasAttestationReadPermissions == \"True\" and customDimensions.HasRequiredAccess == \"True\"\n | summarize arg_max(timestamp, *) by tostring(customDimensions.SubscriptionId), tostring(customDimensions.SubscriptionName), tostring(customDimensions.ControlId)\n | project tostring(customDimensions.SubscriptionId), tostring(customDimensions.SubscriptionName),tostring(customDimensions.ResourceId), tostring(customDimensions.ControlId), Latestresult = tostring(customDimensions.VerificationResult)\n)\non customDimensions_SubscriptionId, customDimensions_SubscriptionName,customDimensions_ResourceId, customDimensions_ControlId\n| project tostring(customDimensions_SubscriptionId), tostring(customDimensions_SubscriptionName),tostring(customDimensions_ResourceId), tostring(customDimensions_ControlId),oldresult,Latestresult;\nlet oldScan = ControlResults\n| where oldresult == \"Passed\"\n| summarize oldScanCount = count() by tostring(customDimensions_ControlId);\nlet LatestScan = ControlResults\n| where Latestresult == \"Passed\"\n| summarize LatestScanCount = count() by tostring(customDimensions_ControlId);\noldScan\n| join\n(\n LatestScan\n)\non customDimensions_ControlId\n| project ControlId=tostring(customDimensions_ControlId),OldStatusCount=oldScanCount,LatestStatusCount=LatestScanCount\n| where OldStatusCount != LatestStatusCount and LatestStatusCount > OldStatusCount\n| extend Change =LatestStatusCount-OldStatusCount\n| order by Change desc\n| project ControlId,OldStatusCount,LatestStatusCount,Change\n" }, { "name": "Version", "value": "1.0" }, { "name": "DashboardId", "value": "[resourceId(parameters('ResourceGroups'),'Microsoft.Portal/dashboards', parameters('DashboardName'))]" }, { "name": "resourceTypeMode", "value": "components" } ], "type": "Extension/AppInsightsExtension/PartType/AnalyticsGridPart", "settings": { "content": { "dashboardPartTitle": "Positive Drift for Controls", "dashboardPartSubTitle": "Shows controls drifting from 'not passed' to 'passed' in the 2 days" } }, "asset": { "idInputName": "ComponentId", "type": "ApplicationInsights" } } }, "8": { "position": { "x": 17, "y": 4, "colSpan": 6, "rowSpan": 4 }, "metadata": { "inputs": [ { "name": "ComponentId", "value": { "SubscriptionId": "[parameters('SubscriptionId')]", "ResourceGroup": "[parameters('ResourceGroups')]", "Name": "[parameters('AIName')]" } }, { "name": "Query", "value": "customEvents\r\n| where name == \"CA Job Error\"\r\n| where timestamp > ago(7d)\r\n| extend SubId=tostring(customDimensions.SubscriptionId)\r\n| summarize Count=count() by tostring(customDimensions.ErrorRecord),Date=bin(timestamp,1d)\r\n| order by Date,Count" }, { "name": "Dimensions", "value": { "xAxis": { "name": "Date", "type": "DateTime" }, "yAxis": [ { "name": "Count", "type": "Int64" } ], "splitBy": [ { "name": "customDimensions_ErrorRecord", "type": "String" } ], "aggregation": "Sum" } }, { "name": "Version", "value": "1.0" }, { "name": "DashboardId", "value": "[resourceId(parameters('ResourceGroups'),'Microsoft.Portal/dashboards', parameters('DashboardName'))]" }, { "name": "resourceTypeMode", "value": "components" } ], "type": "Extension/AppInsightsExtension/PartType/AnalyticsBarChartPart", "settings": { "content": { "dashboardPartTitle": "CA Exceptions", "dashboardPartSubTitle": "Errors during CA runbook execution" } }, "asset": { "idInputName": "ComponentId", "type": "ApplicationInsights" } } } } } } }, "name": "[parameters('DashboardName')]", "type": "Microsoft.Portal/dashboards", "location": "[parameters('Location')]", "tags": { "hidden-title": "[parameters('DashboardTitle')]" }, "apiVersion": "2015-08-01-preview" } ] } |