diff --git a/Workbooks/AcscEssential8.json b/Workbooks/AcscEssential8.json index b9c95d2726c..1f45e0c748f 100644 --- a/Workbooks/AcscEssential8.json +++ b/Workbooks/AcscEssential8.json @@ -106,26 +106,6 @@ "resultVal": "True" } }, - { - "criteriaContext": { - "leftOperand": "Tab", - "operator": "==", - "rightValType": "static", - "rightVal": "macros", - "resultValType": "static", - "resultVal": "True" - } - }, - { - "criteriaContext": { - "leftOperand": "Tab", - "operator": "==", - "rightValType": "static", - "rightVal": "ap hardening", - "resultValType": "static", - "resultVal": "True" - } - }, { "criteriaContext": { "operator": "Default", @@ -196,6 +176,36 @@ "resultVal": "True" } }, + { + "criteriaContext": { + "leftOperand": "Tab", + "operator": "==", + "rightValType": "static", + "rightVal": "macros", + "resultValType": "static", + "resultVal": "True" + } + }, + { + "criteriaContext": { + "leftOperand": "Tab", + "operator": "==", + "rightValType": "static", + "rightVal": "ap hardening", + "resultValType": "static", + "resultVal": "True" + } + }, + { + "criteriaContext": { + "leftOperand": "Tab", + "operator": "==", + "rightValType": "static", + "rightVal": "General", + "resultValType": "static", + "resultVal": "True" + } + }, { "criteriaContext": { "operator": "Default", @@ -229,9 +239,6 @@ "multiSelect": true, "quote": "'", "delimiter": ",", - "value": [ - "value::all" - ], "typeSettings": { "additionalResourceOptions": [ "value::all" @@ -239,7 +246,10 @@ "includeAll": true, "showDefault": false }, - "defaultValue": "value::all" + "defaultValue": "value::all", + "value": [ + "value::all" + ] } ], "style": "above", @@ -258,6 +268,9 @@ "type": 9, "content": { "version": "KqlParameterItem/1.0", + "crossComponentResources": [ + "{Subscription}" + ], "parameters": [ { "id": "6d2d5f84-767c-4d51-82d5-6981e96bacdc", @@ -272,8 +285,7 @@ "additionalResourceOptions": [] }, "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources", - "value": null + "resourceType": "microsoft.resourcegraph/resources" }, { "id": "befbf593-c171-4129-b890-7e642265ed0c", @@ -336,7 +348,7 @@ } ], "style": "above", - "queryType": 0, + "queryType": 1, "resourceType": "microsoft.operationalinsights/workspaces" }, "conditionalVisibility": { @@ -1282,7 +1294,7 @@ { "type": 1, "content": { - "json": "## Health Legend (for Subscriptions)\r\n#### Healthy:\r\nHealthy Subscriptions are compliant with **all of the following** policies:\r\n- A maximum of 3 owners should be designated for subscriptions\r\n- Blocked accounts with owner permissions on Azure resources should be removed\r\n- Blocked accounts with read and write permissions on Azure resources should be removed\r\n- Deprecated accounts with owner permissions should be removed from subscriptions\r\n- External accounts with owner permissions should be removed from subscriptions\r\n- External accounts with write permissions should be removed from subscriptions\r\n- Guest accounts with owner permissions on Azure resources should be removed\r\n- Guest accounts with write permissions on Azure resources should be removed\r\n\r\n#### Unhealthy:\r\nUnhealthy Subscriptions are not compliant with **at least one** of the above policies. If the health state of at least one control is Unhealthy, the subscription will reported as Unhealthy.\r\n\r\n#### Unknown:\r\nUnknown health for Subscriptions indicate inability to retrieve compliance data for the respective policy due to missing pre-requisites. This still requires investigation and remediation to ensure required controls are applied and resources are reporting Healthy state.\r\n\r\n", + "json": "## Health Legend (for Subscriptions)\r\n#### Healthy:\r\nHealthy Subscriptions are compliant with **all of the following** policies:\r\n- A maximum of 3 owners should be designated for subscriptions\r\n- Blocked accounts with owner permissions on Azure resources should be removed\r\n- Blocked accounts with read and write permissions on Azure resources should be removed\r\n- Guest accounts with owner permissions on Azure resources should be removed\r\n- Guest accounts with write permissions on Azure resources should be removed\r\n\r\n#### Unhealthy:\r\nUnhealthy Subscriptions are not compliant with **at least one** of the above policies. If the health state of at least one control is Unhealthy, the subscription will reported as Unhealthy.\r\n\r\n#### Unknown:\r\nUnknown health for Subscriptions indicate inability to retrieve compliance data for the respective policy due to missing pre-requisites. This still requires investigation and remediation to ensure required controls are applied and resources are reporting Healthy state.\r\n\r\n", "style": "success" }, "name": "text - 1" @@ -1298,7 +1310,7 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where subscriptionId in~ ({Subscription:subid})\r\n| where name in~ (\r\n \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", // A maximum of 3 owners should be designated for subscriptions\r\n \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n// \"00c6d40b-e990-6acf-d4f3-471e747a27c4\", // Deprecated accounts should be removed from subscriptions\r\n \"e52064aa-6853-e252-a11e-dffc675689c2\", // Deprecated accounts with owner permissions should be removed from subscriptions\r\n \"c3b6ae71-f1f0-31b4-e6c1-d5951285d03d\", // External accounts with owner permissions should be removed from subscriptions\r\n// \"a8c6a4ad-d51e-88fe-2979-d3ee3c864f8b\", // External accounts with read permissions should be removed from subscriptions\r\n \"04e7147b-0deb-9796-2e5c-0336343ceb3d\", // External accounts with write permissions should be removed from subscriptions\r\n \"20606e75-05c4-48c0-9d97-add6daa2109a\", // Guest accounts with owner permissions on Azure resources should be removed\r\n// \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", // Guest accounts with read permissions on Azure resources should be removed\r\n \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\" // Guest accounts with write permissions on Azure resources should be removed\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", \"Max_3_Owners\", // A maximum of 3 owners should be designated for subscriptions\r\n name =~ \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", \"Remove_Blocked_Owner\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n name =~ \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", \"Remove_Blocked_ReadWrite\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n name =~ \"00c6d40b-e990-6acf-d4f3-471e747a27c4\", \"Remove_Deprecated_All\", // Deprecated accounts should be removed from subscriptions\r\n name =~ \"e52064aa-6853-e252-a11e-dffc675689c2\", \"Remove_Deprecated_Owner\", // Deprecated accounts with owner permissions should be removed from subscriptions\r\n name =~ \"c3b6ae71-f1f0-31b4-e6c1-d5951285d03d\", \"Remove_External_Owner\", // External accounts with owner permissions should be removed from subscriptions\r\n name =~ \"a8c6a4ad-d51e-88fe-2979-d3ee3c864f8b\", \"Remove_External_Read\", // External accounts with read permissions should be removed from subscriptions\r\n name =~ \"04e7147b-0deb-9796-2e5c-0336343ceb3d\", \"Remove_External_Write\", // External accounts with write permissions should be removed from subscriptions\r\n name =~ \"20606e75-05c4-48c0-9d97-add6daa2109a\", \"Remove_Guest_Owner\", // Guest accounts with owner permissions on Azure resources should be removed\r\n name =~ \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", \"Remove_Guest_Read\", // Guest accounts with read permissions on Azure resources should be removed\r\n name =~ \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\", \"Remove_Guest_Write\", // Guest accounts with write permissions on Azure resources should be removed\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Max_3_Owners = iff(Recommendations.Max_3_Owners == \"\", \"Unknown\", Recommendations.Max_3_Owners)\r\n| extend Remove_Blocked_Owner = iff(Recommendations.Remove_Blocked_Owner == \"\", \"Unknown\", Recommendations.Remove_Blocked_Owner)\r\n| extend Remove_Blocked_ReadWrite = iff(Recommendations.Remove_Blocked_ReadWrite == \"\", \"Unknown\", Recommendations.Remove_Blocked_ReadWrite)\r\n//| extend Remove_Deprecated_All = iff(Recommendations.Remove_Deprecated_All == \"\", \"Unknown\", Recommendations.Remove_Deprecated_All)\r\n| extend Remove_Deprecated_Owner = iff(Recommendations.Remove_Deprecated_Owner == \"\", \"Unknown\", Recommendations.Remove_Deprecated_Owner)\r\n| extend Remove_External_Owner = iff(Recommendations.Remove_External_Owner == \"\", \"Unknown\", Recommendations.Remove_External_Owner)\r\n//| extend Remove_External_Read = iff(Recommendations.Remove_External_Read == \"\", \"Unknown\", Recommendations.Remove_External_Read)\r\n| extend Remove_External_Write = iff(Recommendations.Remove_External_Write == \"\", \"Unknown\", Recommendations.Remove_External_Write)\r\n| extend Remove_Guest_Owner = iff(Recommendations.Remove_Guest_Owner == \"\", \"Unknown\", Recommendations.Remove_Guest_Owner)\r\n//| extend Remove_Guest_Read = iff(Recommendations.Remove_Guest_Read == \"\", \"Unknown\", Recommendations.Remove_Guest_Read)\r\n| extend Remove_Guest_Write = iff(Recommendations.Remove_Guest_Write == \"\", \"Unknown\", Recommendations.Remove_Guest_Write)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| summarize count=dcount(ResourceId) by State", + "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where subscriptionId in~ ({Subscription:subid})\r\n| where name in~ (\r\n \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", // A maximum of 3 owners should be designated for subscriptions\r\n \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n \"20606e75-05c4-48c0-9d97-add6daa2109a\", // Guest accounts with owner permissions on Azure resources should be removed\r\n// \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", // Guest accounts with read permissions on Azure resources should be removed\r\n \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\" // Guest accounts with write permissions on Azure resources should be removed\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", \"Max_3_Owners\", // A maximum of 3 owners should be designated for subscriptions\r\n name =~ \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", \"Remove_Blocked_Owner\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n name =~ \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", \"Remove_Blocked_ReadWrite\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n name =~ \"20606e75-05c4-48c0-9d97-add6daa2109a\", \"Remove_Guest_Owner\", // Guest accounts with owner permissions on Azure resources should be removed\r\n name =~ \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", \"Remove_Guest_Read\", // Guest accounts with read permissions on Azure resources should be removed\r\n name =~ \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\", \"Remove_Guest_Write\", // Guest accounts with write permissions on Azure resources should be removed\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Max_3_Owners = iff(Recommendations.Max_3_Owners == \"\", \"Unknown\", Recommendations.Max_3_Owners)\r\n| extend Remove_Blocked_Owner = iff(Recommendations.Remove_Blocked_Owner == \"\", \"Unknown\", Recommendations.Remove_Blocked_Owner)\r\n| extend Remove_Blocked_ReadWrite = iff(Recommendations.Remove_Blocked_ReadWrite == \"\", \"Unknown\", Recommendations.Remove_Blocked_ReadWrite)\r\n| extend Remove_Guest_Owner = iff(Recommendations.Remove_Guest_Owner == \"\", \"Unknown\", Recommendations.Remove_Guest_Owner)\r\n//| extend Remove_Guest_Read = iff(Recommendations.Remove_Guest_Read == \"\", \"Unknown\", Recommendations.Remove_Guest_Read)\r\n| extend Remove_Guest_Write = iff(Recommendations.Remove_Guest_Write == \"\", \"Unknown\", Recommendations.Remove_Guest_Write)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| summarize count=dcount(ResourceId) by State", "size": 3, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1372,7 +1384,7 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where name in~ (\r\n \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", // A maximum of 3 owners should be designated for subscriptions\r\n \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n// \"00c6d40b-e990-6acf-d4f3-471e747a27c4\", // Deprecated accounts should be removed from subscriptions\r\n \"e52064aa-6853-e252-a11e-dffc675689c2\", // Deprecated accounts with owner permissions should be removed from subscriptions\r\n \"c3b6ae71-f1f0-31b4-e6c1-d5951285d03d\", // External accounts with owner permissions should be removed from subscriptions\r\n// \"a8c6a4ad-d51e-88fe-2979-d3ee3c864f8b\", // External accounts with read permissions should be removed from subscriptions\r\n \"04e7147b-0deb-9796-2e5c-0336343ceb3d\", // External accounts with write permissions should be removed from subscriptions\r\n \"20606e75-05c4-48c0-9d97-add6daa2109a\", // Guest accounts with owner permissions on Azure resources should be removed\r\n// \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", // Guest accounts with read permissions on Azure resources should be removed\r\n \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\" // Guest accounts with write permissions on Azure resources should be removed\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", \"Max_3_Owners\", // A maximum of 3 owners should be designated for subscriptions\r\n name =~ \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", \"Remove_Blocked_Owner\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n name =~ \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", \"Remove_Blocked_ReadWrite\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n name =~ \"00c6d40b-e990-6acf-d4f3-471e747a27c4\", \"Remove_Deprecated_All\", // Deprecated accounts should be removed from subscriptions\r\n name =~ \"e52064aa-6853-e252-a11e-dffc675689c2\", \"Remove_Deprecated_Owner\", // Deprecated accounts with owner permissions should be removed from subscriptions\r\n name =~ \"c3b6ae71-f1f0-31b4-e6c1-d5951285d03d\", \"Remove_External_Owner\", // External accounts with owner permissions should be removed from subscriptions\r\n name =~ \"a8c6a4ad-d51e-88fe-2979-d3ee3c864f8b\", \"Remove_External_Read\", // External accounts with read permissions should be removed from subscriptions\r\n name =~ \"04e7147b-0deb-9796-2e5c-0336343ceb3d\", \"Remove_External_Write\", // External accounts with write permissions should be removed from subscriptions\r\n name =~ \"20606e75-05c4-48c0-9d97-add6daa2109a\", \"Remove_Guest_Owner\", // Guest accounts with owner permissions on Azure resources should be removed\r\n name =~ \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", \"Remove_Guest_Read\", // Guest accounts with read permissions on Azure resources should be removed\r\n name =~ \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\", \"Remove_Guest_Write\", // Guest accounts with write permissions on Azure resources should be removed\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Max_3_Owners = iff(Recommendations.Max_3_Owners == \"\", \"Unknown\", Recommendations.Max_3_Owners)\r\n| extend Remove_Blocked_Owner = iff(Recommendations.Remove_Blocked_Owner == \"\", \"Unknown\", Recommendations.Remove_Blocked_Owner)\r\n| extend Remove_Blocked_ReadWrite = iff(Recommendations.Remove_Blocked_ReadWrite == \"\", \"Unknown\", Recommendations.Remove_Blocked_ReadWrite)\r\n//| extend Remove_Deprecated_All = iff(Recommendations.Remove_Deprecated_All == \"\", \"Unknown\", Recommendations.Remove_Deprecated_All)\r\n| extend Remove_Deprecated_Owner = iff(Recommendations.Remove_Deprecated_Owner == \"\", \"Unknown\", Recommendations.Remove_Deprecated_Owner)\r\n| extend Remove_External_Owner = iff(Recommendations.Remove_External_Owner == \"\", \"Unknown\", Recommendations.Remove_External_Owner)\r\n//| extend Remove_External_Read = iff(Recommendations.Remove_External_Read == \"\", \"Unknown\", Recommendations.Remove_External_Read)\r\n| extend Remove_External_Write = iff(Recommendations.Remove_External_Write == \"\", \"Unknown\", Recommendations.Remove_External_Write)\r\n| extend Remove_Guest_Owner = iff(Recommendations.Remove_Guest_Owner == \"\", \"Unknown\", Recommendations.Remove_Guest_Owner)\r\n//| extend Remove_Guest_Read = iff(Recommendations.Remove_Guest_Read == \"\", \"Unknown\", Recommendations.Remove_Guest_Read)\r\n| extend Remove_Guest_Write = iff(Recommendations.Remove_Guest_Write == \"\", \"Unknown\", Recommendations.Remove_Guest_Write)\r\n| extend PackedString=tostring(pack_all())\r\n| extend HealthState = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend HealthState = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", HealthState)\r\n| where HealthState in~ ({HealthStateP})\r\n| project ResourceId, HealthState, Max_3_Owners, Remove_Blocked_Owner, Remove_Blocked_ReadWrite, Remove_Deprecated_Owner, Remove_External_Owner, Remove_External_Write, Remove_Guest_Owner, Remove_Guest_Write", + "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where name in~ (\r\n \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", // A maximum of 3 owners should be designated for subscriptions\r\n \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n \"20606e75-05c4-48c0-9d97-add6daa2109a\", // Guest accounts with owner permissions on Azure resources should be removed\r\n// \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", // Guest accounts with read permissions on Azure resources should be removed\r\n \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\" // Guest accounts with write permissions on Azure resources should be removed\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", \"Max_3_Owners\", // A maximum of 3 owners should be designated for subscriptions\r\n name =~ \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", \"Remove_Blocked_Owner\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n name =~ \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", \"Remove_Blocked_ReadWrite\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n name =~ \"20606e75-05c4-48c0-9d97-add6daa2109a\", \"Remove_Guest_Owner\", // Guest accounts with owner permissions on Azure resources should be removed\r\n name =~ \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", \"Remove_Guest_Read\", // Guest accounts with read permissions on Azure resources should be removed\r\n name =~ \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\", \"Remove_Guest_Write\", // Guest accounts with write permissions on Azure resources should be removed\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Max_3_Owners = iff(Recommendations.Max_3_Owners == \"\", \"Unknown\", Recommendations.Max_3_Owners)\r\n| extend Remove_Blocked_Owner = iff(Recommendations.Remove_Blocked_Owner == \"\", \"Unknown\", Recommendations.Remove_Blocked_Owner)\r\n| extend Remove_Blocked_ReadWrite = iff(Recommendations.Remove_Blocked_ReadWrite == \"\", \"Unknown\", Recommendations.Remove_Blocked_ReadWrite)\r\n| extend Remove_Guest_Owner = iff(Recommendations.Remove_Guest_Owner == \"\", \"Unknown\", Recommendations.Remove_Guest_Owner)\r\n//| extend Remove_Guest_Read = iff(Recommendations.Remove_Guest_Read == \"\", \"Unknown\", Recommendations.Remove_Guest_Read)\r\n| extend Remove_Guest_Write = iff(Recommendations.Remove_Guest_Write == \"\", \"Unknown\", Recommendations.Remove_Guest_Write)\r\n| extend PackedString=tostring(pack_all())\r\n| extend HealthState = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend HealthState = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", HealthState)\r\n| where HealthState in~ ({HealthStateP})\r\n| project ResourceId, HealthState, Max_3_Owners, Remove_Blocked_Owner, Remove_Blocked_ReadWrite, Remove_Guest_Owner, Remove_Guest_Write", "size": 1, "title": "Subscriptions - Health State. Select one or more subscriptions to see cause of \"NotApplicable\" state.", "exportMultipleValues": true, @@ -1927,7 +1939,7 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where name in~ (\r\n \"6240402e-f77c-46fa-9060-a7ce53997754\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n \"94290b00-4d0c-d7b4-7cea-064a9554e681\", // MFA should be enabled on accounts with owner permissions on subscriptions\r\n \"151e82c5-5341-a74b-1eb0-bc38d2c84bb5\", // MFA should be enabled on accounts with read permissions on subscriptions\r\n \"57e98606-6b1e-6193-0e3d-fe621387c16b\" // MFA should be enabled on accounts with write permissions on subscriptions\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6240402e-f77c-46fa-9060-a7ce53997754\", \"Res_Owner_MFA\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n name =~ \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", \"Res_Read_MFA\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n name =~ \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", \"Res_Write_MFA\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n name =~ \"94290b00-4d0c-d7b4-7cea-064a9554e681\", \"Sub_Owner_MFA\", // MFA should be enabled on accounts with owner permissions on subscriptions\r\n name =~ \"151e82c5-5341-a74b-1eb0-bc38d2c84bb5\", \"Sub_Read_MFA\", // MFA should be enabled on accounts with read permissions on subscriptions\r\n name =~ \"57e98606-6b1e-6193-0e3d-fe621387c16b\", \"Sub_Write_MFA\", // MFA should be enabled on accounts with write permissions on subscriptions\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Res_Owner_MFA = iff(Recommendations.Res_Owner_MFA == \"\", \"Unknown\", Recommendations.Res_Owner_MFA)\r\n| extend Res_Read_MFA = iff(Recommendations.Res_Read_MFA == \"\", \"Unknown\", Recommendations.Res_Read_MFA)\r\n| extend Res_Write_MFA = iff(Recommendations.Res_Write_MFA == \"\", \"Unknown\", Recommendations.Res_Write_MFA)\r\n| extend Sub_Owner_MFA = iff(Recommendations.Sub_Owner_MFA == \"\", \"Unknown\", Recommendations.Sub_Owner_MFA)\r\n| extend Sub_Read_MFA = iff(Recommendations.Sub_Read_MFA == \"\", \"Unknown\", Recommendations.Sub_Read_MFA)\r\n| extend Sub_Write_MFA = iff(Recommendations.Sub_Write_MFA == \"\", \"Unknown\", Recommendations.Sub_Write_MFA)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| summarize count = dcount(ResourceId) by State", + "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where name in~ (\r\n \"6240402e-f77c-46fa-9060-a7ce53997754\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\" // Accounts with write permissions on Azure resources should be MFA enabled\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6240402e-f77c-46fa-9060-a7ce53997754\", \"Res_Owner_MFA\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n name =~ \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", \"Res_Read_MFA\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n name =~ \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", \"Res_Write_MFA\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Res_Owner_MFA = iff(Recommendations.Res_Owner_MFA == \"\", \"Unknown\", Recommendations.Res_Owner_MFA)\r\n| extend Res_Read_MFA = iff(Recommendations.Res_Read_MFA == \"\", \"Unknown\", Recommendations.Res_Read_MFA)\r\n| extend Res_Write_MFA = iff(Recommendations.Res_Write_MFA == \"\", \"Unknown\", Recommendations.Res_Write_MFA)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| summarize count = dcount(ResourceId) by State", "size": 3, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2002,7 +2014,7 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where name in~ (\r\n \"6240402e-f77c-46fa-9060-a7ce53997754\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n \"94290b00-4d0c-d7b4-7cea-064a9554e681\", // MFA should be enabled on accounts with owner permissions on subscriptions\r\n \"151e82c5-5341-a74b-1eb0-bc38d2c84bb5\", // MFA should be enabled on accounts with read permissions on subscriptions\r\n \"57e98606-6b1e-6193-0e3d-fe621387c16b\" // MFA should be enabled on accounts with write permissions on subscriptions\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6240402e-f77c-46fa-9060-a7ce53997754\", \"Res_Owner_MFA\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n name =~ \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", \"Res_Read_MFA\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n name =~ \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", \"Res_Write_MFA\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n name =~ \"94290b00-4d0c-d7b4-7cea-064a9554e681\", \"Sub_Owner_MFA\", // MFA should be enabled on accounts with owner permissions on subscriptions\r\n name =~ \"151e82c5-5341-a74b-1eb0-bc38d2c84bb5\", \"Sub_Read_MFA\", // MFA should be enabled on accounts with read permissions on subscriptions\r\n name =~ \"57e98606-6b1e-6193-0e3d-fe621387c16b\", \"Sub_Write_MFA\", // MFA should be enabled on accounts with write permissions on subscriptions\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Res_Owner_MFA = iff(Recommendations.Res_Owner_MFA == \"\", \"Unknown\", Recommendations.Res_Owner_MFA)\r\n| extend Res_Read_MFA = iff(Recommendations.Res_Read_MFA == \"\", \"Unknown\", Recommendations.Res_Read_MFA)\r\n| extend Res_Write_MFA = iff(Recommendations.Res_Write_MFA == \"\", \"Unknown\", Recommendations.Res_Write_MFA)\r\n| extend Sub_Owner_MFA = iff(Recommendations.Sub_Owner_MFA == \"\", \"Unknown\", Recommendations.Sub_Owner_MFA)\r\n| extend Sub_Read_MFA = iff(Recommendations.Sub_Read_MFA == \"\", \"Unknown\", Recommendations.Sub_Read_MFA)\r\n| extend Sub_Write_MFA = iff(Recommendations.Sub_Write_MFA == \"\", \"Unknown\", Recommendations.Sub_Write_MFA)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| where State in~ ({HealthStateP})\r\n| project ResourceId, State, Res_Owner_MFA, Res_Read_MFA, Res_Write_MFA, Sub_Owner_MFA, Sub_Read_MFA, Sub_Write_MFA", + "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where name in~ (\r\n \"6240402e-f77c-46fa-9060-a7ce53997754\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\" // Accounts with write permissions on Azure resources should be MFA enabled\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6240402e-f77c-46fa-9060-a7ce53997754\", \"Res_Owner_MFA\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n name =~ \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", \"Res_Read_MFA\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n name =~ \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", \"Res_Write_MFA\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Res_Owner_MFA = iff(Recommendations.Res_Owner_MFA == \"\", \"Unknown\", Recommendations.Res_Owner_MFA)\r\n| extend Res_Read_MFA = iff(Recommendations.Res_Read_MFA == \"\", \"Unknown\", Recommendations.Res_Read_MFA)\r\n| extend Res_Write_MFA = iff(Recommendations.Res_Write_MFA == \"\", \"Unknown\", Recommendations.Res_Write_MFA)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| where State in~ ({HealthStateP})\r\n| project ResourceId, State, Res_Owner_MFA, Res_Read_MFA, Res_Write_MFA", "size": 1, "exportMultipleValues": true, "exportedParameters": [ @@ -2516,7 +2528,7 @@ { "type": 1, "content": { - "json": "## Health Legend\r\n\r\n#### Healthy:\r\nHealthy Virtual Machines have all the following ASR rules configured in 'block' mode:\r\n- Email Threats - Block executable content from email client and webmail.\r\n- Office Threats - Block Win32 API calls from Office macros.\r\n\r\nHealthy Virtual Machines have antimalware with automatically updated signatures.\r\n\r\nIf the control is not applicable (e.g. Linux OS), the health state is reported as Healthy.\r\n\r\n#### Unhealthy:\r\nUnhealthy Virtual machines do not have at least one of the above ASR rules configured in 'block' mode or do not have antimalware with automatically updated signatures.", + "json": "## Health Legend\r\nThe \"Configure Microsoft Office macro settings\" strategy is applicable to client systems used by interactive users. \r\nAs this workbook targets servers that do not typically match this profile, the health state will be determined by the presence or absence of Microsoft Office applications that are capable of executing macros.\r\n\r\n#### Healthy:\r\nHealthy Virtual Machines do not have any Microsoft Office applications installed.\r\n\r\n#### Unhealthy:\r\nUnhealthy Virtual Machines have one or more Microsoft Office applications installed.\r\n\r\n#### Unknown:\r\nSoftware inventory data is not available for this VM. Verify that vulnerability scanning is enabled on this VM.", "style": "success" }, "name": "text - 1" @@ -2532,13 +2544,12 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "DeviceTvmSecureConfigurationAssessment\r\n| where ConfigurationId in (\r\n \"scid-2500\", // ASR: Block executable content from email client and webmail\r\n \"scid-2506\", // ASR: Block Win32 API calls from Office macros\r\n \"scid-2010\", // AV: Defender AV mode: 0 == active, 1 == passive, 4 == EDR block mode\r\n \"scid-2011\", // AV: Defender AV signature (Windows)\r\n// \"scid-2012\", // AV: Defender enable RTP (Widows)\r\n// \"scid-2016\", // AV: Defender enable cloud protection (Windows)\r\n// \"scid-6090\", // AV: Defender enable RTP (Linux)\r\n// \"scid-6094\", // AV: Defender enable cloud protection (Linux)\r\n \"scid-6095\" // AV: Defender AV signature (Linux)\r\n)\r\n| extend Setting = case(\r\n ConfigurationId == \"scid-2500\", tostring(Context[0].Unknown1),\r\n ConfigurationId == \"scid-2506\", tostring(Context[0].Unknown1),\r\n ConfigurationId == \"scid-2010\", tostring(Context[0].AntiVirusMode),\r\n ConfigurationId == \"scid-2011\", tostring(Context[0].AntiVirusSignatureLastUpdateTime),\r\n ConfigurationId == \"scid-6095\", tostring(Context[0].AntiVirusSignatureLastUpdateTime),\r\n \"Error\"\r\n)\r\n| extend Setting = iff(IsApplicable == false, \"NA\", Setting)\r\n| summarize arg_max(Timestamp, Setting) by DeviceId, DeviceName, OSPlatform, ConfigurationId\r\n| summarize make_bag(pack(ConfigurationId, Setting)), max(Timestamp) by DeviceId, DeviceName, OSPlatform\r\n| evaluate bag_unpack(bag_)\r\n| extend AvSignatureUpdateTime = iff([\"scid-2011\"] == \"NA\", [\"scid-6095\"], [\"scid-2011\"])\r\n| project-away [\"scid-2011\"], [\"scid-6095\"]\r\n| project-rename ExecutableEmailContent = [\"scid-2500\"], OfficeMacroWin32ApiCalls = [\"scid-2506\"], AvMode = [\"scid-2010\"]\r\n| extend TimeSinceAvSignatureUpdate = max_Timestamp - todatetime(AvSignatureUpdateTime)\r\n// assess compliance\r\n| extend Compliant = iff(ExecutableEmailContent in~ (\"Block\", \"NA\"), \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeMacroWin32ApiCalls in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(AvMode in (\"0\", \"1\", \"4\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(TimeSinceAvSignatureUpdate < 7d and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| where not(AvMode in~ (\"\", \"Unknown\") and ExecutableEmailContent in~ (\"\", \"Unknown\") and AvSignatureUpdateTime == \"\")\r\n| summarize count = dcount(DeviceId) by Compliant", + "query": "securityresources\r\n| where type == \"microsoft.security/softwareinventories\"\r\n| parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n| parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n| extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n| where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n| distinct subscriptionId, resourceGroup, resourceId, resourceType\r\n| join kind = leftouter (\r\n securityresources\r\n | where type == \"microsoft.security/softwareinventories\"\r\n | parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend vendor = tostring(properties.vendor),\r\n software = tostring(properties.softwareName),\r\n version = tostring(properties.version)\r\n | where vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\")\r\n | summarize applications = make_list(pack(\"Vendor\", vendor, \"Software\", software, \"Version\", version)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend appCompliant = iff(isnull(applications), \"Healthy\", \"Unhealthy\")\r\n| project subscriptionId, resourceGroup, resourceId = tolower(resourceId), resourceType, appCompliant, applications\r\n| join kind = fullouter (\r\n resources\r\n //| where type in~ (\"microsoft.compute/virtualmachines\", \"microsoft.classiccompute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | where type in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend osType = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.storageProfile.osDisk.osType), tostring(properties.osType)),\r\n osName = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.extended.instanceView.osName), tostring(properties.osName)), // blank if machine stopped, deallocated\r\n osVersion = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.extended.instanceView.osVersion), tostring(properties.osVersion)), // blank if machine stopped, deallocated\r\n publisher = tostring(properties.storageProfile.imageReference.publisher),\r\n exactVersion = tostring(properties.storageProfile.imageReference.exactVersion),\r\n sku = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.storageProfile.imageReference.sku), tostring(properties.osSku)),\r\n offer = tostring(properties.storageProfile.imageReference.offer)\r\n | project subscriptionId, resourceGroup, resourceId = tolower(id), resourceType = type, name, osType, osName, osVersion, sku, publisher, exactVersion, offer\r\n) on resourceId\r\n| extend subscriptionId = iff(isempty(subscriptionId), subscriptionId1, subscriptionId)\r\n| extend resourceGroup = iff(isempty(resourceGroup), resourceGroup1, resourceGroup)\r\n| extend resourceId = iff(isempty(resourceId), resourceId1, resourceId)\r\n| extend resourceType = iff(isempty(resourceType), resourceType1, resourceType)\r\n//| project-away subscriptionId1, resourceGroup1, resourceId1, resourceType1\r\n| extend appCompliant = iff(isempty(appCompliant), \"Unknown\", appCompliant)\r\n| summarize count = dcount(resourceId) by appCompliant", "size": 3, - "timeContextFromParameter": "TimeRange", - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ - "{Workspace}" + "{Subscription}" ], "visualization": "piechart", "chartSettings": { @@ -2550,6 +2561,10 @@ { "seriesName": "Healthy", "color": "green" + }, + { + "seriesName": "Unknown", + "color": "gray" } ] } @@ -2584,13 +2599,13 @@ ], "showDefault": false }, - "jsonData": "[\"Healthy\", \"Unhealthy\"]", + "jsonData": "[\"Healthy\", \"Unhealthy\", \"Unknown\"]", "timeContext": { "durationMs": 86400000 }, "defaultValue": "value::all", "value": [ - "Unhealthy" + "Unknown" ] } ], @@ -2604,142 +2619,33 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "DeviceTvmSecureConfigurationAssessment\r\n| where ConfigurationId in (\r\n \"scid-2500\", // ASR: Block executable content from email client and webmail\r\n \"scid-2506\", // ASR: Block Win32 API calls from Office macros\r\n \"scid-2010\", // AV: Defender AV mode: 0 == active, 1 == passive, 4 == EDR block mode\r\n \"scid-2011\", // AV: Defender AV signature (Windows)\r\n// \"scid-2012\", // AV: Defender enable RTP (Widows)\r\n// \"scid-2016\", // AV: Defender enable cloud protection (Windows)\r\n// \"scid-6090\", // AV: Defender enable RTP (Linux)\r\n// \"scid-6094\", // AV: Defender enable cloud protection (Linux)\r\n \"scid-6095\" // AV: Defender AV signature (Linux)\r\n)\r\n| extend Setting = case(\r\n ConfigurationId == \"scid-2500\", tostring(Context[0].Unknown1),\r\n ConfigurationId == \"scid-2506\", tostring(Context[0].Unknown1),\r\n ConfigurationId == \"scid-2010\", tostring(Context[0].AntiVirusMode),\r\n ConfigurationId == \"scid-2011\", tostring(Context[0].AntiVirusSignatureLastUpdateTime),\r\n ConfigurationId == \"scid-6095\", tostring(Context[0].AntiVirusSignatureLastUpdateTime),\r\n \"Error\"\r\n)\r\n| extend Setting = iff(IsApplicable == false, \"NA\", Setting)\r\n| summarize arg_max(Timestamp, Setting) by DeviceId, DeviceName, OSPlatform, ConfigurationId\r\n| summarize make_bag(pack(ConfigurationId, Setting)), max(Timestamp) by DeviceId, DeviceName, OSPlatform\r\n| evaluate bag_unpack(bag_)\r\n| extend AvSignatureUpdateTime = iff([\"scid-2011\"] == \"NA\", [\"scid-6095\"], [\"scid-2011\"])\r\n| project-away [\"scid-2011\"], [\"scid-6095\"]\r\n| project-rename ExecutableEmailContent = [\"scid-2500\"], OfficeMacroWin32ApiCalls = [\"scid-2506\"], AvMode = [\"scid-2010\"]\r\n| extend TimeSinceAvSignatureUpdate = max_Timestamp - todatetime(AvSignatureUpdateTime)\r\n// assess compliance\r\n| extend Compliant = iff(ExecutableEmailContent in~ (\"Block\", \"NA\"), \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeMacroWin32ApiCalls in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(AvMode in (\"0\", \"1\", \"4\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(TimeSinceAvSignatureUpdate < 7d and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| where not(AvMode in~ (\"\", \"Unknown\") and ExecutableEmailContent in~ (\"\", \"Unknown\") and AvSignatureUpdateTime == \"\")\r\n| where Compliant in~ ({HealthState})\r\n| extend AvMode = case(\r\n AvMode == \"0\", \"Active\",\r\n AvMode == \"1\", \"Passive\",\r\n AvMode == \"4\", \"EDR Block\",\r\n AvMode\r\n)\r\n| project-reorder DeviceName, DeviceId, Compliant, max_Timestamp\r\n| order by DeviceName asc, DeviceId asc", - "size": 2, - "timeContextFromParameter": "TimeRange", - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", + "query": "securityresources\r\n| where type == \"microsoft.security/softwareinventories\"\r\n| parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n| parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n| extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n| where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n| distinct subscriptionId, resourceGroup, resourceId, resourceType\r\n| join kind = leftouter (\r\n securityresources\r\n | where type == \"microsoft.security/softwareinventories\"\r\n | parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend vendor = tostring(properties.vendor),\r\n software = tostring(properties.softwareName),\r\n version = tostring(properties.version)\r\n | where vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\")\r\n | summarize applications = make_list(pack(\"Vendor\", vendor, \"Software\", software, \"Version\", version)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend appCompliant = iff(isnull(applications), \"Healthy\", \"Unhealthy\")\r\n| project subscriptionId, resourceGroup, resourceId = tolower(resourceId), resourceType, appCompliant, applications\r\n| join kind = fullouter (\r\n resources\r\n //| where type in~ (\"microsoft.compute/virtualmachines\", \"microsoft.classiccompute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | where type in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend osType = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.storageProfile.osDisk.osType), tostring(properties.osType)),\r\n osName = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.extended.instanceView.osName), tostring(properties.osName)), // blank if machine stopped, deallocated\r\n osVersion = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.extended.instanceView.osVersion), tostring(properties.osVersion)), // blank if machine stopped, deallocated\r\n publisher = tostring(properties.storageProfile.imageReference.publisher),\r\n exactVersion = tostring(properties.storageProfile.imageReference.exactVersion),\r\n sku = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.storageProfile.imageReference.sku), tostring(properties.osSku)),\r\n offer = tostring(properties.storageProfile.imageReference.offer)\r\n | project subscriptionId, resourceGroup, resourceId = tolower(id), resourceType = type, name, osType, osName, osVersion, sku, publisher, exactVersion, offer\r\n) on resourceId\r\n| extend subscriptionId = iff(isempty(subscriptionId), subscriptionId1, subscriptionId)\r\n| extend resourceGroup = iff(isempty(resourceGroup), resourceGroup1, resourceGroup)\r\n| extend resourceId = iff(isempty(resourceId), resourceId1, resourceId)\r\n| extend resourceType = iff(isempty(resourceType), resourceType1, resourceType)\r\n| project-away subscriptionId1, resourceGroup1, resourceId1, resourceType1\r\n| extend appCompliant = iff(isempty(appCompliant), \"Unknown\", appCompliant)\r\n| where appCompliant in~ ({HealthState})\r\n", + "size": 0, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ - "{Workspace}" + "{Subscription}" ], "gridSettings": { "formatters": [ { - "columnMatch": "Compliant", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "colors", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Healthy", - "representation": "green", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "Unhealthy", - "representation": "red", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "gray", - "text": "{0}{1}" - } - ] - } - }, - { - "columnMatch": "AvMode", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Active", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "Passive", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "EDR Block", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "NA", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "4", - "text": "{0}{1}" - } - ] - } - }, - { - "columnMatch": "ExecutableEmailContent", - "formatter": 18, + "columnMatch": "$gen_group", + "formatter": 15, "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Block", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "NA", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "4", - "text": "{0}{1}" - } - ] + "linkTarget": "Resource", + "showIcon": true } }, { - "columnMatch": "OfficeMacroWin32ApiCalls", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Block", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "NA", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "critical", - "text": "{0}{1}" - } - ] - } + "columnMatch": "subscriptionId", + "formatter": 5 }, { - "columnMatch": "TimeSinceAvSignatureUpdate", + "columnMatch": "resourceGroup", "formatter": 5 }, { - "columnMatch": "HealthState", + "columnMatch": "appCompliant", "formatter": 18, "formatOptions": { "thresholdsOptions": "colors", @@ -2756,6 +2662,12 @@ "representation": "red", "text": "{0}{1}" }, + { + "operator": "==", + "thresholdValue": "Unknown", + "representation": "gray", + "text": "{0}{1}" + }, { "operator": "Default", "thresholdValue": null, @@ -2766,39 +2678,74 @@ } } ], + "hierarchySettings": { + "treeType": 1, + "groupBy": [ + "subscriptionId", + "resourceGroup" + ], + "expandTopLevel": true + }, "labelSettings": [ { - "columnId": "DeviceName", + "columnId": "subscriptionId", + "label": "Subscription" + }, + { + "columnId": "resourceId", "label": "Resource" }, { - "columnId": "Compliant", + "columnId": "resourceType", + "label": "Resource Type" + }, + { + "columnId": "appCompliant", "label": "Health State" }, { - "columnId": "max_Timestamp", - "label": "Timestamp" + "columnId": "applications", + "label": "Non-compliant Apps" + }, + { + "columnId": "name", + "label": "VM name" + }, + { + "columnId": "osType", + "label": "OS Type" + }, + { + "columnId": "osName", + "label": "OS Name" + }, + { + "columnId": "osVersion", + "label": "OS Version" }, { - "columnId": "OSPlatform", - "label": "OS Platform" + "columnId": "sku", + "label": "SKU" }, { - "columnId": "AvMode", - "label": "AV Mode" + "columnId": "publisher", + "label": "Publisher" + }, + { + "columnId": "exactVersion", + "label": "Exact Version" + }, + { + "columnId": "offer", + "label": "Offer" } ] } }, - "name": "query - 5" + "name": "query - 6" } ] }, - "conditionalVisibility": { - "parameterName": "tvmExists", - "comparison": "isEqualTo", - "value": "True" - }, "name": "group - 7" } ] @@ -2810,26 +2757,6 @@ }, "name": "group - 9" }, - { - "type": 1, - "content": { - "json": "## Please make sure that you have selected the appropriate Sentinel workspace from the drop-down parameter above.\r\n\r\n### If you still see this message, it is because this strategy relies on data only available through a Microsoft Sentinel private preview feature. \r\n### To see this strategy, and to provide feedback on this and other private preview features for Microsoft Sentinel and other Microsoft security products, join our Customer Connection Program. \r\n### [Learn more here](https://techcommunity.microsoft.com/t5/security-compliance-and-identity/how-microsoft-security-wants-to-help-you-take-your-fandom-and/ba-p/3745057) or fill out the [form](https://www.aka.ms/JoinCCP) to join.", - "style": "warning" - }, - "conditionalVisibilities": [ - { - "parameterName": "tvmExists", - "comparison": "isEqualTo", - "value": "False" - }, - { - "parameterName": "Tab", - "comparison": "isEqualTo", - "value": "macros" - } - ], - "name": "text - 14" - }, { "type": 12, "content": { @@ -2852,7 +2779,7 @@ { "type": 1, "content": { - "json": "## Health Legend\r\n#### Healthy:\r\nHealthy Virtual Machines have **all of the following** ASR rules configured in 'block' mode:\r\n\r\nScripting Threats:\r\n- Block JavaScript or VBScript from launching downloaded executable content.\r\n- Block execution of potentially obfuscated scripts.\r\n\r\nEmail Threats:\r\n- Block executable content from email client and webmail.\r\n\r\nOffice Threats:\r\n- Block Office application from creating child processes.\r\n- Block Office applications from creating executable content.\r\n- Block Office applications from injecting code into other processes.\r\n- Block Adobe Reader from creating child processes.\r\n\r\n#### Unhealthy:\r\nUnhealthy Virtual Machines have **at least one** of the above ASR rules not configured in 'block' mode.", + "json": "## Health Legend\r\nThe \"User application hardening\" strategy is applicable to client systems used by interactive users. \r\nAs this workbook targets servers that do not typically match this profile, the health state will be determined by the presence or absence of web browsers, Microsoft Office and PDF applications, and whether an endpoint protection solution is enabled and in a healthy state.\r\n\r\n#### Healthy:\r\nHealthy Virtual Machines:\r\n- Do not have any (non-Microsoft) web browsers (*), Microsoft Office or PDF applications installed.\r\n- Have a [supported endpoint protection solution](https://learn.microsoft.com/en-gb/azure/defender-for-cloud/support-matrix-defender-for-servers#endpoint-protection-support) installed and in a healthy state.\r\n\r\n#### Unhealthy:\r\nUnhealthy Virtual Machines do not meet one or both of the above conditions.\r\n\r\n#### Unknown:\r\nOne or both of the following is true for a VM:\r\n- Software inventory data is not available for this VM. Verify that vulnerability scanning is enabled on this VM.\r\n- Endpoint protection data is not available for this VM.\r\n\r\n(*) Microsoft browsers are not counted as installed apps as they are included with the OS.", "style": "success" }, "name": "text - 1" @@ -2868,13 +2795,12 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "DeviceTvmSecureConfigurationAssessment\r\n//| where OSPlatform != \"Linux\" //exclude Linux machines\r\n| where ConfigurationId in (\r\n \"scid-2500\", // Block executable content from email client and webmail\r\n \"scid-2501\", // Block Office applications from creating child processes\r\n \"scid-2502\", // Block Office applications from creating executable content\r\n \"scid-2503\", // Block Office applications from injecting code into other processes\r\n \"scid-2504\", // Block JavaScript or VBScript from launching downloaded executable content\r\n \"scid-2505\", // Block execution of potentially obfuscated scripts\r\n \"scid-2513\" // Block Adobe Reader from creating child processes\r\n)\r\n| extend Setting = tostring(Context[0].Unknown1)\r\n| where Setting != \"Unknown\"\r\n| extend Setting = iff(IsApplicable == false, \"NA\", Setting)\r\n| summarize arg_max(Timestamp, Setting) by DeviceId, DeviceName, OSPlatform, ConfigurationId\r\n| summarize make_bag(pack(ConfigurationId, Setting)), max(Timestamp) by DeviceId, DeviceName, OSPlatform\r\n| evaluate bag_unpack(bag_)\r\n| project-rename\r\n ExecutableEmailContent = [\"scid-2500\"],\r\n OfficeChildProcess = [\"scid-2501\"],\r\n ExecutableOfficeContent = [\"scid-2502\"],\r\n OfficeProcessInjection = [\"scid-2503\"],\r\n ScriptExecutableDownload = [\"scid-2504\"],\r\n ObfuscatedScript = [\"scid-2505\"],\r\n AdobeReaderChildProcess = [\"scid-2513\"]\r\n// assess compliance\r\n| extend Compliant = iff(ExecutableEmailContent in~ (\"Block\", \"NA\"), \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeChildProcess in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ExecutableOfficeContent in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeProcessInjection in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ScriptExecutableDownload in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ObfuscatedScript in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(AdobeReaderChildProcess in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| summarize count = dcount(DeviceId) by Compliant", + "query": "securityresources\r\n| where type == \"microsoft.security/softwareinventories\"\r\n| parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n| parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n| extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n| where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n| distinct subscriptionId, resourceGroup, resourceId, resourceType\r\n| join kind = leftouter (\r\n securityresources\r\n | where type == \"microsoft.security/softwareinventories\"\r\n | parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend vendor = tostring(properties.vendor),\r\n software = tostring(properties.softwareName),\r\n version = tostring(properties.version)\r\n | where (vendor =~ \"adobe\" and software contains \"acrobat\") or \r\n (vendor =~ \"google\" and software contains \"chrome\") or\r\n (vendor =~ \"mozilla\" and software contains \"firefox\") or\r\n //(vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\", \"edge_chromium-based\", \"internet_explorer\", \"teams\"))\r\n (vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\", \"teams\"))\r\n | summarize applications = make_list(pack(\"Vendor\", vendor, \"Software\", software, \"Version\", version)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend appCompliant = iff(isnull(applications), \"Healthy\", \"Unhealthy\")\r\n| project subscriptionId, resourceGroup, resourceId = tolower(resourceId), resourceType, appCompliant, applications\r\n| join kind = fullouter (\r\n securityresources\r\n | where type == \"microsoft.security/assessments\"\r\n | where tostring(name) in~ (\r\n \"83f577bd-a1b6-b7e1-0891-12ca19d1e6df\", // \"Install endpoint protection solution on virtual machines\" (legacy)\r\n \"4fb67663-9ab9-475d-b026-8c544cced439\", // \"Endpoint protection should be installed on machines\"\r\n \"383cf3bc-fdf9-4a02-120a-3e7e36c6bfee\", // \"Endpoint protection should be installed on machines\" (legacy)\r\n \"21300918-b2e3-0346-785f-c77ff57d243b\", // \"Endpoint protection should be installed on virtual machine scale sets\"\r\n \"37a3689a-818e-4a0e-82ac-b1392b9bb000\", // \"Endpoint protection health issues on machines should be resolved\"\r\n \"3bcd234d-c9c7-c2a2-89e0-c01f419c1a8a\", // \"Endpoint protection health issues on machines should be resolved\" (legacy)\r\n \"e71020c2-860c-3235-cd39-04f3f8c936d2\" // \"Endpoint protection health issues on virtual machine scale sets should be resolved\"\r\n )\r\n | parse id with resourceId \"/providers/Microsoft.Security/assessments/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend resourceId = tolower(resourceId)\r\n | extend displayName = tostring(properties.displayName)\r\n //| extend statusChangeDate = format_datetime(todatetime(properties.status.statusChangeDate), \"yyyy-MM-dd\")\r\n | extend statusCode = tostring(properties.status.code)\r\n | extend statusCause = tostring(properties.status.cause)\r\n | extend statusDescription = tostring(properties.status.description)\r\n | extend statusChangeDate = todatetime(properties.status.statusChangeDate)\r\n | extend osName = tostring(properties.additionalData.OSName)\r\n | extend link = tostring(properties.additionalData.subAssessmentsLink)\r\n | project subscriptionId, resourceGroup, resourceId, resourceType, displayName, statusCode, statusCause, statusDescription, statusChangeDate, osName, link, name\r\n | extend recommendation = case (\r\n name =~ \"83f577bd-a1b6-b7e1-0891-12ca19d1e6df\", \"EP_Installed\", // \"Install endpoint protection solution on virtual machines\" (legacy)\r\n name =~ \"4fb67663-9ab9-475d-b026-8c544cced439\", \"EP_Installed\", // \"Endpoint protection should be installed on machines\"\r\n name =~ \"383cf3bc-fdf9-4a02-120a-3e7e36c6bfee\", \"EP_Installed\", // \"Endpoint protection should be installed on machines\" (legacy)\r\n name =~ \"21300918-b2e3-0346-785f-c77ff57d243b\", \"EP_Installed\", // \"Endpoint protection should be installed on virtual machine scale sets\"\r\n name =~ \"37a3689a-818e-4a0e-82ac-b1392b9bb000\", \"EP_Status\", // \"Endpoint protection health issues on machines should be resolved\"\r\n name =~ \"3bcd234d-c9c7-c2a2-89e0-c01f419c1a8a\", \"EP_Status\", // \"Endpoint protection health issues on machines should be resolved\" (legacy)\r\n name =~ \"e71020c2-860c-3235-cd39-04f3f8c936d2\", \"EP_Status\", // \"Endpoint protection health issues on virtual machine scale sets should be resolved\"\r\n \"Unknown\"\r\n )\r\n | summarize arg_max(statusChangeDate, *) by resourceId, recommendation\r\n | extend statusCode = iff(statusCode =~ \"NotApplicable\", strcat(\"NA-\", statusCause), statusCode)\r\n | summarize endpointProtection = make_bag(pack(recommendation, statusCode)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend subscriptionId = iff(isempty(subscriptionId), subscriptionId1, subscriptionId)\r\n| extend resourceGroup = iff(isempty(resourceGroup), resourceGroup1, resourceGroup)\r\n| extend resourceId = iff(isempty(resourceId), resourceId1, resourceId)\r\n| extend resourceType = iff(isempty(resourceType), resourceType1, resourceType)\r\n| project-away subscriptionId1, resourceGroup1, resourceId1, resourceType1\r\n| extend appCompliant = iff(isempty(appCompliant), \"Unknown-NoSoftwareInventory\", appCompliant)\r\n| extend endpointProtection = iff(isnull(endpointProtection), parse_json('{\"EP_Installed\":\"Unknown\",\"EP_Status\":\"Unknown\"}'), endpointProtection)\r\n| extend EP_Installed = tostring(endpointProtection.EP_Installed)\r\n| extend EP_Status = tostring(endpointProtection.EP_Status)\r\n| project-away endpointProtection\r\n| extend status = appCompliant\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Status == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"Unknown\", \"Unknown-NoEndpointProtectionData\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"NA-OffByPolicy\", \"Unknown-OffByPolicy\", status)\r\n| extend status = iff(status == \"Unknown-NoSoftwareInventory\" and EP_Installed == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Unknown-NoSoftwareInventory\" and EP_Status == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status startswith \"Unknown\", \"Unknown\", status)\r\n| summarize count = dcount(resourceId) by status", "size": 3, - "timeContextFromParameter": "TimeRange", - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ - "{Workspace}" + "{Subscription}" ], "visualization": "piechart", "chartSettings": { @@ -2886,11 +2812,15 @@ { "seriesName": "Healthy", "color": "green" + }, + { + "seriesName": "Unknown", + "color": "gray" } ] } }, - "name": "query - 9" + "name": "query - 6" }, { "type": 1, @@ -2920,13 +2850,13 @@ ], "showDefault": false }, - "jsonData": "[\"Healthy\", \"Unhealthy\"]", + "jsonData": "[\"Healthy\", \"Unhealthy\", \"Unknown-NoSoftwareInventory\", \"Unknown-NoEndpointProtectionData\"]", "timeContext": { "durationMs": 86400000 }, "defaultValue": "value::all", "value": [ - "Healthy" + "Unknown-NoEndpointProtectionData" ] } ], @@ -2940,393 +2870,111 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "DeviceTvmSecureConfigurationAssessment\r\n//| where OSPlatform != \"Linux\" //exclude Linux machines\r\n| where ConfigurationId in (\r\n \"scid-2500\", // Block executable content from email client and webmail\r\n \"scid-2501\", // Block Office applications from creating child processes\r\n \"scid-2502\", // Block Office applications from creating executable content\r\n \"scid-2503\", // Block Office applications from injecting code into other processes\r\n \"scid-2504\", // Block JavaScript or VBScript from launching downloaded executable content\r\n \"scid-2505\", // Block execution of potentially obfuscated scripts\r\n \"scid-2513\" // Block Adobe Reader from creating child processes\r\n)\r\n| extend Setting = tostring(Context[0].Unknown1)\r\n| where Setting != \"Unknown\"\r\n| extend Setting = iff(IsApplicable == false, \"NA\", Setting)\r\n| summarize arg_max(Timestamp, Setting) by DeviceId, DeviceName, OSPlatform, ConfigurationId\r\n| summarize make_bag(pack(ConfigurationId, Setting)), max(Timestamp) by DeviceId, DeviceName, OSPlatform\r\n| evaluate bag_unpack(bag_)\r\n| project-rename\r\n ExecutableEmailContent = [\"scid-2500\"],\r\n OfficeChildProcess = [\"scid-2501\"],\r\n ExecutableOfficeContent = [\"scid-2502\"],\r\n OfficeProcessInjection = [\"scid-2503\"],\r\n ScriptExecutableDownload = [\"scid-2504\"],\r\n ObfuscatedScript = [\"scid-2505\"],\r\n AdobeReaderChildProcess = [\"scid-2513\"]\r\n// assess compliance\r\n| extend Compliant = iff(ExecutableEmailContent in~ (\"Block\", \"NA\"), \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeChildProcess in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ExecutableOfficeContent in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeProcessInjection in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ScriptExecutableDownload in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ObfuscatedScript in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(AdobeReaderChildProcess in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| where Compliant in~ ({HealthState})\r\n| project-reorder DeviceName, DeviceId, Compliant, max_Timestamp\r\n| order by DeviceName asc, DeviceId asc", + "query": "securityresources\r\n| where type == \"microsoft.security/softwareinventories\"\r\n| parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n| parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n| extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n| where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n| distinct subscriptionId, resourceGroup, resourceId, resourceType\r\n| join kind = leftouter (\r\n securityresources\r\n | where type == \"microsoft.security/softwareinventories\"\r\n | parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend vendor = tostring(properties.vendor),\r\n software = tostring(properties.softwareName),\r\n version = tostring(properties.version)\r\n | where (vendor =~ \"adobe\" and software contains \"acrobat\") or \r\n (vendor =~ \"google\" and software contains \"chrome\") or\r\n (vendor =~ \"mozilla\" and software contains \"firefox\") or\r\n //(vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\", \"edge_chromium-based\", \"internet_explorer\", \"teams\"))\r\n (vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\", \"teams\"))\r\n | summarize applications = make_list(pack(\"Vendor\", vendor, \"Software\", software, \"Version\", version)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend appCompliant = iff(isnull(applications), \"Healthy\", \"Unhealthy\")\r\n| project subscriptionId, resourceGroup, resourceId = tolower(resourceId), resourceType, appCompliant, applications\r\n| join kind = fullouter (\r\n securityresources\r\n | where type == \"microsoft.security/assessments\"\r\n | where tostring(name) in~ (\r\n \"83f577bd-a1b6-b7e1-0891-12ca19d1e6df\", // \"Install endpoint protection solution on virtual machines\" (legacy)\r\n \"4fb67663-9ab9-475d-b026-8c544cced439\", // \"Endpoint protection should be installed on machines\"\r\n \"383cf3bc-fdf9-4a02-120a-3e7e36c6bfee\", // \"Endpoint protection should be installed on machines\" (legacy)\r\n \"21300918-b2e3-0346-785f-c77ff57d243b\", // \"Endpoint protection should be installed on virtual machine scale sets\"\r\n \"37a3689a-818e-4a0e-82ac-b1392b9bb000\", // \"Endpoint protection health issues on machines should be resolved\"\r\n \"3bcd234d-c9c7-c2a2-89e0-c01f419c1a8a\", // \"Endpoint protection health issues on machines should be resolved\" (legacy)\r\n \"e71020c2-860c-3235-cd39-04f3f8c936d2\" // \"Endpoint protection health issues on virtual machine scale sets should be resolved\"\r\n )\r\n | parse id with resourceId \"/providers/Microsoft.Security/assessments/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend resourceId = tolower(resourceId)\r\n | extend displayName = tostring(properties.displayName)\r\n //| extend statusChangeDate = format_datetime(todatetime(properties.status.statusChangeDate), \"yyyy-MM-dd\")\r\n | extend statusCode = tostring(properties.status.code)\r\n | extend statusCause = tostring(properties.status.cause)\r\n | extend statusDescription = tostring(properties.status.description)\r\n | extend statusChangeDate = todatetime(properties.status.statusChangeDate)\r\n | extend osName = tostring(properties.additionalData.OSName)\r\n | extend link = tostring(properties.additionalData.subAssessmentsLink)\r\n | project subscriptionId, resourceGroup, resourceId, resourceType, displayName, statusCode, statusCause, statusDescription, statusChangeDate, osName, link, name\r\n | extend recommendation = case (\r\n name =~ \"83f577bd-a1b6-b7e1-0891-12ca19d1e6df\", \"EP_Installed\", // \"Install endpoint protection solution on virtual machines\" (legacy)\r\n name =~ \"4fb67663-9ab9-475d-b026-8c544cced439\", \"EP_Installed\", // \"Endpoint protection should be installed on machines\"\r\n name =~ \"383cf3bc-fdf9-4a02-120a-3e7e36c6bfee\", \"EP_Installed\", // \"Endpoint protection should be installed on machines\" (legacy)\r\n name =~ \"21300918-b2e3-0346-785f-c77ff57d243b\", \"EP_Installed\", // \"Endpoint protection should be installed on virtual machine scale sets\"\r\n name =~ \"37a3689a-818e-4a0e-82ac-b1392b9bb000\", \"EP_Status\", // \"Endpoint protection health issues on machines should be resolved\"\r\n name =~ \"3bcd234d-c9c7-c2a2-89e0-c01f419c1a8a\", \"EP_Status\", // \"Endpoint protection health issues on machines should be resolved\" (legacy)\r\n name =~ \"e71020c2-860c-3235-cd39-04f3f8c936d2\", \"EP_Status\", // \"Endpoint protection health issues on virtual machine scale sets should be resolved\"\r\n \"Unknown\"\r\n )\r\n | summarize arg_max(statusChangeDate, *) by resourceId, recommendation\r\n | extend statusCode = iff(statusCode =~ \"NotApplicable\", strcat(\"NA-\", statusCause), statusCode)\r\n | summarize endpointProtection = make_bag(pack(recommendation, statusCode)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend subscriptionId = iff(isempty(subscriptionId), subscriptionId1, subscriptionId)\r\n| extend resourceGroup = iff(isempty(resourceGroup), resourceGroup1, resourceGroup)\r\n| extend resourceId = iff(isempty(resourceId), resourceId1, resourceId)\r\n| extend resourceType = iff(isempty(resourceType), resourceType1, resourceType)\r\n| project-away subscriptionId1, resourceGroup1, resourceId1, resourceType1\r\n| extend appCompliant = iff(isempty(appCompliant), \"Unknown-NoSoftwareInventory\", appCompliant)\r\n| extend endpointProtection = iff(isnull(endpointProtection), parse_json('{\"EP_Installed\":\"Unknown\",\"EP_Status\":\"Unknown\"}'), endpointProtection)\r\n| extend EP_Installed = tostring(endpointProtection.EP_Installed)\r\n| extend EP_Status = tostring(endpointProtection.EP_Status)\r\n| project-away endpointProtection\r\n| extend status = appCompliant\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Status == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"Unknown\", \"Unknown-NoEndpointProtectionData\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"NA-OffByPolicy\", \"Unknown-OffByPolicy\", status)\r\n| extend status = iff(status == \"Unknown-NoSoftwareInventory\" and EP_Installed == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Unknown-NoSoftwareInventory\" and EP_Status == \"Unhealthy\", \"Unhealthy\", status)\r\n| where status in~ ({HealthState})\r\n| project subscriptionId, resourceGroup, resourceId, resourceType, status, appCompliant, applications, EP_Installed, EP_Status", "size": 0, - "timeContextFromParameter": "TimeRange", - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ - "{Workspace}" + "{Subscription}" ], "gridSettings": { "formatters": [ { - "columnMatch": "Compliant", - "formatter": 18, + "columnMatch": "$gen_group", + "formatter": 15, "formatOptions": { - "thresholdsOptions": "colors", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Healthy", - "representation": "green", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "Unhealthy", - "representation": "red", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "gray", - "text": "{0}{1}" - } - ] - } - }, - { - "columnMatch": "ExecutableEmailContent", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Block", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "NA", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "critical", - "text": "{0}{1}" - } - ] - } - }, - { - "columnMatch": "OfficeChildProcess", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Block", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "NA", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "critical", - "text": "{0}{1}" - } - ] + "linkTarget": "Resource", + "showIcon": true } }, { - "columnMatch": "ExecutableOfficeContent", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Block", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "NA", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "critical", - "text": "{0}{1}" - } - ] - } - }, - { - "columnMatch": "OfficeProcessInjection", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Block", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "NA", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "critical", - "text": "{0}{1}" - } - ] - } + "columnMatch": "subscriptionId", + "formatter": 5 }, { - "columnMatch": "ScriptExecutableDownload", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "Block", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "==", - "thresholdValue": "NA", - "representation": "success", - "text": "{0}{1}" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "critical", - "text": "{0}{1}" - } - ] - } + "columnMatch": "resourceGroup", + "formatter": 5 }, { - "columnMatch": "ObfuscatedScript", + "columnMatch": "status", "formatter": 18, "formatOptions": { - "thresholdsOptions": "icons", + "thresholdsOptions": "colors", "thresholdsGrid": [ { "operator": "==", - "thresholdValue": "Block", - "representation": "success", + "thresholdValue": "Healthy", + "representation": "green", "text": "{0}{1}" }, { "operator": "==", - "thresholdValue": "NA", - "representation": "success", + "thresholdValue": "Unhealthy", + "representation": "red", "text": "{0}{1}" }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "critical", - "text": "{0}{1}" - } - ] - } - }, - { - "columnMatch": "AdobeReaderChildProcess", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ { "operator": "==", - "thresholdValue": "Block", - "representation": "success", + "thresholdValue": "Unknown-NoSoftwareInventory", + "representation": "gray", "text": "{0}{1}" }, { "operator": "==", - "thresholdValue": "NA", - "representation": "success", + "thresholdValue": "Unknown-NoEndpointProtectionData", + "representation": "grayBlue", "text": "{0}{1}" }, { "operator": "Default", "thresholdValue": null, - "representation": "critical", + "representation": "gray", "text": "{0}{1}" } ] } } ], - "sortBy": [ - { - "itemKey": "OSPlatform", - "sortOrder": 1 - } - ], - "labelSettings": [ - { - "columnId": "DeviceName", - "label": "Resource" - }, - { - "columnId": "Compliant", - "label": "Health State" - }, - { - "columnId": "max_Timestamp", - "label": "Timestamp" - }, - { - "columnId": "OSPlatform", - "label": "OS Platform" - } - ] - }, - "sortBy": [ - { - "itemKey": "OSPlatform", - "sortOrder": 1 - } - ] - }, - "name": "query - 8" - }, - { - "type": 1, - "content": { - "json": "## Supporting information: Description of configuration items " - }, - "name": "text - 14" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "DeviceTvmSecureConfigurationAssessmentKB_CL\r\n| where ConfigurationId_s in (\"scid-2500\", \"scid-2501\", \"scid-2502\", \"scid-2503\", \"scid-2504\", \"scid-2505\", \"scid-2513\")\r\n| extend Config = case(\r\n ConfigurationId_s == \"scid-2500\", \"ExecutableEmailContent\",\r\n ConfigurationId_s == \"scid-2501\", \"OfficeChildProcess\",\r\n ConfigurationId_s == \"scid-2502\", \"ExecutableOfficeContent\",\r\n ConfigurationId_s == \"scid-2503\", \"OfficeProcessInjection\",\r\n ConfigurationId_s == \"scid-2504\", \"ScriptExecutableDownload\",\r\n ConfigurationId_s == \"scid-2505\", \"ObfuscatedScript\",\r\n ConfigurationId_s == \"scid-2513\", \"AdobeReaderChildProcess\",\r\n \"Error\"\r\n)\r\n| summarize arg_max(TimeGenerated, *) by ConfigurationId_s\r\n| parse ConfigurationDescription_s with * \"ASR rule \" ConfigurationDescription\r\n| extend ConfigurationDescription = strcat(\"This ASR rule \", ConfigurationDescription)\r\n| extend ConfigurationDescription = replace_string(ConfigurationDescription, \"
\", \" \")\r\n| project Config, ConfigurationName_s, ConfigurationDescription, RiskDescription_s, ConfigurationId_s, DocLink\r\n| order by ConfigurationId_s asc", - "size": 0, - "timeContext": { - "durationMs": 2592000000 - }, - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", - "crossComponentResources": [ - "{Workspace}" - ], - "gridSettings": { - "formatters": [ - { - "columnMatch": "Config", - "formatter": 0, - "formatOptions": { - "customColumnWidthSetting": "15%" - } - }, - { - "columnMatch": "ConfigurationName_s", - "formatter": 0, - "formatOptions": { - "customColumnWidthSetting": "25%" - } - }, - { - "columnMatch": "ConfigurationDescription", - "formatter": 0, - "formatOptions": { - "customColumnWidthSetting": "25%" - } - }, - { - "columnMatch": "RiskDescription_s", - "formatter": 0, - "formatOptions": { - "customColumnWidthSetting": "25%" - } - }, - { - "columnMatch": "ConfigurationId_s", - "formatter": 0, - "formatOptions": { - "customColumnWidthSetting": "5%" - } - }, - { - "columnMatch": "DocLink", - "formatter": 7, - "formatOptions": { - "linkTarget": "Url", - "linkLabel": "Link", - "customColumnWidthSetting": "5%" - } - } - ], + "hierarchySettings": { + "treeType": 1, + "groupBy": [ + "subscriptionId", + "resourceGroup" + ] + }, "labelSettings": [ { - "columnId": "Config", - "label": "Configuration Item" + "columnId": "subscriptionId", + "label": "Subscription" }, { - "columnId": "ConfigurationName_s", - "label": "Configuration Name" + "columnId": "resourceId", + "label": "Resource" }, { - "columnId": "ConfigurationDescription", - "label": "Configuration Description" + "columnId": "resourceType", + "label": "Resource Type" }, { - "columnId": "RiskDescription_s", - "label": "Risk Description" + "columnId": "status", + "label": "Health State" }, { - "columnId": "ConfigurationId_s", - "label": "Config Id" + "columnId": "appCompliant", + "label": "App Compliance" }, { - "columnId": "DocLink", - "label": "Link" + "columnId": "applications", + "label": "Non-compliant Apps" } ] } }, - "name": "query - 13" + "name": "query - 7" } ] }, - "conditionalVisibility": { - "parameterName": "tvmExists", - "comparison": "isEqualTo", - "value": "True" - }, "name": "group - 9" - }, - { - "type": 1, - "content": { - "json": "## Please make sure that you have selected the appropriate Sentinel workspace from the drop-down parameter above.\r\n\r\n### If you still see this message, it is because this strategy relies on data only available through a Microsoft Sentinel private preview feature. \r\n### To see this strategy, and to provide feedback on this and other private preview features for Microsoft Sentinel and other Microsoft security products, join our Customer Connection Program. \r\n### [Learn more here](https://techcommunity.microsoft.com/t5/security-compliance-and-identity/how-microsoft-security-wants-to-help-you-take-your-fandom-and/ba-p/3745057) or fill out the [form](https://www.aka.ms/JoinCCP) to join.", - "style": "warning" - }, - "conditionalVisibilities": [ - { - "parameterName": "Tab", - "comparison": "isEqualTo", - "value": "ap hardening" - }, - { - "parameterName": "tvmExists", - "comparison": "isEqualTo", - "value": "False" - } - ], - "name": "text - 2" } ] }, @@ -3386,7 +3034,7 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where name in~ (\r\n \"6240402e-f77c-46fa-9060-a7ce53997754\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n \"94290b00-4d0c-d7b4-7cea-064a9554e681\", // MFA should be enabled on accounts with owner permissions on subscriptions\r\n \"151e82c5-5341-a74b-1eb0-bc38d2c84bb5\", // MFA should be enabled on accounts with read permissions on subscriptions\r\n \"57e98606-6b1e-6193-0e3d-fe621387c16b\" // MFA should be enabled on accounts with write permissions on subscriptions\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6240402e-f77c-46fa-9060-a7ce53997754\", \"Res_Owner_MFA\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n name =~ \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", \"Res_Read_MFA\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n name =~ \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", \"Res_Write_MFA\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n name =~ \"94290b00-4d0c-d7b4-7cea-064a9554e681\", \"Sub_Owner_MFA\", // MFA should be enabled on accounts with owner permissions on subscriptions\r\n name =~ \"151e82c5-5341-a74b-1eb0-bc38d2c84bb5\", \"Sub_Read_MFA\", // MFA should be enabled on accounts with read permissions on subscriptions\r\n name =~ \"57e98606-6b1e-6193-0e3d-fe621387c16b\", \"Sub_Write_MFA\", // MFA should be enabled on accounts with write permissions on subscriptions\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Res_Owner_MFA = iff(Recommendations.Res_Owner_MFA == \"\", \"Unknown\", Recommendations.Res_Owner_MFA)\r\n| extend Res_Read_MFA = iff(Recommendations.Res_Read_MFA == \"\", \"Unknown\", Recommendations.Res_Read_MFA)\r\n| extend Res_Write_MFA = iff(Recommendations.Res_Write_MFA == \"\", \"Unknown\", Recommendations.Res_Write_MFA)\r\n| extend Sub_Owner_MFA = iff(Recommendations.Sub_Owner_MFA == \"\", \"Unknown\", Recommendations.Sub_Owner_MFA)\r\n| extend Sub_Read_MFA = iff(Recommendations.Sub_Read_MFA == \"\", \"Unknown\", Recommendations.Sub_Read_MFA)\r\n| extend Sub_Write_MFA = iff(Recommendations.Sub_Write_MFA == \"\", \"Unknown\", Recommendations.Sub_Write_MFA)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| summarize count = dcount(ResourceId) by State", + "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where name in~ (\r\n \"6240402e-f77c-46fa-9060-a7ce53997754\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\" // Accounts with write permissions on Azure resources should be MFA enabled\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6240402e-f77c-46fa-9060-a7ce53997754\", \"Res_Owner_MFA\", // Accounts with owner permissions on Azure resources should be MFA enabled\r\n name =~ \"dabc9bc4-b8a8-45bd-9a5a-43000df8aa1c\", \"Res_Read_MFA\", // Accounts with read permissions on Azure resources should be MFA enabled\r\n name =~ \"c0cb17b2-0607-48a7-b0e0-903ed22de39b\", \"Res_Write_MFA\", // Accounts with write permissions on Azure resources should be MFA enabled\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Res_Owner_MFA = iff(Recommendations.Res_Owner_MFA == \"\", \"Unknown\", Recommendations.Res_Owner_MFA)\r\n| extend Res_Read_MFA = iff(Recommendations.Res_Read_MFA == \"\", \"Unknown\", Recommendations.Res_Read_MFA)\r\n| extend Res_Write_MFA = iff(Recommendations.Res_Write_MFA == \"\", \"Unknown\", Recommendations.Res_Write_MFA)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| summarize count = dcount(ResourceId) by State", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3418,7 +3066,7 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where subscriptionId in~ ({Subscription:subid})\r\n| where name in~ (\r\n \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", // A maximum of 3 owners should be designated for subscriptions\r\n \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n// \"00c6d40b-e990-6acf-d4f3-471e747a27c4\", // Deprecated accounts should be removed from subscriptions\r\n \"e52064aa-6853-e252-a11e-dffc675689c2\", // Deprecated accounts with owner permissions should be removed from subscriptions\r\n \"c3b6ae71-f1f0-31b4-e6c1-d5951285d03d\", // External accounts with owner permissions should be removed from subscriptions\r\n// \"a8c6a4ad-d51e-88fe-2979-d3ee3c864f8b\", // External accounts with read permissions should be removed from subscriptions\r\n \"04e7147b-0deb-9796-2e5c-0336343ceb3d\", // External accounts with write permissions should be removed from subscriptions\r\n \"20606e75-05c4-48c0-9d97-add6daa2109a\", // Guest accounts with owner permissions on Azure resources should be removed\r\n// \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", // Guest accounts with read permissions on Azure resources should be removed\r\n \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\" // Guest accounts with write permissions on Azure resources should be removed\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", \"Max_3_Owners\", // A maximum of 3 owners should be designated for subscriptions\r\n name =~ \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", \"Remove_Blocked_Owner\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n name =~ \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", \"Remove_Blocked_ReadWrite\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n name =~ \"00c6d40b-e990-6acf-d4f3-471e747a27c4\", \"Remove_Deprecated_All\", // Deprecated accounts should be removed from subscriptions\r\n name =~ \"e52064aa-6853-e252-a11e-dffc675689c2\", \"Remove_Deprecated_Owner\", // Deprecated accounts with owner permissions should be removed from subscriptions\r\n name =~ \"c3b6ae71-f1f0-31b4-e6c1-d5951285d03d\", \"Remove_External_Owner\", // External accounts with owner permissions should be removed from subscriptions\r\n name =~ \"a8c6a4ad-d51e-88fe-2979-d3ee3c864f8b\", \"Remove_External_Read\", // External accounts with read permissions should be removed from subscriptions\r\n name =~ \"04e7147b-0deb-9796-2e5c-0336343ceb3d\", \"Remove_External_Write\", // External accounts with write permissions should be removed from subscriptions\r\n name =~ \"20606e75-05c4-48c0-9d97-add6daa2109a\", \"Remove_Guest_Owner\", // Guest accounts with owner permissions on Azure resources should be removed\r\n name =~ \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", \"Remove_Guest_Read\", // Guest accounts with read permissions on Azure resources should be removed\r\n name =~ \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\", \"Remove_Guest_Write\", // Guest accounts with write permissions on Azure resources should be removed\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Max_3_Owners = iff(Recommendations.Max_3_Owners == \"\", \"Unknown\", Recommendations.Max_3_Owners)\r\n| extend Remove_Blocked_Owner = iff(Recommendations.Remove_Blocked_Owner == \"\", \"Unknown\", Recommendations.Remove_Blocked_Owner)\r\n| extend Remove_Blocked_ReadWrite = iff(Recommendations.Remove_Blocked_ReadWrite == \"\", \"Unknown\", Recommendations.Remove_Blocked_ReadWrite)\r\n//| extend Remove_Deprecated_All = iff(Recommendations.Remove_Deprecated_All == \"\", \"Unknown\", Recommendations.Remove_Deprecated_All)\r\n| extend Remove_Deprecated_Owner = iff(Recommendations.Remove_Deprecated_Owner == \"\", \"Unknown\", Recommendations.Remove_Deprecated_Owner)\r\n| extend Remove_External_Owner = iff(Recommendations.Remove_External_Owner == \"\", \"Unknown\", Recommendations.Remove_External_Owner)\r\n//| extend Remove_External_Read = iff(Recommendations.Remove_External_Read == \"\", \"Unknown\", Recommendations.Remove_External_Read)\r\n| extend Remove_External_Write = iff(Recommendations.Remove_External_Write == \"\", \"Unknown\", Recommendations.Remove_External_Write)\r\n| extend Remove_Guest_Owner = iff(Recommendations.Remove_Guest_Owner == \"\", \"Unknown\", Recommendations.Remove_Guest_Owner)\r\n//| extend Remove_Guest_Read = iff(Recommendations.Remove_Guest_Read == \"\", \"Unknown\", Recommendations.Remove_Guest_Read)\r\n| extend Remove_Guest_Write = iff(Recommendations.Remove_Guest_Write == \"\", \"Unknown\", Recommendations.Remove_Guest_Write)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| summarize count=dcount(ResourceId) by State", + "query": "securityresources\r\n| where type == \"microsoft.security/assessments\"\r\n| where subscriptionId in~ ({Subscription:subid})\r\n| where name in~ (\r\n \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", // A maximum of 3 owners should be designated for subscriptions\r\n \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n \"20606e75-05c4-48c0-9d97-add6daa2109a\", // Guest accounts with owner permissions on Azure resources should be removed\r\n// \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", // Guest accounts with read permissions on Azure resources should be removed\r\n \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\" // Guest accounts with write permissions on Azure resources should be removed\r\n)\r\n| extend DisplayName = tostring(properties.displayName)\r\n| extend ResourceId = tostring(properties.resourceDetails.Id)\r\n| extend StatusCode = tostring(properties.status.code)\r\n| extend StatusCause = tostring(properties.status.cause)\r\n| extend StatusDescription = tostring(properties.status.description)\r\n| extend RecommendationId = case (\r\n name =~ \"6f90a6d6-d4d6-0794-0ec1-98fa77878c2e\", \"Max_3_Owners\", // A maximum of 3 owners should be designated for subscriptions\r\n name =~ \"050ac097-3dda-4d24-ab6d-82568e7a50cf\", \"Remove_Blocked_Owner\", // Blocked accounts with owner permissions on Azure resources should be removed\r\n name =~ \"1ff0b4c9-ed56-4de6-be9c-d7ab39645926\", \"Remove_Blocked_ReadWrite\", // Blocked accounts with read and write permissions on Azure resources should be removed \r\n name =~ \"20606e75-05c4-48c0-9d97-add6daa2109a\", \"Remove_Guest_Owner\", // Guest accounts with owner permissions on Azure resources should be removed\r\n name =~ \"fde1c0c9-0fd2-4ecc-87b5-98956cbc1095\", \"Remove_Guest_Read\", // Guest accounts with read permissions on Azure resources should be removed\r\n name =~ \"0354476c-a12a-4fcc-a79d-f0ab7ffffdbb\", \"Remove_Guest_Write\", // Guest accounts with write permissions on Azure resources should be removed\r\n \"Unknown Recommendation Id\"\r\n)\r\n| summarize Recommendations = make_bag(pack(RecommendationId, StatusCode)) by ResourceId\r\n//| evaluate bag_unpack(Recommendations) // evaluate operator not supported on Resource Graph, need to do manually\r\n| extend Max_3_Owners = iff(Recommendations.Max_3_Owners == \"\", \"Unknown\", Recommendations.Max_3_Owners)\r\n| extend Remove_Blocked_Owner = iff(Recommendations.Remove_Blocked_Owner == \"\", \"Unknown\", Recommendations.Remove_Blocked_Owner)\r\n| extend Remove_Blocked_ReadWrite = iff(Recommendations.Remove_Blocked_ReadWrite == \"\", \"Unknown\", Recommendations.Remove_Blocked_ReadWrite)\r\n| extend Remove_Guest_Owner = iff(Recommendations.Remove_Guest_Owner == \"\", \"Unknown\", Recommendations.Remove_Guest_Owner)\r\n//| extend Remove_Guest_Read = iff(Recommendations.Remove_Guest_Read == \"\", \"Unknown\", Recommendations.Remove_Guest_Read)\r\n| extend Remove_Guest_Write = iff(Recommendations.Remove_Guest_Write == \"\", \"Unknown\", Recommendations.Remove_Guest_Write)\r\n| extend PackedString=tostring(pack_all())\r\n| extend State = iff(PackedString contains \"NotApplicable\" or\r\n PackedString contains \"Unknown\", \"Unknown\", \"Healthy\")\r\n| extend State = iff(PackedString contains \"Unhealthy\", \"Unhealthy\", State)\r\n| summarize count=dcount(ResourceId) by State", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3642,13 +3290,12 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "DeviceTvmSecureConfigurationAssessment\r\n//| where OSPlatform != \"Linux\" //exclude Linux machines\r\n| where ConfigurationId in (\r\n \"scid-2500\", // Block executable content from email client and webmail\r\n \"scid-2501\", // Block Office applications from creating child processes\r\n \"scid-2502\", // Block Office applications from creating executable content\r\n \"scid-2503\", // Block Office applications from injecting code into other processes\r\n \"scid-2504\", // Block JavaScript or VBScript from launching downloaded executable content\r\n \"scid-2505\", // Block execution of potentially obfuscated scripts\r\n \"scid-2513\" // Block Adobe Reader from creating child processes\r\n)\r\n| extend Setting = tostring(Context[0].Unknown1)\r\n| where Setting != \"Unknown\"\r\n| extend Setting = iff(IsApplicable == false, \"NA\", Setting)\r\n| summarize arg_max(Timestamp, Setting) by DeviceId, DeviceName, OSPlatform, ConfigurationId\r\n| summarize make_bag(pack(ConfigurationId, Setting)), max(Timestamp) by DeviceId, DeviceName, OSPlatform\r\n| evaluate bag_unpack(bag_)\r\n| project-rename\r\n ExecutableEmailContent = [\"scid-2500\"],\r\n OfficeChildProcess = [\"scid-2501\"],\r\n ExecutableOfficeContent = [\"scid-2502\"],\r\n OfficeProcessInjection = [\"scid-2503\"],\r\n ScriptExecutableDownload = [\"scid-2504\"],\r\n ObfuscatedScript = [\"scid-2505\"],\r\n AdobeReaderChildProcess = [\"scid-2513\"]\r\n// assess compliance\r\n| extend Compliant = iff(ExecutableEmailContent in~ (\"Block\", \"NA\"), \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeChildProcess in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ExecutableOfficeContent in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeProcessInjection in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ScriptExecutableDownload in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(ObfuscatedScript in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(AdobeReaderChildProcess in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| summarize count = dcount(DeviceId) by Compliant", + "query": "securityresources\r\n| where type == \"microsoft.security/softwareinventories\"\r\n| parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n| parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n| extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n| where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n| distinct subscriptionId, resourceGroup, resourceId, resourceType\r\n| join kind = leftouter (\r\n securityresources\r\n | where type == \"microsoft.security/softwareinventories\"\r\n | parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend vendor = tostring(properties.vendor),\r\n software = tostring(properties.softwareName),\r\n version = tostring(properties.version)\r\n | where vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\")\r\n | summarize applications = make_list(pack(\"Vendor\", vendor, \"Software\", software, \"Version\", version)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend appCompliant = iff(isnull(applications), \"Healthy\", \"Unhealthy\")\r\n| project subscriptionId, resourceGroup, resourceId = tolower(resourceId), resourceType, appCompliant, applications\r\n| join kind = fullouter (\r\n resources\r\n //| where type in~ (\"microsoft.compute/virtualmachines\", \"microsoft.classiccompute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | where type in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend osType = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.storageProfile.osDisk.osType), tostring(properties.osType)),\r\n osName = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.extended.instanceView.osName), tostring(properties.osName)), // blank if machine stopped, deallocated\r\n osVersion = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.extended.instanceView.osVersion), tostring(properties.osVersion)), // blank if machine stopped, deallocated\r\n publisher = tostring(properties.storageProfile.imageReference.publisher),\r\n exactVersion = tostring(properties.storageProfile.imageReference.exactVersion),\r\n sku = iff(type =~ \"microsoft.compute/virtualmachines\", tostring(properties.storageProfile.imageReference.sku), tostring(properties.osSku)),\r\n offer = tostring(properties.storageProfile.imageReference.offer)\r\n | project subscriptionId, resourceGroup, resourceId = tolower(id), resourceType = type, name, osType, osName, osVersion, sku, publisher, exactVersion, offer\r\n) on resourceId\r\n| extend subscriptionId = iff(isempty(subscriptionId), subscriptionId1, subscriptionId)\r\n| extend resourceGroup = iff(isempty(resourceGroup), resourceGroup1, resourceGroup)\r\n| extend resourceId = iff(isempty(resourceId), resourceId1, resourceId)\r\n| extend resourceType = iff(isempty(resourceType), resourceType1, resourceType)\r\n//| project-away subscriptionId1, resourceGroup1, resourceId1, resourceType1\r\n| extend appCompliant = iff(isempty(appCompliant), \"Unknown\", appCompliant)\r\n| summarize count = dcount(resourceId) by appCompliant", "size": 4, - "timeContextFromParameter": "TimeRange", - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ - "{Workspace}" + "{Subscription}" ], "visualization": "piechart", "chartSettings": { @@ -3660,6 +3307,10 @@ { "seriesName": "Healthy", "color": "green" + }, + { + "seriesName": "Unknown", + "color": "gray" } ] } @@ -3671,13 +3322,12 @@ "type": 3, "content": { "version": "KqlItem/1.0", - "query": "DeviceTvmSecureConfigurationAssessment\r\n| where ConfigurationId in (\r\n \"scid-2500\", // ASR: Block executable content from email client and webmail\r\n \"scid-2506\", // ASR: Block Win32 API calls from Office macros\r\n \"scid-2010\", // AV: Defender AV mode: 0 == active, 1 == passive, 4 == EDR block mode\r\n \"scid-2011\", // AV: Defender AV signature (Windows)\r\n// \"scid-2012\", // AV: Defender enable RTP (Widows)\r\n// \"scid-2016\", // AV: Defender enable cloud protection (Windows)\r\n// \"scid-6090\", // AV: Defender enable RTP (Linux)\r\n// \"scid-6094\", // AV: Defender enable cloud protection (Linux)\r\n \"scid-6095\" // AV: Defender AV signature (Linux)\r\n)\r\n| extend Setting = case(\r\n ConfigurationId == \"scid-2500\", tostring(Context[0].Unknown1),\r\n ConfigurationId == \"scid-2506\", tostring(Context[0].Unknown1),\r\n ConfigurationId == \"scid-2010\", tostring(Context[0].AntiVirusMode),\r\n ConfigurationId == \"scid-2011\", tostring(Context[0].AntiVirusSignatureLastUpdateTime),\r\n ConfigurationId == \"scid-6095\", tostring(Context[0].AntiVirusSignatureLastUpdateTime),\r\n \"Error\"\r\n)\r\n| extend Setting = iff(IsApplicable == false, \"NA\", Setting)\r\n| summarize arg_max(Timestamp, Setting) by DeviceId, DeviceName, OSPlatform, ConfigurationId\r\n| summarize make_bag(pack(ConfigurationId, Setting)), max(Timestamp) by DeviceId, DeviceName, OSPlatform\r\n| evaluate bag_unpack(bag_)\r\n| extend AvSignatureUpdateTime = iff([\"scid-2011\"] == \"NA\", [\"scid-6095\"], [\"scid-2011\"])\r\n| project-away [\"scid-2011\"], [\"scid-6095\"]\r\n| project-rename ExecutableEmailContent = [\"scid-2500\"], OfficeMacroWin32ApiCalls = [\"scid-2506\"], AvMode = [\"scid-2010\"]\r\n| extend TimeSinceAvSignatureUpdate = max_Timestamp - todatetime(AvSignatureUpdateTime)\r\n// assess compliance\r\n| extend Compliant = iff(ExecutableEmailContent in~ (\"Block\", \"NA\"), \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(OfficeMacroWin32ApiCalls in~ (\"Block\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(AvMode in (\"0\", \"1\", \"4\", \"NA\") and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| extend Compliant = iff(TimeSinceAvSignatureUpdate < 7d and Compliant == \"Healthy\", \"Healthy\", \"Unhealthy\")\r\n| where not(AvMode in~ (\"\", \"Unknown\") and ExecutableEmailContent in~ (\"\", \"Unknown\") and AvSignatureUpdateTime == \"\")\r\n| summarize count = dcount(DeviceId) by Compliant", + "query": "securityresources\r\n| where type == \"microsoft.security/softwareinventories\"\r\n| parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n| parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n| extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n| where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n| distinct subscriptionId, resourceGroup, resourceId, resourceType\r\n| join kind = leftouter (\r\n securityresources\r\n | where type == \"microsoft.security/softwareinventories\"\r\n | parse id with resourceId \"/providers/Microsoft.Security/softwareInventories/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend vendor = tostring(properties.vendor),\r\n software = tostring(properties.softwareName),\r\n version = tostring(properties.version)\r\n | where (vendor =~ \"adobe\" and software contains \"acrobat\") or \r\n (vendor =~ \"google\" and software contains \"chrome\") or\r\n (vendor =~ \"mozilla\" and software contains \"firefox\") or\r\n //(vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\", \"edge_chromium-based\", \"internet_explorer\", \"teams\"))\r\n (vendor =~ \"microsoft\" and software in~ (\"office\", \"office_web_components\", \"teams\"))\r\n | summarize applications = make_list(pack(\"Vendor\", vendor, \"Software\", software, \"Version\", version)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend appCompliant = iff(isnull(applications), \"Healthy\", \"Unhealthy\")\r\n| project subscriptionId, resourceGroup, resourceId = tolower(resourceId), resourceType, appCompliant, applications\r\n| join kind = fullouter (\r\n securityresources\r\n | where type == \"microsoft.security/assessments\"\r\n | where tostring(name) in~ (\r\n \"83f577bd-a1b6-b7e1-0891-12ca19d1e6df\", // \"Install endpoint protection solution on virtual machines\" (legacy)\r\n \"4fb67663-9ab9-475d-b026-8c544cced439\", // \"Endpoint protection should be installed on machines\"\r\n \"383cf3bc-fdf9-4a02-120a-3e7e36c6bfee\", // \"Endpoint protection should be installed on machines\" (legacy)\r\n \"21300918-b2e3-0346-785f-c77ff57d243b\", // \"Endpoint protection should be installed on virtual machine scale sets\"\r\n \"37a3689a-818e-4a0e-82ac-b1392b9bb000\", // \"Endpoint protection health issues on machines should be resolved\"\r\n \"3bcd234d-c9c7-c2a2-89e0-c01f419c1a8a\", // \"Endpoint protection health issues on machines should be resolved\" (legacy)\r\n \"e71020c2-860c-3235-cd39-04f3f8c936d2\" // \"Endpoint protection health issues on virtual machine scale sets should be resolved\"\r\n )\r\n | parse id with resourceId \"/providers/Microsoft.Security/assessments/\" *\r\n | parse resourceId with * \"/providers/\" resourceType1 \"/\" resourceType2 \"/\" *\r\n | extend resourceType = strcat(resourceType1, \"/\", resourceType2)\r\n | where resourceType in~ (\"microsoft.compute/virtualmachines\", \"microsoft.hybridcompute/machines\")\r\n | extend resourceId = tolower(resourceId)\r\n | extend displayName = tostring(properties.displayName)\r\n //| extend statusChangeDate = format_datetime(todatetime(properties.status.statusChangeDate), \"yyyy-MM-dd\")\r\n | extend statusCode = tostring(properties.status.code)\r\n | extend statusCause = tostring(properties.status.cause)\r\n | extend statusDescription = tostring(properties.status.description)\r\n | extend statusChangeDate = todatetime(properties.status.statusChangeDate)\r\n | extend osName = tostring(properties.additionalData.OSName)\r\n | extend link = tostring(properties.additionalData.subAssessmentsLink)\r\n | project subscriptionId, resourceGroup, resourceId, resourceType, displayName, statusCode, statusCause, statusDescription, statusChangeDate, osName, link, name\r\n | extend recommendation = case (\r\n name =~ \"83f577bd-a1b6-b7e1-0891-12ca19d1e6df\", \"EP_Installed\", // \"Install endpoint protection solution on virtual machines\" (legacy)\r\n name =~ \"4fb67663-9ab9-475d-b026-8c544cced439\", \"EP_Installed\", // \"Endpoint protection should be installed on machines\"\r\n name =~ \"383cf3bc-fdf9-4a02-120a-3e7e36c6bfee\", \"EP_Installed\", // \"Endpoint protection should be installed on machines\" (legacy)\r\n name =~ \"21300918-b2e3-0346-785f-c77ff57d243b\", \"EP_Installed\", // \"Endpoint protection should be installed on virtual machine scale sets\"\r\n name =~ \"37a3689a-818e-4a0e-82ac-b1392b9bb000\", \"EP_Status\", // \"Endpoint protection health issues on machines should be resolved\"\r\n name =~ \"3bcd234d-c9c7-c2a2-89e0-c01f419c1a8a\", \"EP_Status\", // \"Endpoint protection health issues on machines should be resolved\" (legacy)\r\n name =~ \"e71020c2-860c-3235-cd39-04f3f8c936d2\", \"EP_Status\", // \"Endpoint protection health issues on virtual machine scale sets should be resolved\"\r\n \"Unknown\"\r\n )\r\n | summarize arg_max(statusChangeDate, *) by resourceId, recommendation\r\n | extend statusCode = iff(statusCode =~ \"NotApplicable\", strcat(\"NA-\", statusCause), statusCode)\r\n | summarize endpointProtection = make_bag(pack(recommendation, statusCode)) by subscriptionId, resourceGroup, resourceId, resourceType\r\n) on resourceId\r\n| extend subscriptionId = iff(isempty(subscriptionId), subscriptionId1, subscriptionId)\r\n| extend resourceGroup = iff(isempty(resourceGroup), resourceGroup1, resourceGroup)\r\n| extend resourceId = iff(isempty(resourceId), resourceId1, resourceId)\r\n| extend resourceType = iff(isempty(resourceType), resourceType1, resourceType)\r\n| project-away subscriptionId1, resourceGroup1, resourceId1, resourceType1\r\n| extend appCompliant = iff(isempty(appCompliant), \"Unknown-NoSoftwareInventory\", appCompliant)\r\n| extend endpointProtection = iff(isnull(endpointProtection), parse_json('{\"EP_Installed\":\"Unknown\",\"EP_Status\":\"Unknown\"}'), endpointProtection)\r\n| extend EP_Installed = tostring(endpointProtection.EP_Installed)\r\n| extend EP_Status = tostring(endpointProtection.EP_Status)\r\n| project-away endpointProtection\r\n| extend status = appCompliant\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Status == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"Unknown\", \"Unknown-NoEndpointProtectionData\", status)\r\n| extend status = iff(status == \"Healthy\" and EP_Installed == \"NA-OffByPolicy\", \"Unknown-OffByPolicy\", status)\r\n| extend status = iff(status == \"Unknown-NoSoftwareInventory\" and EP_Installed == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status == \"Unknown-NoSoftwareInventory\" and EP_Status == \"Unhealthy\", \"Unhealthy\", status)\r\n| extend status = iff(status startswith \"Unknown\", \"Unknown\", status)\r\n| summarize count = dcount(resourceId) by status", "size": 4, - "timeContextFromParameter": "TimeRange", - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ - "{Workspace}" + "{Subscription}" ], "visualization": "piechart", "chartSettings": { @@ -3689,6 +3339,10 @@ { "seriesName": "Healthy", "color": "green" + }, + { + "seriesName": "Unknown", + "color": "gray" } ] } @@ -3698,18 +3352,6 @@ } ] }, - "conditionalVisibilities": [ - { - "parameterName": "Tab", - "comparison": "isEqualTo", - "value": "General" - }, - { - "parameterName": "tvmExists", - "comparison": "isEqualTo", - "value": "True" - } - ], "name": "group - 12" } ] @@ -3726,6 +3368,6 @@ } ], "fallbackResourceIds": [], - "fromTemplateId": "sentinel-AcscEssential8Workbook", + "fromTemplateId": "sentinel-AcscEssential8", "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" -} +} \ No newline at end of file diff --git a/Workbooks/Images/Preview/AcscEssential8Black1.png b/Workbooks/Images/Preview/AcscEssential8Black1.png index cc5cbca4973..67ead11ad19 100644 Binary files a/Workbooks/Images/Preview/AcscEssential8Black1.png and b/Workbooks/Images/Preview/AcscEssential8Black1.png differ diff --git a/Workbooks/Images/Preview/AcscEssential8Black2.png b/Workbooks/Images/Preview/AcscEssential8Black2.png index 3a58edff3d9..59d06b6a6d2 100644 Binary files a/Workbooks/Images/Preview/AcscEssential8Black2.png and b/Workbooks/Images/Preview/AcscEssential8Black2.png differ diff --git a/Workbooks/Images/Preview/AcscEssential8White1.png b/Workbooks/Images/Preview/AcscEssential8White1.png index b264af70b72..de6dd55c3e5 100644 Binary files a/Workbooks/Images/Preview/AcscEssential8White1.png and b/Workbooks/Images/Preview/AcscEssential8White1.png differ diff --git a/Workbooks/Images/Preview/AcscEssential8White2.png b/Workbooks/Images/Preview/AcscEssential8White2.png index 739a3146f5e..bd67dd28781 100644 Binary files a/Workbooks/Images/Preview/AcscEssential8White2.png and b/Workbooks/Images/Preview/AcscEssential8White2.png differ diff --git a/Workbooks/WorkbooksMetadata.json b/Workbooks/WorkbooksMetadata.json index eb491bb2688..e6f5c2671da 100644 --- a/Workbooks/WorkbooksMetadata.json +++ b/Workbooks/WorkbooksMetadata.json @@ -3473,7 +3473,7 @@ "dataTypesDependencies": [ "DeviceTvmSecureConfigurationAssessment" ], "dataConnectorsDependencies": [], "previewImagesFileNames": [ "AcscEssential8Black1.png", "AcscEssential8White1.png", "AcscEssential8Black2.png", "AcscEssential8White2.png" ], - "version": "1.0.0", + "version": "2.0.0", "title": "ACSC Essential 8", "templateRelativePath": "AcscEssential8.json", "subtitle": "",