diff --git a/checklists-ext/fullwaf_checklist.en.json b/checklists-ext/fullwaf_checklist.en.json index 06dbaba2..70daf38c 100644 --- a/checklists-ext/fullwaf_checklist.en.json +++ b/checklists-ext/fullwaf_checklist.en.json @@ -8050,6 +8050,17 @@ "text": "Store passwords, secerts and keys in Azure key vault", "waf": "Reliability" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "You can store credentials or secret values in an Azure Key Vault and use them during pipeline execution to pass to your activities.", + "guid": "a3aec2c4-e243-46b0-936d-b55e17960eee", + "link": "https://learn.microsoft.com/azure/data-factory/how-to-use-azure-key-vault-secrets-pipeline-activities", + "service": "Data Factory", + "severity": "Medium", + "text": "Use Azure Key Vault secrets in pipeline activities", + "waf": "Reliability" + }, { "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", @@ -8081,6 +8092,15 @@ "text": "Separate and limit highly privileged/administrative users and enable MFA and conditional policies", "waf": "Reliability" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "guid": "4e4f1854-287d-45cd-a126-cc032af5b1fc", + "service": "Data Factory", + "severity": "Medium", + "text": "Disable access over public internet and configure either firewall rules or trusted services rules", + "waf": "Reliability" + }, { "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", @@ -8111,6 +8131,17 @@ "text": "Configure managed private endpoints to connect to resources using managed azure IR", "waf": "Reliability" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "By using Azure Private Link, you can connect to various platform as a service (PaaS) deployments in Azure via a private endpoint. A private endpoint is a private IP address within a specific virtual network and subnet", + "guid": "b47a393a-0804-4272-a479-8b1578b219a4", + "link": "https://learn.microsoft.com/azure/data-factory/data-factory-private-link", + "service": "Data Factory", + "severity": "Medium", + "text": "Configure Private Links to connect to sources in customer Vnet and data factory", + "waf": "Reliability" + }, { "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", @@ -8152,6 +8183,28 @@ "text": "Store passwords, secrets in Azure Key Vault", "waf": "Reliability" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "You can store credentials or secret values in an Azure Key Vault and use them during pipeline execution to pass to your activities.", + "guid": "6f4a1652-bddd-4ea8-a487-cdec4861bc3b", + "link": "https://learn.microsoft.com/azure/data-factory/how-to-use-azure-key-vault-secrets-pipeline-activities", + "service": "Data Factory", + "severity": "Medium", + "text": "Use Azure Key Vault secrets in pipeline activities", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "You can encrypt and store credentials for any of your on-premises data stores (linked services with sensitive information) on a machine with self-hosted integration runtime.", + "guid": "c14aeb7e-66e8-4d9a-9bec-218e6436b173", + "link": "https://learn.microsoft.com/azure/data-factory/encrypt-credentials-self-hosted-integration-runtime", + "service": "Data Factory", + "severity": "Medium", + "text": "Encrypt credentials for on-premises using SHIR data stores in Azure Data Factory", + "waf": "Reliability" + }, { "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", "guid": "6db55f57-9603-4334-adf9-cc23418db612", @@ -8416,6 +8469,17 @@ "text": "Limit cluster creation rights.", "waf": "Reliability" }, + { + "arm-service": "Microsoft.Databricks/workspaces", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "Account admins can configure a workspace setting called RestrictWorkspaceAdmins to restrict workspace admins to only change a job owner to themselves and the job run as setting to a service principal that they have the Service Principal User role on.", + "guid": "6b57dfc6-5546-41e1-a3e3-453a3c863964", + "link": "https://learn.microsoft.com/azure/databricks/admin/workspace-settings/restrict-workspace-admins", + "service": "Databricks", + "severity": "High", + "text": "Restrict workspace admins", + "waf": "Reliability" + }, { "arm-service": "Microsoft.Databricks/workspaces", "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", @@ -11666,6 +11730,108 @@ "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", "waf": "Reliability" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Data Factory", + "severity": "High", + "text": "Reference Databricks HA/DR playbook", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Data Factory", + "severity": "Low", + "text": "Use Databricks Sync", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Data Factory", + "severity": "Medium", + "text": "Backup your workspace configuration including ARM templates and secret scopes", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Data Factory", + "severity": "Medium", + "text": "Share metaData across different Databricks workspaces using Hive external metastore", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Data Factory", + "severity": "Medium", + "text": "Plan Disaster Recovery strategy in Databricks using the Hive External Metastore", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Data Factory", + "severity": "Medium", + "text": "Backup your data with deep and shallow clones", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "Download the blob using the secondary endpoint in RAGRS storage account", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Data Factory", + "severity": "Medium", + "text": "Backup your data to Azure Storage RA-GRS", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Data Factory", + "severity": "High", + "text": "Backup your code with DevOps", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Data Factory", + "severity": "High", + "text": "Plan for Disaster recovery using Active/Active or Active/Passive Configuration", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "Migration package to log all Databricks resources for backup and/or migrating to another Databricks workspace", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "link": "https://github.com/databrickslabs/migrate", + "service": "Data Factory", + "severity": "Medium", + "text": "Use Databricks Migration tools", + "waf": "Reliability" + }, { "checklist": "Identity Review Checklist", "guid": "bb235c70-5e17-496f-bedf-a8a4c8cdec4c", diff --git a/checklists/checklist.en.master.json b/checklists/checklist.en.master.json index f3f6709b..f2fbf17f 100644 --- a/checklists/checklist.en.master.json +++ b/checklists/checklist.en.master.json @@ -238,8 +238,8 @@ "guid": "c851fd44-7cf1-459c-95a4-f6455d75a981", "link": "https://learn.microsoft.com/azure/architecture/guide/multitenant/approaches/cost-management-allocation", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "severity": "Medium", "subcategory": "Cost Optimization", @@ -416,8 +416,8 @@ "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#cross-region-disaster-recovery-and-business-continuity", "service": "Container Apps", "services": [ - "TrafficManager", - "FrontDoor" + "FrontDoor", + "TrafficManager" ], "severity": "High", "subcategory": "High Availability", @@ -836,8 +836,8 @@ "link": "https://learn.microsoft.com/azure/virtual-machines/managed-disks-overview#temporary-disk", "service": "VM", "services": [ - "VM", "Storage", + "VM", "SQL" ], "severity": "Medium", @@ -853,9 +853,9 @@ "link": "https://learn.microsoft.com/azure/reliability/availability-zones-overview", "service": "VM", "services": [ + "ACR", "Storage", - "VM", - "ACR" + "VM" ], "severity": "Medium", "subcategory": "Virtual Machines", @@ -885,8 +885,8 @@ "link": "https://learn.microsoft.com/azure/virtual-machines/availability", "service": "VM", "services": [ - "VM", - "ASR" + "ASR", + "VM" ], "severity": "High", "subcategory": "Virtual Machines", @@ -1095,8 +1095,8 @@ "guid": "fe237de2-43b1-46c3-8d7a-a9b7570449aa", "link": "https://learn.microsoft.com/azure/well-architected/devops/automation-infrastructure", "services": [ - "RBAC", - "ASR" + "ASR", + "RBAC" ], "severity": "Medium", "subcategory": "DevOps", @@ -1138,8 +1138,8 @@ "guid": "ced126cd-032a-4f5b-8fc6-998a535e3378", "link": "https://learn.microsoft.com/azure/application-gateway/overview-v2", "services": [ - "AppGW", - "Storage" + "Storage", + "AppGW" ], "severity": "High", "subcategory": "Application Gateways", @@ -1167,10 +1167,10 @@ "guid": "8df03a82-2cd4-463c-abbc-8ac299ebc92a", "link": "https://learn.microsoft.com/azure/networking/disaster-recovery-dns-traffic-manager", "services": [ - "TrafficManager", - "DNS", "ASR", - "Monitor" + "TrafficManager", + "Monitor", + "DNS" ], "severity": "Low", "subcategory": "DNS", @@ -1185,9 +1185,9 @@ "link": "https://learn.microsoft.com/azure/dns/tutorial-dns-private-resolver-failover", "service": "DNS", "services": [ - "DNS", + "ACR", "ASR", - "ACR" + "DNS" ], "severity": "Low", "subcategory": "DNS", @@ -1230,8 +1230,8 @@ "guid": "a359c373-e7dd-4616-83a3-64a907ebae48", "link": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering", "services": [ - "ExpressRoute", - "Backup" + "Backup", + "ExpressRoute" ], "severity": "Medium", "subcategory": "ExpressRoute", @@ -1246,9 +1246,9 @@ "link": "https://learn.microsoft.com/azure/expressroute/use-s2s-vpn-as-backup-for-expressroute-privatepeering", "services": [ "Cost", + "Backup", "ExpressRoute", - "VPN", - "Backup" + "VPN" ], "severity": "Low", "subcategory": "ExpressRoute", @@ -1321,8 +1321,8 @@ "guid": "927139b8-2110-42db-b6ea-f11e6f843e53", "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-highlyavailable", "services": [ - "VPN", - "ACR" + "ACR", + "VPN" ], "severity": "Medium", "subcategory": "VPN Gateways", @@ -1362,8 +1362,8 @@ "guid": "aa359271-8e6e-4205-8725-769e46691e88", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#azure-subscription-and-service-limits", "services": [ - "Entra", - "Arc" + "Arc", + "Entra" ], "severity": "Medium", "subcategory": "Capacity Planning", @@ -1377,8 +1377,8 @@ "guid": "deace4bb-1deb-44c6-9fc3-fc14eeaa3692", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#azure-resource-providers", "services": [ - "Subscriptions", - "Arc" + "Arc", + "Subscriptions" ], "severity": "High", "subcategory": "General", @@ -1447,8 +1447,8 @@ "guid": "f9ccbd86-8266-4abc-a264-f9a19bf39d95", "link": "https://learn.microsoft.com/azure/azure-arc/servers/organize-inventory-servers#organize-resources-with-built-in-azure-hierarchies", "services": [ - "Subscriptions", - "Arc" + "Arc", + "Subscriptions" ], "severity": "Low", "subcategory": "Organization", @@ -1462,9 +1462,9 @@ "guid": "9bf39d95-d44c-47c8-a19c-a1f6d5215ae5", "link": "https://learn.microsoft.com/azure/azure-arc/servers/security-overview#identity-and-access-control", "services": [ - "Entra", + "Arc", "RBAC", - "Arc" + "Entra" ], "severity": "Medium", "subcategory": "Access", @@ -1477,9 +1477,9 @@ "guid": "14ba34d4-585e-4111-89bd-7ba012f7b94e", "link": "https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/tutorial-windows-vm-access-nonaad", "services": [ + "Arc", "AKV", - "Entra", - "Arc" + "Entra" ], "severity": "Low", "subcategory": "Access", @@ -1493,9 +1493,9 @@ "guid": "35ac9322-23e1-4380-8523-081a94174158", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#azure-subscription-and-service-limits", "services": [ + "Arc", "Entra", - "Subscriptions", - "Arc" + "Subscriptions" ], "severity": "High", "subcategory": "Requirements", @@ -1509,9 +1509,9 @@ "guid": "33ee7ad6-c6d3-4733-865c-7acbe44bbe60", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#required-permissions", "services": [ - "Entra", + "Arc", "RBAC", - "Arc" + "Entra" ], "severity": "Medium", "subcategory": "Requirements", @@ -1525,9 +1525,9 @@ "guid": "9d79f2e8-7778-4424-a516-775c6fa95b96", "link": "https://learn.microsoft.com/azure/azure-arc/servers/onboard-service-principal#create-a-service-principal-for-onboarding-at-scale", "services": [ - "Entra", + "Arc", "RBAC", - "Arc" + "Entra" ], "severity": "Medium", "subcategory": "Security", @@ -1541,9 +1541,9 @@ "guid": "ad88408e-3727-434b-a76b-a28f21459013", "link": "https://learn.microsoft.com/azure/azure-arc/servers/onboard-service-principal#create-a-service-principal-for-onboarding-at-scale", "services": [ - "Entra", + "Arc", "RBAC", - "Arc" + "Entra" ], "severity": "Medium", "subcategory": "Security", @@ -1557,9 +1557,9 @@ "guid": "65d38e53-f9cc-4bd8-9826-6abca264f9a1", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#required-permissions", "services": [ - "Entra", + "Arc", "RBAC", - "Arc" + "Entra" ], "severity": "Medium", "subcategory": "Security", @@ -1573,8 +1573,8 @@ "guid": "6ee79d6b-5c2a-4364-a4b6-9bad38aad53c", "link": "https://learn.microsoft.com/azure/azure-arc/servers/plan-at-scale-deployment", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -1588,8 +1588,8 @@ "guid": "c78e1d76-6673-457c-9496-74c5ed85b859", "link": "https://learn.microsoft.com/azure/azure-arc/servers/manage-agent#upgrade-the-agent", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "High", "subcategory": "Management", @@ -1603,9 +1603,9 @@ "guid": "c7733be2-a1a2-47b7-95a9-1be1f388ff39", "link": "https://learn.microsoft.com/azure/azure-arc/servers/manage-vm-extensions", "services": [ - "AzurePolicy", + "Arc", "Monitor", - "Arc" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Management", @@ -1620,8 +1620,8 @@ "guid": "4c2bd463-cbbb-4c86-a195-abb91a4ed90d", "link": "https://learn.microsoft.com/azure/azure-arc/servers/manage-automatic-vm-extension-upgrade?tabs=azure-portal", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "High", "subcategory": "Management", @@ -1635,8 +1635,8 @@ "guid": "7a927c39-74d1-4102-aac6-aae01e6a84de", "link": "https://learn.microsoft.com/azure/governance/machine-configuration/overview", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -1649,8 +1649,8 @@ "guid": "37b6b780-cbaf-4e6c-9658-9d457a927c39", "link": "https://learn.microsoft.com/azure/azure-arc/servers/plan-at-scale-deployment#phase-3-manage-and-operate", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -1663,8 +1663,8 @@ "guid": "74d1102c-ac6a-4ae0-8e6a-84de5df47d2d", "link": "https://learn.microsoft.com/azure/azure-monitor/agents/log-analytics-agent#data-collected", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -1677,8 +1677,8 @@ "guid": "92881b1c-d5d1-4e54-a296-59e3958fd782", "link": "https://learn.microsoft.com/azure/service-health/resource-health-alert-monitor-guide", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -1691,8 +1691,8 @@ "guid": "89c93555-6d02-4bfe-9564-b0d834a34872", "link": "https://learn.microsoft.com/azure/azure-arc/servers/learn/tutorial-enable-vm-insights", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -1705,8 +1705,8 @@ "guid": "5df47d2d-9288-41b1-ad5d-1e54a29659e3", "link": "https://learn.microsoft.com/azure/azure-arc/servers/plan-at-scale-deployment#phase-3-manage-and-operate", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -1721,9 +1721,9 @@ "guid": "ae2cc84c-37b6-4b78-8cba-fe6c46589d45", "link": "https://learn.microsoft.com/azure/update-manager/scheduled-patching?tabs=schedule-updates-single-machine%2Cschedule-updates-scale-overview%2Cwindows-maintenance", "services": [ - "Monitor", "ACR", - "Arc" + "Arc", + "Monitor" ], "severity": "Low", "subcategory": "Security", @@ -1765,10 +1765,10 @@ "guid": "94174158-33ee-47ad-9c6d-3733165c7acb", "link": "https://learn.microsoft.com/azure/azure-arc/servers/private-link-security", "services": [ + "Arc", "PrivateLink", "ExpressRoute", - "VPN", - "Arc" + "VPN" ], "severity": "Medium", "subcategory": "Networking", @@ -1824,9 +1824,9 @@ "guid": "a264f9a1-9bf3-49d9-9d44-c7c8919ca1f6", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/hybrid/arc-enabled-servers/eslz-arc-servers-connectivity#define-extensions-connectivity-method", "services": [ + "Arc", "PrivateLink", - "Monitor", - "Arc" + "Monitor" ], "severity": "Low", "subcategory": "Networking", @@ -1839,8 +1839,8 @@ "guid": "ac6aae01-e6a8-44de-9df4-7d2d92881b1c", "link": "https://learn.microsoft.com/azure/governance/policy/", "services": [ - "AzurePolicy", - "Arc" + "Arc", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Management", @@ -1866,8 +1866,8 @@ "guid": "667357c4-4967-44c5-bd85-b859c7733be2", "link": "https://learn.microsoft.com/azure/governance/machine-configuration/machine-configuration-create", "services": [ - "AzurePolicy", - "Arc" + "Arc", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Management", @@ -1880,8 +1880,8 @@ "guid": "49674c5e-d85b-4859-a773-3be2a1a27b77", "link": "https://learn.microsoft.com/azure/automation/change-tracking/overview", "services": [ - "Monitor", - "Arc" + "Arc", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -1907,8 +1907,8 @@ "guid": "195abb91-a4ed-490d-ae2c-c84c37b6b780", "link": "https://learn.microsoft.com/azure/key-vault/general/basic-concepts", "services": [ - "AKV", - "Arc" + "Arc", + "AKV" ], "severity": "Medium", "subcategory": "Secrets", @@ -1923,9 +1923,9 @@ "link": "https://learn.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal#option-2-create-a-new-application-secret", "services": [ "AKV", + "Arc", "Storage", - "Entra", - "Arc" + "Entra" ], "severity": "High", "subcategory": "Secrets", @@ -1939,8 +1939,8 @@ "guid": "a1a27b77-5a91-4be1-b388-ff394c2bd463", "link": "https://learn.microsoft.com/azure/azure-arc/servers/security-overview#using-disk-encryption", "services": [ - "AKV", - "Arc" + "Arc", + "AKV" ], "severity": "Medium", "subcategory": "Secrets", @@ -1981,8 +1981,8 @@ "guid": "4b69bad3-8aad-453c-a78e-1d76667357c4", "link": "https://learn.microsoft.com/azure/azure-arc/servers/managed-identity-authentication", "services": [ - "Entra", - "Arc" + "Arc", + "Entra" ], "severity": "Medium", "subcategory": "Security", @@ -1996,8 +1996,8 @@ "guid": "5a91be1f-388f-4f39-9c2b-d463cbbbc868", "link": "https://learn.microsoft.com/azure/security-center/security-center-get-started", "services": [ - "Defender", - "Arc" + "Arc", + "Defender" ], "severity": "Medium", "subcategory": "Security", @@ -2069,8 +2069,8 @@ "link": "https://learn.microsoft.com/azure/virtual-machines/migration-classic-resource-manager-overview#migration-of-storage-accounts", "service": "Azure Storage", "services": [ - "RBAC", "Storage", + "RBAC", "Subscriptions" ], "severity": "Medium", @@ -2178,8 +2178,8 @@ "link": "https://learn.microsoft.com/azure/storage/blobs/immutable-storage-overview", "service": "Azure Storage", "services": [ - "AzurePolicy", "Storage", + "AzurePolicy", "Subscriptions" ], "severity": "High", @@ -2272,8 +2272,8 @@ "guid": "a4b1410d-4395-48a8-a228-9b3d6b57cfc6", "service": "Azure Storage", "services": [ - "RBAC", "Storage", + "RBAC", "Entra" ], "severity": "Medium", @@ -2306,8 +2306,8 @@ "link": "https://learn.microsoft.com/rest/api/storageservices/authorize-with-shared-key", "service": "Azure Storage", "services": [ - "AKV", "Storage", + "AKV", "Monitor", "Entra" ], @@ -2324,10 +2324,10 @@ "link": "https://learn.microsoft.com/azure/storage/blobs/blob-storage-monitoring-scenarios#audit-account-activity", "service": "Azure Storage", "services": [ - "AKV", "Storage", - "AzurePolicy", - "Monitor" + "AKV", + "Monitor", + "AzurePolicy" ], "severity": "High", "subcategory": "Monitoring", @@ -2342,10 +2342,10 @@ "link": "https://learn.microsoft.com/azure/storage/common/storage-account-keys-manage?tabs=azure-portal#create-a-key-expiration-policy", "service": "Azure Storage", "services": [ - "AKV", "Storage", - "AzurePolicy", - "Entra" + "AKV", + "Entra", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -2360,9 +2360,9 @@ "link": "https://learn.microsoft.com/azure/storage/common/sas-expiration-policy", "service": "Azure Storage", "services": [ - "AzurePolicy", "Storage", - "Entra" + "Entra", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -2377,10 +2377,10 @@ "link": "https://learn.microsoft.com/rest/api/storageservices/define-stored-access-policy", "service": "Azure Storage", "services": [ - "AzurePolicy", "Storage", "AKV", - "Entra" + "Entra", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -2394,8 +2394,8 @@ "link": "https://microsoft.github.io/code-with-engineering-playbook/continuous-integration/dev-sec-ops/secret-management/recipes/detect-secrets-ado/", "service": "Azure Storage", "services": [ - "AKV", - "Storage" + "Storage", + "AKV" ], "severity": "Medium", "subcategory": "CI/CD", @@ -2490,8 +2490,8 @@ "link": "https://learn.microsoft.com/azure/storage/blobs/secure-file-transfer-protocol-support#sftp-permission-model", "service": "Azure Storage", "services": [ - "RBAC", "Storage", + "RBAC", "Entra" ], "severity": "High", @@ -2522,8 +2522,8 @@ "link": "https://learn.microsoft.com/rest/api/storageservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services", "service": "Azure Storage", "services": [ - "AzurePolicy", - "Storage" + "Storage", + "AzurePolicy" ], "severity": "High", "subcategory": "Networking", @@ -2698,8 +2698,8 @@ "guid": "2ea55b56-ad48-4408-be72-734b476ba18f", "link": "https://learn.microsoft.com/azure/virtual-machines/premium-storage-performance#counters-to-measure-application-performance-requirements", "services": [ - "VM", "Storage", + "VM", "SQL" ], "severity": "Medium", @@ -2744,9 +2744,9 @@ "guid": "25659d35-58fd-4772-99c9-31112d027fe4", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql#storage", "services": [ + "Cost", "Storage", - "SQL", - "Cost" + "SQL" ], "severity": "High", "subcategory": "Storage", @@ -2776,8 +2776,8 @@ "guid": "4b69bad3-4aad-45e8-a78e-1d76667313c4", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql#storage", "services": [ - "VM", "Storage", + "VM", "SQL" ], "severity": "High", @@ -2808,8 +2808,8 @@ "guid": "5a917e1f-348e-4f35-9c27-d42e8bbac868", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql#storage", "services": [ - "VM", "Storage", + "VM", "SQL" ], "severity": "High", @@ -2870,8 +2870,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/availability-group-azure-portal-configure?view=azuresql&tabs=azure-cli", "services": [ "VM", - "SQL", "LoadBalancer", + "SQL", "VNet" ], "severity": "Medium", @@ -2916,8 +2916,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/availability-group-vnn-azure-load-balancer-configure?view=azuresql-vm&tabs=ilb", "services": [ "VM", - "SQL", "LoadBalancer", + "SQL", "VNet" ], "severity": "High", @@ -2976,8 +2976,8 @@ "guid": "b824546c-e1ae-4e34-93ae-c8239248725d", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql-vm#sql-server-features", "services": [ - "VM", "Storage", + "VM", "SQL" ], "severity": "Low", @@ -3082,10 +3082,10 @@ "guid": "e36c1c81-770a-4fbc-9c0d-43918648d285", "link": "https://learn.microsoft.com/azure/virtual-machines/constrained-vcpu", "services": [ + "Cost", "Storage", "VM", - "SQL", - "Cost" + "SQL" ], "severity": "Low", "subcategory": "Cost Optimization", @@ -3100,8 +3100,8 @@ "guid": "7ed67178-b824-4546-ae1a-ee3453aec823", "link": "https://azure.microsoft.com/en-ca/pricing/hybrid-benefit/", "services": [ - "SQL", - "Cost" + "Cost", + "SQL" ], "severity": "Low", "subcategory": "Cost Optimization", @@ -3146,9 +3146,9 @@ "guid": "74a748b6-633a-4d2a-8916-a66498fad0e2", "link": "https://learn.microsoft.com/azure/defender-for-cloud/secure-score-security-controls", "services": [ + "Defender", "VM", - "SQL", - "Defender" + "SQL" ], "severity": "High", "subcategory": "Azure", @@ -3163,8 +3163,8 @@ "guid": "78ee293c-1bc3-452b-aaab-7571849ab809", "link": "https://learn.microsoft.com/azure/azure-sql/managed-instance/transact-sql-tsql-differences-sql-server?view=azuresql", "services": [ - "SQL", - "EventHubs" + "EventHubs", + "SQL" ], "severity": "High", "subcategory": "Pre Migration", @@ -3421,8 +3421,8 @@ "guid": "3334fdf9-1c23-4418-8b65-275269440b4b", "link": "https://learn.microsoft.com/azure/azure-sql/migration-guides/managed-instance/sql-server-to-managed-instance-guide?view=azuresql-mi#backup-and-restore", "services": [ - "SQL", - "Backup" + "Backup", + "SQL" ], "severity": "Low", "subcategory": "Migration", @@ -3479,8 +3479,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/managed-instance/auto-failover-group-configure-sql-mi?view=azuresql&tabs=azure-portal#test-failover", "services": [ "EventHubs", - "SQL", - "LoadBalancer" + "LoadBalancer", + "SQL" ], "severity": "High", "subcategory": "Post Migration", @@ -3512,8 +3512,8 @@ "services": [ "AKV", "AzurePolicy", - "SQL", - "Backup" + "Backup", + "SQL" ], "severity": "Low", "subcategory": "Post Migration", @@ -3544,9 +3544,9 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/long-term-retention-overview?view=azuresql-mi", "services": [ "Storage", - "SQL", "Backup", - "ARS" + "ARS", + "SQL" ], "severity": "Low", "subcategory": "Post Migration", @@ -3561,8 +3561,8 @@ "guid": "ad88408f-3727-434c-a76b-a28021459014", "link": "https://azure.microsoft.com/en-gb/pricing/hybrid-benefit/#overview", "services": [ - "SQL", - "Cost" + "Cost", + "SQL" ], "severity": "Low", "subcategory": "Post Migration", @@ -3577,8 +3577,8 @@ "guid": "65d38e53-f9cc-4bd8-9926-6acca274faa1", "link": "https://learn.microsoft.com/azure/azure-sql/database/threat-detection-overview?view=azuresql", "services": [ - "SQL", - "Defender" + "Defender", + "SQL" ], "severity": "Medium", "subcategory": "Post Migration", @@ -3623,9 +3623,9 @@ "link": "https://learn.microsoft.com/azure/well-architected/sap/design-areas/data-platform", "service": "SAP", "services": [ - "Backup", "ASR", - "SAP" + "SAP", + "Backup" ], "severity": "Medium", "subcategory": "Backup and restore", @@ -3654,11 +3654,11 @@ "link": "https://learn.microsoft.com/azure/reliability/cross-region-replication-azure", "service": "SAP", "services": [ - "SQL", - "Storage", "ASR", "Backup", - "SAP" + "Storage", + "SAP", + "SQL" ], "severity": "High", "subcategory": "Disaster recovery", @@ -3692,8 +3692,8 @@ "services": [ "ExpressRoute", "ASR", - "VPN", - "SAP" + "SAP", + "VPN" ], "severity": "High", "subcategory": "Disaster recovery", @@ -3708,10 +3708,10 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance", "service": "SAP", "services": [ - "AKV", + "ACR", "ASR", - "SAP", - "ACR" + "AKV", + "SAP" ], "severity": "Low", "subcategory": "Disaster recovery", @@ -3776,8 +3776,8 @@ "service": "SAP", "services": [ "ASR", - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "High", "subcategory": "Disaster recovery", @@ -3841,10 +3841,10 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", "service": "SAP", "services": [ - "VM", "Storage", - "ASR", - "SAP" + "VM", + "SAP", + "ASR" ], "severity": "High", "subcategory": "High availability", @@ -3943,8 +3943,8 @@ "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", "service": "SAP", "services": [ - "VM", "ASR", + "VM", "SAP", "Entra" ], @@ -3960,11 +3960,11 @@ "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", "service": "SAP", "services": [ - "VM", - "Entra", "ASR", "RBAC", - "SAP" + "SAP", + "VM", + "Entra" ], "severity": "High", "subcategory": "High availability", @@ -3995,8 +3995,8 @@ "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", "service": "SAP", "services": [ - "VM", "ASR", + "VM", "SAP" ], "severity": "High", @@ -4028,9 +4028,9 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", "service": "SAP", "services": [ + "ACR", "ASR", - "SAP", - "ACR" + "SAP" ], "severity": "High", "subcategory": "High availability", @@ -4061,8 +4061,8 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-suse-multi-sid", "service": "SAP", "services": [ - "VM", "ASR", + "VM", "SAP", "Entra" ], @@ -4080,10 +4080,10 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-business-continuity-and-disaster-recovery", "service": "SAP", "services": [ - "VM", "Storage", - "ASR", - "SAP" + "VM", + "SAP", + "ASR" ], "severity": "Medium", "subcategory": "High availability", @@ -4195,9 +4195,9 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-premium-ssd-v1", "service": "SAP", "services": [ - "VM", - "Storage", "Cost", + "Storage", + "VM", "SAP" ], "severity": "Low", @@ -4212,9 +4212,9 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-premium-ssd-v1", "service": "SAP", "services": [ - "VM", - "Storage", "Cost", + "Storage", + "VM", "SAP" ], "severity": "Low", @@ -4231,9 +4231,9 @@ "service": "SAP", "services": [ "RBAC", - "Subscriptions", "SAP", - "Entra" + "Entra", + "Subscriptions" ], "severity": "High", "subcategory": "Identity", @@ -4465,9 +4465,9 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups", "service": "SAP", "services": [ + "SAP", "AzurePolicy", - "Subscriptions", - "SAP" + "Subscriptions" ], "severity": "Medium", "subcategory": "Subscriptions", @@ -4483,8 +4483,8 @@ "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", "service": "SAP", "services": [ - "Subscriptions", - "SAP" + "SAP", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -4500,8 +4500,8 @@ "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", "service": "SAP", "services": [ - "Subscriptions", - "SAP" + "SAP", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -4518,8 +4518,8 @@ "service": "SAP", "services": [ "VM", - "Subscriptions", - "SAP" + "SAP", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -4534,8 +4534,8 @@ "link": "https://learn.microsoft.com/rest/api/reserved-vm-instances/quotaapi?branch=capacity", "service": "SAP", "services": [ - "Subscriptions", - "SAP" + "SAP", + "Subscriptions" ], "severity": "Low", "subcategory": "Subscriptions", @@ -4550,8 +4550,8 @@ "service": "SAP", "services": [ "VM", - "Subscriptions", - "SAP" + "SAP", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -4565,8 +4565,8 @@ "link": "https://azure.microsoft.com/explore/global-infrastructure/products-by-region/", "service": "SAP", "services": [ - "Subscriptions", - "SAP" + "SAP", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -4582,10 +4582,10 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-resource-organization", "service": "SAP", "services": [ - "TrafficManager", "Cost", - "Subscriptions", - "SAP" + "TrafficManager", + "SAP", + "Subscriptions" ], "severity": "Medium", "subcategory": "Subscriptions", @@ -4601,8 +4601,8 @@ "service": "SAP", "services": [ "Backup", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "High", "subcategory": "BCDR", @@ -4617,11 +4617,11 @@ "link": "https://learn.microsoft.com/azure/azure-netapp-files/azacsnap-introduction", "service": "SAP", "services": [ - "VM", - "Entra", - "Storage", "Monitor", - "SAP" + "Storage", + "SAP", + "VM", + "Entra" ], "severity": "Medium", "subcategory": "BCDR", @@ -4635,8 +4635,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-management-and-monitoring", "service": "SAP", "services": [ - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "High", "subcategory": "Management", @@ -4668,8 +4668,8 @@ "service": "SAP", "services": [ "Cost", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Low", "subcategory": "Management", @@ -4700,8 +4700,8 @@ "service": "SAP", "services": [ "VM", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -4716,8 +4716,8 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/lama-installation", "service": "SAP", "services": [ - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Low", "subcategory": "Management", @@ -4733,8 +4733,8 @@ "service": "SAP", "services": [ "SQL", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -4750,8 +4750,8 @@ "service": "SAP", "services": [ "VM", - "Monitor", "SAP", + "Monitor", "Entra" ], "severity": "High", @@ -4767,9 +4767,9 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "service": "SAP", "services": [ - "AzurePolicy", "Monitor", - "SAP" + "SAP", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Monitoring", @@ -4784,9 +4784,9 @@ "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-overview", "service": "SAP", "services": [ - "NetworkWatcher", + "SAP", "Monitor", - "SAP" + "NetworkWatcher" ], "severity": "Medium", "subcategory": "Monitoring", @@ -4802,8 +4802,8 @@ "service": "SAP", "services": [ "VM", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -4817,9 +4817,9 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-zones", "service": "SAP", "services": [ - "Subscriptions", + "SAP", "Monitor", - "SAP" + "Subscriptions" ], "severity": "High", "subcategory": "Monitoring", @@ -4836,8 +4836,8 @@ "services": [ "Storage", "ASR", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -4853,8 +4853,8 @@ "service": "SAP", "services": [ "Sentinel", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -4871,8 +4871,8 @@ "service": "SAP", "services": [ "Cost", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -4888,8 +4888,8 @@ "service": "SAP", "services": [ "VM", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Low", "subcategory": "Performance", @@ -4904,8 +4904,8 @@ "service": "SAP", "services": [ "ASR", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Performance", @@ -4921,8 +4921,8 @@ "service": "SAP", "services": [ "Storage", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Performance", @@ -4936,8 +4936,8 @@ "link": "https://sapit-forme-prod.authentication.eu11.hana.ondemand.com/login", "service": "SAP", "services": [ - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Low", "subcategory": "Performance", @@ -4952,8 +4952,8 @@ "service": "SAP", "services": [ "Storage", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Performance", @@ -4968,9 +4968,9 @@ "link": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/announcement-sap-on-azure-oracle-performance-efficiency-scripts/ba-p/3725178", "service": "SAP", "services": [ - "SQL", "Monitor", - "SAP" + "SAP", + "SQL" ], "severity": "Medium", "subcategory": "Performance", @@ -4986,8 +4986,8 @@ "service": "SAP", "services": [ "ASR", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "High", "subcategory": "Reliability", @@ -5003,9 +5003,9 @@ "service": "SAP", "services": [ "AppGW", + "SAP", "AzurePolicy", - "WAF", - "SAP" + "WAF" ], "severity": "Medium", "subcategory": "App delivery", @@ -5021,8 +5021,8 @@ "service": "SAP", "services": [ "VM", - "DNS", - "SAP" + "SAP", + "DNS" ], "severity": "Medium", "subcategory": "DNS", @@ -5038,8 +5038,8 @@ "service": "SAP", "services": [ "DNS", - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "Medium", "subcategory": "DNS", @@ -5056,9 +5056,9 @@ "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-peering-overview", "service": "SAP", "services": [ - "VNet", + "ACR", "SAP", - "ACR" + "VNet" ], "severity": "Medium", "subcategory": "Hybrid", @@ -5090,9 +5090,9 @@ "link": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/?source=recommendations", "service": "SAP", "services": [ - "VWAN", + "ACR", "SAP", - "ACR" + "VWAN" ], "severity": "Medium", "subcategory": "Hybrid", @@ -5108,8 +5108,8 @@ "service": "SAP", "services": [ "NVA", - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "Medium", "subcategory": "Hybrid", @@ -5125,9 +5125,9 @@ "service": "SAP", "services": [ "NVA", + "SAP", "VWAN", - "VNet", - "SAP" + "VNet" ], "severity": "Medium", "subcategory": "Hybrid", @@ -5144,8 +5144,8 @@ "service": "SAP", "services": [ "VM", - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "High", "subcategory": "IP plan", @@ -5178,8 +5178,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", "service": "SAP", "services": [ - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "High", "subcategory": "IP plan", @@ -5195,8 +5195,8 @@ "service": "SAP", "services": [ "Storage", - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "Medium", "subcategory": "IP plan", @@ -5229,8 +5229,8 @@ "service": "SAP", "services": [ "AppGW", - "WAF", - "SAP" + "SAP", + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -5245,11 +5245,11 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "SAP", "services": [ - "SAP", "ACR", - "AzurePolicy", + "SAP", "WAF", - "FrontDoor" + "FrontDoor", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Internet", @@ -5265,10 +5265,10 @@ "service": "SAP", "services": [ "AppGW", - "FrontDoor", - "AzurePolicy", + "SAP", "WAF", - "SAP" + "FrontDoor", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Internet", @@ -5284,9 +5284,9 @@ "service": "SAP", "services": [ "AppGW", + "SAP", "LoadBalancer", - "WAF", - "SAP" + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -5301,9 +5301,9 @@ "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", "service": "SAP", "services": [ - "VWAN", + "ACR", "SAP", - "ACR" + "VWAN" ], "severity": "Medium", "subcategory": "Internet", @@ -5319,11 +5319,11 @@ "service": "SAP", "services": [ "ACR", + "Backup", "Storage", - "PrivateLink", + "SAP", "VNet", - "Backup", - "SAP" + "PrivateLink" ], "severity": "Medium", "subcategory": "Internet", @@ -5373,8 +5373,8 @@ "service": "SAP", "services": [ "VM", - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "Medium", "subcategory": "Segmentation", @@ -5389,8 +5389,8 @@ "link": "https://me.sap.com/notes/2015553", "service": "SAP", "services": [ - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "High", "subcategory": "Segmentation", @@ -5436,8 +5436,8 @@ "service": "SAP", "services": [ "Cost", - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "High", "subcategory": "Segmentation", @@ -5468,8 +5468,8 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration", "service": "SAP", "services": [ - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "Medium", "subcategory": "Segmentation", @@ -5484,8 +5484,8 @@ "service": "SAP", "services": [ "VM", - "Backup", - "SAP" + "SAP", + "Backup" ], "severity": "High", "subcategory": " ", @@ -5500,8 +5500,8 @@ "service": "SAP", "services": [ "ASR", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": " ", @@ -5515,8 +5515,8 @@ "link": "https://help.sap.com/docs/SAP_HANA_PLATFORM/c4d7c773af4a4e5dbebb6548d6e2d4f4/e3111d2ebb5710149510cc120646bf3f.html?locale=en-US", "service": "SAP", "services": [ - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "High", "subcategory": " ", @@ -5531,8 +5531,8 @@ "service": "SAP", "services": [ "VM", - "Backup", - "SAP" + "SAP", + "Backup" ], "severity": "Medium", "subcategory": " ", @@ -5547,8 +5547,8 @@ "service": "SAP", "services": [ "Storage", - "SQL", - "SAP" + "SAP", + "SQL" ], "severity": "Medium", "subcategory": " ", @@ -5563,8 +5563,8 @@ "service": "SAP", "services": [ "VM", - "Backup", - "SAP" + "SAP", + "Backup" ], "severity": "Medium", "subcategory": " ", @@ -5635,8 +5635,8 @@ "service": "SAP", "services": [ "SQL", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": " ", @@ -5666,8 +5666,8 @@ "link": "https://learn.microsoft.com/en-us/azure/sap/large-instances/hana-monitor-troubleshoot", "service": "SAP", "services": [ - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": " ", @@ -5726,8 +5726,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", "service": "SAP", "services": [ - "SQL", - "SAP" + "SAP", + "SQL" ], "severity": "Low", "subcategory": "Governance", @@ -5741,8 +5741,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", "service": "SAP", "services": [ - "SQL", - "SAP" + "SAP", + "SQL" ], "severity": "High", "subcategory": "Governance", @@ -5757,11 +5757,11 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", "service": "SAP", "services": [ - "SQL", - "Storage", - "Backup", "AKV", - "SAP" + "Backup", + "Storage", + "SAP", + "SQL" ], "severity": "High", "subcategory": "Secrets", @@ -5776,8 +5776,8 @@ "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", "service": "SAP", "services": [ - "AKV", "Storage", + "AKV", "SAP" ], "severity": "Medium", @@ -5811,10 +5811,10 @@ "service": "SAP", "services": [ "AKV", - "AzurePolicy", "RBAC", + "SAP", "Subscriptions", - "SAP" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Secrets", @@ -5830,8 +5830,8 @@ "service": "SAP", "services": [ "AKV", - "AzurePolicy", - "SAP" + "SAP", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Secrets", @@ -5846,10 +5846,10 @@ "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", "service": "SAP", "services": [ - "AzurePolicy", - "RBAC", "AKV", - "SAP" + "RBAC", + "SAP", + "AzurePolicy" ], "severity": "High", "subcategory": "Secrets", @@ -5864,8 +5864,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", "service": "SAP", "services": [ - "AKV", "Storage", + "AKV", "SAP", "Defender" ], @@ -5883,9 +5883,9 @@ "service": "SAP", "services": [ "AKV", + "Defender", "RBAC", - "SAP", - "Defender" + "SAP" ], "severity": "High", "subcategory": "Secrets", @@ -5966,8 +5966,8 @@ "service": "SAP", "services": [ "RBAC", - "Subscriptions", - "SAP" + "SAP", + "Subscriptions" ], "severity": "High", "subcategory": "Security", @@ -5999,8 +5999,8 @@ "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", "service": "SAP", "services": [ - "VM", "Storage", + "VM", "SAP" ], "severity": "Low", @@ -6016,8 +6016,8 @@ "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", "service": "SAP", "services": [ - "SAP", - "Defender" + "Defender", + "SAP" ], "severity": "Low", "subcategory": "Security", @@ -6032,8 +6032,8 @@ "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", "service": "SAP", "services": [ - "VNet", - "SAP" + "SAP", + "VNet" ], "severity": "High", "subcategory": "Security", @@ -6048,8 +6048,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", "service": "SAP", "services": [ - "WAF", - "SAP" + "SAP", + "WAF" ], "severity": "Low", "subcategory": "Security", @@ -6065,8 +6065,8 @@ "service": "SAP", "services": [ "AKV", - "Monitor", - "SAP" + "SAP", + "Monitor" ], "severity": "Medium", "subcategory": "Security", @@ -6098,8 +6098,8 @@ "link": "https://learn.microsoft.com/azure/app-service/overview-hosting-plans", "service": "App Services", "services": [ - "AppSvc", "ASR", + "AppSvc", "Backup" ], "severity": "Medium", @@ -6115,8 +6115,8 @@ "link": "https://learn.microsoft.com/azure/reliability/migrate-app-service", "service": "App Services", "services": [ - "AppSvc", - "ACR" + "ACR", + "AppSvc" ], "severity": "High", "subcategory": "High Availability", @@ -6180,8 +6180,8 @@ "link": "https://learn.microsoft.com/azure/app-service/manage-disaster-recovery#recover-app-content-only", "service": "App Services", "services": [ - "AppSvc", - "ASR" + "ASR", + "AppSvc" ], "severity": "Low", "subcategory": "High Availability", @@ -6272,8 +6272,8 @@ "link": "https://learn.microsoft.com/azure/app-service/app-service-key-vault-references", "service": "App Services", "services": [ - "AppSvc", - "AKV" + "AKV", + "AppSvc" ], "severity": "High", "subcategory": "Data Protection", @@ -6288,8 +6288,8 @@ "link": "https://learn.microsoft.com/azure/app-service/app-service-key-vault-references", "service": "App Services", "services": [ - "AppSvc", "AKV", + "AppSvc", "Entra" ], "severity": "High", @@ -6305,8 +6305,8 @@ "link": "https://learn.microsoft.com/azure/app-service/configure-ssl-certificate", "service": "App Services", "services": [ - "AppSvc", "AKV", + "AppSvc", "Entra" ], "severity": "High", @@ -6354,8 +6354,8 @@ "link": "https://learn.microsoft.com/azure/app-service/overview-authentication-authorization", "service": "App Services", "services": [ - "AppSvc", "ACR", + "AppSvc", "Entra" ], "severity": "Medium", @@ -6403,8 +6403,8 @@ "link": "https://learn.microsoft.com/azure/app-service/overview-managed-identity?tabs=portal%2Chttp", "service": "App Services", "services": [ - "AppSvc", "AKV", + "AppSvc", "Entra" ], "severity": "High", @@ -6420,8 +6420,8 @@ "link": "https://learn.microsoft.com/azure/app-service/configure-custom-container#use-managed-identity-to-pull-image-from-azure-container-registry", "service": "App Services", "services": [ - "AppSvc", "ACR", + "AppSvc", "Entra" ], "severity": "High", @@ -6472,10 +6472,10 @@ "service": "App Services", "services": [ "AppSvc", + "Monitor", "NVA", "Firewall", - "VNet", - "Monitor" + "VNet" ], "severity": "Medium", "subcategory": "Network Security", @@ -6492,8 +6492,8 @@ "services": [ "AppSvc", "NVA", - "Storage", "Firewall", + "Storage", "VNet", "PrivateLink" ], @@ -6510,8 +6510,8 @@ "link": "https://learn.microsoft.com/azure/app-service/networking-features#access-restrictions", "service": "App Services", "services": [ - "AppSvc", - "PrivateLink" + "PrivateLink", + "AppSvc" ], "severity": "High", "subcategory": "Network Security", @@ -6527,8 +6527,8 @@ "service": "App Services", "services": [ "AppSvc", - "AppGW", "Monitor", + "AppGW", "WAF", "FrontDoor" ], @@ -6545,8 +6545,8 @@ "link": "https://learn.microsoft.com/azure/app-service/networking-features#access-restrictions", "service": "App Services", "services": [ - "AppSvc", "PrivateLink", + "AppSvc", "WAF" ], "severity": "High", @@ -6596,8 +6596,8 @@ "link": "https://learn.microsoft.com/azure/app-service/app-service-web-tutorial-rest-api", "service": "App Services", "services": [ - "AppSvc", - "Storage" + "Storage", + "AppSvc" ], "severity": "High", "subcategory": "Network Security", @@ -6628,8 +6628,8 @@ "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-app-service-introduction", "service": "App Services", "services": [ - "AppSvc", - "Defender" + "Defender", + "AppSvc" ], "severity": "Medium", "subcategory": "Network Security", @@ -6645,12 +6645,12 @@ "service": "App Services", "services": [ "AppSvc", - "AppGW", - "DDoS", "NVA", - "VNet", + "WAF", "EventHubs", - "WAF" + "AppGW", + "VNet", + "DDoS" ], "severity": "Medium", "subcategory": "Network Security", @@ -6665,10 +6665,10 @@ "link": "https://learn.microsoft.com/azure/app-service/configure-custom-container#use-an-image-from-a-network-protected-registry", "service": "App Services", "services": [ + "ACR", "AppSvc", "PrivateLink", - "VNet", - "ACR" + "VNet" ], "severity": "Medium", "subcategory": "Network Security", @@ -6759,10 +6759,10 @@ "link": "https://learn.microsoft.com/azure/governance/policy/overview", "service": "App Services", "services": [ + "ACR", "AppSvc", - "AzurePolicy", "Backup", - "ACR" + "AzurePolicy" ], "severity": "High", "subcategory": "Compliance", @@ -6777,9 +6777,9 @@ "link": "https://learn.microsoft.com/azure/cost-management-billing/", "service": "App Services", "services": [ + "Cost", "AppSvc", - "Monitor", - "Cost" + "Monitor" ], "severity": "Low", "subcategory": "Cost Monitoring", @@ -6794,9 +6794,9 @@ "link": "https://learn.microsoft.com/azure/cost-management-billing/reservations/", "service": "App Services", "services": [ - "AppSvc", - "Storage", "Cost", + "Storage", + "AppSvc", "ARS" ], "severity": "Medium", @@ -6906,12 +6906,12 @@ "guid": "aa369282-9e7e-4216-8836-87af467a1f89", "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", "services": [ - "Entra", - "DDoS", - "Firewall", "VNet", "Subscriptions", - "WAF" + "Firewall", + "WAF", + "DDoS", + "Entra" ], "severity": "Low", "subcategory": "DDoS", @@ -6935,8 +6935,8 @@ "guid": "44008ae7-d7e4-4743-876c-8bdbf55bce61", "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -6963,9 +6963,9 @@ "guid": "be985190-4838-435c-a86b-b2912155a114", "link": "https://learn.microsoft.com/azure/openshift/howto-restrict-egress", "services": [ - "AzurePolicy", "NVA", - "Firewall" + "Firewall", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Internet", @@ -6991,8 +6991,8 @@ "guid": "ab039da6-d54d-47c8-a29d-b107d5325ae6", "link": "https://learn.microsoft.com/azure/container-registry/container-registry-private-link", "services": [ - "PrivateLink", - "ACR" + "ACR", + "PrivateLink" ], "severity": "Medium", "subcategory": "Private access", @@ -7306,8 +7306,8 @@ "guid": "a2c02149-9014-4a5d-9ce5-74dccbd9792a", "link": "https://access.redhat.com/documentation/red_hat_openshift_container_storage/4.4/html/deploying_and_managing_openshift_container_storage_on_microsoft_azure/deploying-openshift-container-storage-on-microsoft-azure_rhocs", "services": [ - "Storage", - "ACR" + "ACR", + "Storage" ], "severity": "Medium", "subcategory": "Data Store", @@ -7364,8 +7364,8 @@ "guid": "08fe8273-4c48-46ba-880d-c0591cf75ee8", "link": "https://learn.microsoft.com/azure/azure-arc/kubernetes/quickstart-connect-cluster", "services": [ - "AKS", - "Arc" + "Arc", + "AKS" ], "severity": "High", "subcategory": "Control plane", @@ -7389,9 +7389,9 @@ "guid": "d55d14c3-c492-49cb-8b3d-1325ae124ba3", "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-containers-introduction", "services": [ - "AKS", "Defender", - "Arc" + "Arc", + "AKS" ], "severity": "Medium", "subcategory": "Posture", @@ -7404,9 +7404,9 @@ "guid": "4d0685ed-dce9-4be3-ab0d-db3b55fb2ec1", "link": "https://learn.microsoft.com/azure/azure-arc/kubernetes/tutorial-akv-secrets-provider", "services": [ + "Arc", "AKV", - "AKS", - "Arc" + "AKS" ], "severity": "Medium", "subcategory": "Secrets", @@ -7430,8 +7430,8 @@ "guid": "b4935ada-4232-44ec-b81c-123181a64174", "link": "https://learn.microsoft.com/azure/governance/policy/concepts/policy-for-kubernetes#install-azure-policy-extension-for-azure-arc-enabled-kubernetes", "services": [ - "AzurePolicy", - "Monitor" + "Monitor", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Workload", @@ -7457,8 +7457,8 @@ "guid": "e209d4a0-da57-4778-924d-216785d2fa56", "link": "https://learn.microsoft.com/azure/container-registry/container-registry-private-link", "services": [ - "Subscriptions", - "ACR" + "ACR", + "Subscriptions" ], "severity": "Low", "subcategory": "Workload", @@ -7484,8 +7484,8 @@ "guid": "f7c015e0-7d97-4283-b006-567afeb2b5ca", "link": "https://learn.microsoft.com/azure-stack/hci/concepts/drive-symmetry-considerations#understand-capacity-imbalance", "services": [ - "Storage", - "ACR" + "ACR", + "Storage" ], "severity": "Medium", "subcategory": "Physical", @@ -7864,8 +7864,8 @@ "guid": "074541e3-fe08-458a-8062-32d13dcc10c6", "link": "https://learn.microsoft.com/azure/backup/back-up-azure-stack-hyperconverged-infrastructure-virtual-machines", "services": [ - "VM", "ASR", + "VM", "Backup" ], "severity": "High", @@ -8316,8 +8316,8 @@ "service": "Cognitive Search", "services": [ "Storage", - "ASR", - "Backup" + "Backup", + "ASR" ], "severity": "High", "subcategory": "Disaster Recovery", @@ -8367,8 +8367,8 @@ "link": "https://learn.microsoft.com/azure/architecture/guide/multitenant/considerations/tenancy-models", "service": "Azure Monitor", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "severity": "Medium", "subcategory": "Azure Monitor - enforce data collection rules", @@ -8383,8 +8383,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/automation", "service": "Azure Backup", "services": [ - "Backup", - "Cost" + "Cost", + "Backup" ], "severity": "Medium", "subcategory": "Backup", @@ -8424,9 +8424,9 @@ "guid": "3b0d834a-3487-426d-b69c-6b5c2a26494b", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", "services": [ + "Cost", "Storage", - "Backup", - "Cost" + "Backup" ], "severity": "Medium", "subcategory": "Delete/archive", @@ -8440,10 +8440,10 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", "service": "Azure Backup", "services": [ - "Backup", + "Cost", "Storage", - "ASR", - "Cost" + "Backup", + "ASR" ], "severity": "Medium", "subcategory": "Delete/archive", @@ -8457,8 +8457,8 @@ "link": "https://learn.microsoft.com/azure/cost-management-billing/manage/direct-ea-administration#manage-notification-contacts", "service": "Azure Monitor", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "severity": "Medium", "subcategory": "Log Analytics retention for workspaces", @@ -8473,9 +8473,9 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", "service": "Azure Monitor", "services": [ - "AzurePolicy", + "Cost", "Storage", - "Cost" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Policy", @@ -8518,10 +8518,10 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", "service": "VM", "services": [ - "VM", + "Cost", "Storage", "Backup", - "Cost" + "VM" ], "severity": "Medium", "subcategory": "stopped/deallocated VMs: check disks", @@ -8536,9 +8536,9 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", "service": "Storage", "services": [ - "AzurePolicy", + "Cost", "Storage", - "Cost" + "AzurePolicy" ], "severity": "Medium", "subcategory": "storage accounts lifecycle policy", @@ -8591,9 +8591,9 @@ "guid": "a27b765a-91be-41f3-a8ef-394c2bd463cb", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", "services": [ - "VM", + "Cost", "Storage", - "Cost" + "VM" ], "severity": "Medium", "subcategory": "DB optimization", @@ -8634,8 +8634,8 @@ "link": "https://learn.microsoft.com/azure/governance/policy/overview", "service": "VM", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "Advisor", @@ -8661,8 +8661,8 @@ "guid": "b835556d-f2bf-4e45-93b0-d834a348726d", "link": "https://learn.microsoft.com/azure/governance/policy/overview", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "severity": "Medium", "subcategory": "Automation", @@ -8701,8 +8701,8 @@ "guid": "733be2a1-a27b-4765-a91b-e1f388ef394c", "link": "https://learn.microsoft.com/azure/governance/policy/overview#azure-rbac-permissions-in-azure-policy", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Baseline", @@ -8715,8 +8715,8 @@ "guid": "2bd463cb-bac7-4581-a59b-b91a3ed90cae", "link": "https://learn.microsoft.com/azure/governance/policy/overview", "services": [ - "AzurePolicy", - "Cost" + "Cost", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Baseline", @@ -8849,10 +8849,10 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/manage/centralize-operations", "service": "VM", "services": [ - "AzurePolicy", + "Cost", "VM", - "SQL", - "Cost" + "AzurePolicy", + "SQL" ], "severity": "Medium", "subcategory": "check AHUB is applied to all Windows VMs, RHEL and SQL", @@ -8866,8 +8866,8 @@ "link": "https://learn.microsoft.com/azure/active-directory/privileged-identity-management/pim-configure", "service": "VM", "services": [ - "LoadBalancer", - "Cost" + "Cost", + "LoadBalancer" ], "severity": "Medium", "subcategory": "Check Red Hat Licences if applicable", @@ -8880,8 +8880,8 @@ "guid": "a76af4a6-91e8-4839-ada4-6667e13c1056", "link": "https://learn.microsoft.com/azure/active-directory/roles/security-planning#identify-microsoft-accounts-in-administrative-roles-that-need-to-be-switched-to-work-or-school-accounts", "services": [ - "AppSvc", - "Cost" + "Cost", + "AppSvc" ], "severity": "Medium", "subcategory": "Functions", @@ -8895,8 +8895,8 @@ "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-groups-create-azure-portal", "service": "VM", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "Planning", @@ -8911,8 +8911,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access#prerequisites-for-a-landing-zone---design-recommendations", "service": "VM", "services": [ - "VM", "Cost", + "VM", "ARS" ], "severity": "Medium", @@ -8953,8 +8953,8 @@ "link": "https://learn.microsoft.com/azure/active-directory-domain-services/overview", "service": "VM", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Reserve storage", @@ -8968,8 +8968,8 @@ "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/identity/adds-extend-domain", "service": "VM", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "Reserve VMs with normalized and rationalized sizes", @@ -8983,9 +8983,9 @@ "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy", "service": "Azure SQL", "services": [ - "AzurePolicy", + "Cost", "SQL", - "Cost" + "AzurePolicy" ], "severity": "Medium", "subcategory": "SQL Database AHUB", @@ -8999,9 +8999,9 @@ "link": "https://learn.microsoft.com/azure/active-directory/roles/best-practices", "service": "VM", "services": [ + "Cost", "VM", - "SQL", - "Cost" + "SQL" ], "severity": "Medium", "subcategory": "SQL Database Reservations", @@ -9027,8 +9027,8 @@ "guid": "d3b475a5-c7ac-4be4-abbe-64dd89f2e877", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access-landing-zones#rbac-recommendations", "services": [ - "AzurePolicy", - "Cost" + "Cost", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Tracking", @@ -9041,8 +9041,8 @@ "guid": "78468d55-a785-4c6f-b96c-96ad8844cf3b", "link": "https://learn.microsoft.com/azure/active-directory/privileged-identity-management/pim-create-roles-and-resource-roles-review", "services": [ - "AzurePolicy", - "Cost" + "Cost", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Automation", @@ -9055,8 +9055,8 @@ "guid": "2b38c886-ba2c-4021-9990-14a5d3ce574d", "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-diagnostic-settings-to-save-your-wafs-logs", "services": [ - "AzurePolicy", - "Cost" + "Cost", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Automation", @@ -9070,8 +9070,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", "service": "VM", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "Autoscale", @@ -9085,8 +9085,8 @@ "link": "https://learn.microsoft.com/azure/reliability/cross-region-replication-azure", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Medium", "subcategory": "Autoscale", @@ -9139,8 +9139,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/logs/data-retention-archive?tabs=portal-1%2Cportal-2#how-retention-and-archiving-work", "service": "Azure Backup", "services": [ - "Backup", - "Cost" + "Cost", + "Backup" ], "severity": "Medium", "subcategory": "Backup", @@ -9155,9 +9155,9 @@ "link": "https://learn.microsoft.com/azure/databricks/clusters/cluster-config-best-practices#automatic-termination", "service": "Databricks", "services": [ + "Cost", "VM", - "LoadBalancer", - "Cost" + "LoadBalancer" ], "severity": "Medium", "subcategory": "Databricks", @@ -9201,8 +9201,8 @@ "link": "https://learn.microsoft.com/azure/network-watcher/network-watcher-monitoring-overview", "service": "Azure Functions", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Functions", @@ -9287,9 +9287,9 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "service": "Front Door", "services": [ - "FrontDoor", + "Cost", "EventHubs", - "Cost" + "FrontDoor" ], "severity": "Medium", "subcategory": "Networking", @@ -9303,9 +9303,9 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-setup-guide/monitoring-reporting?tabs=AzureMonitor", "service": "Front Door", "services": [ + "Cost", "AppSvc", - "FrontDoor", - "Cost" + "FrontDoor" ], "severity": "Medium", "subcategory": "Networking", @@ -9345,8 +9345,8 @@ "link": "https://learn.microsoft.com/azure/architecture/best-practices/monitoring", "service": "Storage", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Storage", @@ -9360,8 +9360,8 @@ "link": "https://learn.microsoft.com/azure/automation/how-to/region-mappings", "service": "VM", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Storage", @@ -9375,8 +9375,8 @@ "link": "https://learn.microsoft.com/azure/governance/policy/concepts/guest-configuration", "service": "Storage", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Storage", @@ -9390,8 +9390,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#monitoring-for-configuration-drift", "service": "Storage", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Storage", @@ -9405,9 +9405,9 @@ "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", "service": "Site Recovery", "services": [ + "Cost", "Storage", - "ASR", - "Cost" + "ASR" ], "severity": "Medium", "subcategory": "Storage", @@ -9421,8 +9421,8 @@ "link": "https://learn.microsoft.com/azure/architecture/framework/resiliency/backup-and-recovery", "service": "Storage", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "storage", @@ -9436,8 +9436,8 @@ "link": "https://learn.microsoft.com/azure/backup/backup-center-overview", "service": "VM", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Storage", @@ -9451,8 +9451,8 @@ "link": "https://learn.microsoft.com/azure/reliability/availability-zones-overview", "service": "Synapse", "services": [ - "EventHubs", "Cost", + "EventHubs", "Monitor" ], "severity": "Medium", @@ -9467,8 +9467,8 @@ "link": "https://learn.microsoft.com/azure/virtual-machines/availability", "service": "Synapse", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "Medium", "subcategory": "Synapse", @@ -9482,8 +9482,8 @@ "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", "service": "Synapse", "services": [ - "SQL", - "Cost" + "Cost", + "SQL" ], "severity": "Medium", "subcategory": "Synapse", @@ -9540,8 +9540,8 @@ "link": "https://learn.microsoft.com/azure/application-gateway/overview-v2", "service": "VM", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "VM", @@ -9556,8 +9556,8 @@ "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", "service": "VM", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "VM", @@ -9571,8 +9571,8 @@ "link": "https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet", "service": "VM", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "VM", @@ -9587,9 +9587,9 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "VM", "services": [ + "Cost", "VM", - "Monitor", - "Cost" + "Monitor" ], "severity": "Medium", "subcategory": "VM", @@ -9604,8 +9604,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "VM", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "VM", @@ -9693,9 +9693,9 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "Front Door", "services": [ + "FrontDoor", "AzurePolicy", - "WAF", - "FrontDoor" + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -9711,9 +9711,9 @@ "service": "Front Door", "services": [ "AppGW", + "FrontDoor", "AzurePolicy", - "WAF", - "FrontDoor" + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -9729,9 +9729,9 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings", "service": "Front Door", "services": [ + "FrontDoor", "AzurePolicy", - "WAF", - "FrontDoor" + "WAF" ], "severity": "High", "subcategory": "Front Door", @@ -9746,9 +9746,9 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#avoid-combining-traffic-manager-and-front-door", "service": "Front Door", "services": [ - "TrafficManager", "EventHubs", - "FrontDoor" + "FrontDoor", + "TrafficManager" ], "severity": "High", "subcategory": "Front Door", @@ -9822,9 +9822,9 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates", "service": "Front Door", "services": [ + "Cost", "AKV", - "FrontDoor", - "Cost" + "FrontDoor" ], "severity": "High", "subcategory": "Front Door", @@ -9838,8 +9838,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#define-your-waf-configuration-as-code", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -9884,8 +9884,8 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#enable-the-waf", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "High", "subcategory": "Front Door", @@ -9899,8 +9899,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#tune-your-waf", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "High", "subcategory": "Front Door", @@ -9914,9 +9914,9 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection", "service": "Front Door", "services": [ + "FrontDoor", "AzurePolicy", - "WAF", - "FrontDoor" + "WAF" ], "severity": "High", "subcategory": "Front Door", @@ -9930,8 +9930,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#enable-default-rule-sets", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "High", "subcategory": "Front Door", @@ -9945,8 +9945,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#enable-bot-management-rules", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "High", "subcategory": "Front Door", @@ -9960,8 +9960,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#use-the-latest-ruleset-versions", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -9975,8 +9975,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-rate-limiting", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -9990,8 +9990,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#use-a-high-threshold-for-rate-limits", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -10019,8 +10019,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#specify-the-unknown-zz-location", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -10034,9 +10034,9 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-diagnostic-settings-to-save-your-wafs-logs", "service": "Front Door", "services": [ - "WAF", "FrontDoor", - "Monitor" + "Monitor", + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -10051,8 +10051,8 @@ "service": "Front Door", "services": [ "Sentinel", - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -10066,8 +10066,8 @@ "link": "https://learn.microsoft.com/azure/frontdoor/routing-methods", "service": "Front Door", "services": [ - "FrontDoor", - "Backup" + "Backup", + "FrontDoor" ], "severity": "Medium", "subcategory": "Front Door", @@ -10241,9 +10241,9 @@ "link": "https://learn.microsoft.com/azure/architecture/guide/networking/global-web-applications/mission-critical-content-delivery", "service": "Front Door", "services": [ - "TrafficManager", "Storage", - "FrontDoor" + "FrontDoor", + "TrafficManager" ], "severity": "Medium", "subcategory": "Front Door", @@ -10273,8 +10273,8 @@ "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/sql-database-security-baseline#br-2-encrypt-backup-data", "services": [ "AKV", - "SQL", - "Backup" + "Backup", + "SQL" ], "severity": "Medium", "subcategory": "Azure Key Vault", @@ -10289,8 +10289,8 @@ "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/sql-database-security-baseline#br-1-ensure-regular-automated-backups", "services": [ "Storage", - "SQL", - "Backup" + "Backup", + "SQL" ], "severity": "Medium", "subcategory": "Backup", @@ -10305,8 +10305,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/automated-backups-overview?tabs=single-database&view=azuresql#backup-storage-redundancy", "services": [ "Storage", - "SQL", - "Backup" + "Backup", + "SQL" ], "severity": "Low", "subcategory": "Backup", @@ -10362,9 +10362,9 @@ "guid": "4e52d73f-5d37-428f-b3a2-e6997e835979", "link": "https://learn.microsoft.com/azure/azure-sql/database/threat-detection-configure", "services": [ - "SQL", + "Defender", "EventHubs", - "Defender" + "SQL" ], "severity": "High", "subcategory": "Advanced Threat Protection", @@ -10378,9 +10378,9 @@ "guid": "dff87489-9edb-4cef-bdda-86e8212b2aa1", "link": "https://learn.microsoft.com/azure/azure-sql/database/azure-defender-for-sql?view=azuresql#enable-microsoft-defender-for-sql ", "services": [ + "Defender", "SQL", - "Subscriptions", - "Defender" + "Subscriptions" ], "severity": "High", "subcategory": "Defender for Azure SQL", @@ -10394,9 +10394,9 @@ "guid": "ca342fdf-d25a-4427-b105-fcd50ff8a0ea", "link": "https://learn.microsoft.com/azure/azure-sql/database/threat-detection-configure", "services": [ - "SQL", + "Defender", "Monitor", - "Defender" + "SQL" ], "severity": "High", "subcategory": "Defender for Azure SQL", @@ -10410,9 +10410,9 @@ "guid": "a6101ae7-534c-45ab-86fd-b34c55ea21ca", "link": "https://learn.microsoft.com/azure/defender-for-cloud/sql-azure-vulnerability-assessment-overview", "services": [ - "SQL", + "Defender", "Monitor", - "Defender" + "SQL" ], "severity": "High", "subcategory": "Vulnerability Assessment", @@ -10426,8 +10426,8 @@ "guid": "c8c5f112-1e50-4f77-9264-8195b4cd61ac", "link": "https://learn.microsoft.com/azure/defender-for-cloud/sql-azure-vulnerability-assessment-find?view=azuresql", "services": [ - "SQL", - "Defender" + "Defender", + "SQL" ], "severity": "High", "subcategory": "Vulnerability Assessment", @@ -10455,8 +10455,8 @@ "guid": "c03ce136-e3d5-4e17-bf25-ed955ee480d3", "link": "https://learn.microsoft.com/azure/azure-sql/database/security-best-practice?view=azuresql#control-access-of-application-users-to-sensitive-data-through-encryption", "services": [ - "AKV", "Storage", + "AKV", "SQL" ], "severity": "Low", @@ -10472,8 +10472,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/transparent-data-encryption-byok-create-server", "services": [ "Storage", - "SQL", - "Backup" + "Backup", + "SQL" ], "severity": "High", "subcategory": "Transparent Data Encryption", @@ -10516,8 +10516,8 @@ "guid": "c9b8b6bf-2c6b-453d-b400-de9a43a549d7", "link": "https://learn.microsoft.com/azure/azure-sql/database/authentication-aad-overview", "services": [ - "SQL", - "Entra" + "Entra", + "SQL" ], "severity": "Medium", "subcategory": "Azure Active Directory", @@ -10531,9 +10531,9 @@ "guid": "29820254-1d14-4778-ae90-ff4aeba504a3", "link": "https://learn.microsoft.com/azure/azure-sql/database/security-best-practice?view=azuresql#central-management-for-identities", "services": [ - "SQL", "Monitor", - "Entra" + "Entra", + "SQL" ], "severity": "Medium", "subcategory": "Azure Active Directory", @@ -10547,8 +10547,8 @@ "guid": "df3a09ee-03bb-4198-8637-d141acf5f289", "link": "https://learn.microsoft.com/azure/azure-sql/database/security-best-practice?view=azuresql#minimize-the-use-of-password-based-authentication-for-applications", "services": [ - "SQL", - "Entra" + "Entra", + "SQL" ], "severity": "Medium", "subcategory": "Azure Active Directory", @@ -10562,11 +10562,11 @@ "guid": "69891194-5074-4e30-8f69-4efc3c580900", "link": "https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview", "services": [ - "SQL", "ACR", - "Entra", "AKV", - "RBAC" + "RBAC", + "SQL", + "Entra" ], "severity": "Low", "subcategory": "Managed Identities", @@ -10580,8 +10580,8 @@ "guid": "88287d4a-8bb8-4640-ad78-03f51354d003", "link": "https://learn.microsoft.com/azure/azure-sql/database/authentication-aad-configure?view=azuresql&tabs=azure-powershell#active-directory-integrated-authentication", "services": [ - "SQL", - "Entra" + "Entra", + "SQL" ], "severity": "Medium", "subcategory": "Passwords", @@ -10685,12 +10685,12 @@ "guid": "9b64bc50-b60f-4035-bf7a-28c4806dfb46", "link": "https://learn.microsoft.com/azure/azure-sql/database/auditing-overview", "services": [ - "SQL", - "Entra", - "Storage", + "Monitor", "EventHubs", "Backup", - "Monitor" + "Storage", + "SQL", + "Entra" ], "severity": "Low", "subcategory": "Auditing", @@ -10704,11 +10704,11 @@ "guid": "fcd34708-87ac-4efc-aaf6-57a47f76644a", "link": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log", "services": [ - "SQL", - "Storage", + "Monitor", "EventHubs", - "Subscriptions", - "Monitor" + "Storage", + "SQL", + "Subscriptions" ], "severity": "Medium", "subcategory": "Auditing", @@ -10722,8 +10722,8 @@ "guid": "f96e127e-9572-453a-b325-ff89ae9f6b44", "link": "https://learn.microsoft.com/azure/azure-sql/database/auditing-overview", "services": [ - "SQL", - "Monitor" + "Monitor", + "SQL" ], "severity": "Medium", "subcategory": "SIEM/SOAR", @@ -10737,8 +10737,8 @@ "guid": "41503bf8-73da-4a10-af9f-5f7fceb5456f", "link": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log", "services": [ - "SQL", - "Monitor" + "Monitor", + "SQL" ], "severity": "Medium", "subcategory": "SIEM/SOAR", @@ -10752,8 +10752,8 @@ "guid": "19ec7c97-c563-4e1d-82f0-54d6ec12e754", "link": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log", "services": [ - "SQL", - "EventHubs" + "EventHubs", + "SQL" ], "severity": "Medium", "subcategory": "SIEM/SOAR", @@ -10813,8 +10813,8 @@ "guid": "cb3274a7-e36d-46f6-8de5-46d30c8dde8e", "link": "https://learn.microsoft.com/sql/relational-databases/system-stored-procedures/sp-invoke-external-rest-endpoint-transact-sql", "services": [ - "SQL", "EventHubs", + "SQL", "APIM" ], "severity": "Medium", @@ -10844,11 +10844,11 @@ "guid": "246cd832-f550-4af0-9c74-ca9baeeb8860", "link": "https://learn.microsoft.com/azure/azure-sql/database/private-endpoint-overview?view=azuresql#disable-public-access-to-your-logical-server", "services": [ - "SQL", - "PrivateLink", + "Monitor", "Firewall", + "SQL", "VNet", - "Monitor" + "PrivateLink" ], "severity": "Medium", "subcategory": "Private Access", @@ -11015,8 +11015,8 @@ "guid": "7b5b55e5-4750-4920-be97-eb726c256a5c", "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/sql-database-security-baseline#im-3-use-azure-ad-single-sign-on-sso-for-application-access", "services": [ - "SQL", - "Entra" + "Entra", + "SQL" ], "severity": "Low", "subcategory": "Permissions", @@ -11097,8 +11097,8 @@ "guid": "36cb45e5-7960-4332-9bdf-8cc23318da61", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/enterprise-scale/business-continuity-and-disaster-recovery", "services": [ - "AKS", - "ASR" + "ASR", + "AKS" ], "severity": "High", "subcategory": "Disaster Recovery", @@ -11111,10 +11111,10 @@ "guid": "170265f4-bb46-4a39-9af7-f317284797b1", "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-multi-region", "services": [ - "TrafficManager", - "AKS", "LoadBalancer", - "FrontDoor" + "TrafficManager", + "FrontDoor", + "AKS" ], "severity": "Medium", "subcategory": "High Availability", @@ -11157,8 +11157,8 @@ "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-scheduler", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "subcategory": "High Availability", @@ -11172,8 +11172,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-geo-replication", "service": "ACR", "services": [ - "AKS", - "ACR" + "ACR", + "AKS" ], "severity": "High", "subcategory": "High Availability", @@ -11187,8 +11187,8 @@ "link": "https://learn.microsoft.com/azure/aks/availability-zones#azure-disk-availability-zone-support", "services": [ "Storage", - "AKS", - "ASR" + "ASR", + "AKS" ], "severity": "High", "subcategory": "Disaster Recovery", @@ -11215,8 +11215,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/aks/eslz-cost-governance-with-kubecost", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "subcategory": "Cost", @@ -11230,8 +11230,8 @@ "link": "https://learn.microsoft.com/azure/aks/scale-down-mode", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "subcategory": "Cost", @@ -11245,8 +11245,8 @@ "link": "https://learn.microsoft.com/azure/aks/gpu-multi-instance", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Medium", "subcategory": "Cost", @@ -11260,8 +11260,8 @@ "link": "https://learn.microsoft.com/azure/aks/start-stop-nodepools", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "subcategory": "Cost", @@ -11320,8 +11320,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/", "service": "AKS", "services": [ - "AKS", - "ACR" + "ACR", + "AKS" ], "severity": "Medium", "subcategory": "Compliance", @@ -11348,8 +11348,8 @@ "guid": "cc639637-a652-42ac-89e8-06965388e9de", "link": "https://learn.microsoft.com/azure/security-center/container-security", "services": [ - "AKS", - "Defender" + "Defender", + "AKS" ], "severity": "Medium", "subcategory": "Compliance", @@ -11450,9 +11450,9 @@ "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-containers-enable", "service": "AKS", "services": [ + "Defender", "AKV", - "AKS", - "Defender" + "AKS" ], "severity": "Medium", "subcategory": "Secrets", @@ -11467,8 +11467,8 @@ "link": "https://learn.microsoft.com/azure/aks/use-managed-identity", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "High", "subcategory": "Identity", @@ -11483,8 +11483,8 @@ "link": "https://learn.microsoft.com/azure/aks/managed-aad", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Medium", "subcategory": "Identity", @@ -11498,8 +11498,8 @@ "link": "https://learn.microsoft.com/azure/aks/control-kubeconfig-access", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Medium", "subcategory": "Identity", @@ -11514,8 +11514,8 @@ "service": "AKS", "services": [ "RBAC", - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Medium", "subcategory": "Identity", @@ -11530,8 +11530,8 @@ "service": "AKS", "services": [ "RBAC", - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "High", "subcategory": "Identity", @@ -11545,8 +11545,8 @@ "link": "https://learn.microsoft.com/azure/aks/workload-identity-migration-sidecar", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Medium", "subcategory": "Identity", @@ -11560,8 +11560,8 @@ "link": "https://learn.microsoft.com/azure/aks/managed-aad#non-interactive-sign-in-with-kubelogin", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Medium", "subcategory": "Identity", @@ -11576,8 +11576,8 @@ "link": "https://learn.microsoft.com/azure/aks/managed-aad#disable-local-accounts", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Medium", "subcategory": "Identity", @@ -11591,8 +11591,8 @@ "link": "https://learn.microsoft.com/azure/aks/managed-aad#configure-just-in-time-cluster-access-with-azure-ad-and-aks", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Low", "subcategory": "Identity", @@ -11606,8 +11606,8 @@ "link": "https://learn.microsoft.com/azure/aks/managed-aad#use-conditional-access-with-azure-ad-and-aks", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Low", "subcategory": "Identity", @@ -11621,8 +11621,8 @@ "link": "https://learn.microsoft.com/azure/aks/use-group-managed-service-accounts", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Low", "subcategory": "Identity", @@ -11636,8 +11636,8 @@ "link": "https://learn.microsoft.com/azure/aks/use-managed-identity#use-a-pre-created-kubelet-managed-identity", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Medium", "subcategory": "Identity", @@ -11651,9 +11651,9 @@ "link": "https://azure.github.io/application-gateway-kubernetes-ingress/setup/install-existing/", "service": "AKS", "services": [ + "ACR", "AppGW", - "AKS", - "ACR" + "AKS" ], "severity": "Medium", "subcategory": "Best practices", @@ -11697,8 +11697,8 @@ "link": "https://learn.microsoft.com/azure/aks/load-balancer-standard", "service": "AKS", "services": [ - "AKS", - "LoadBalancer" + "LoadBalancer", + "AKS" ], "severity": "High", "subcategory": "Best practices", @@ -11727,10 +11727,10 @@ "link": "https://learn.microsoft.com/azure/private-link/private-link-overview", "service": "AKS", "services": [ + "Cost", "PrivateLink", "AKS", - "VNet", - "Cost" + "VNet" ], "severity": "Medium", "subcategory": "Cost", @@ -11743,8 +11743,8 @@ "guid": "e8a03f97-8794-468d-96a7-86d60f96c97b", "link": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering", "services": [ - "AKS", - "VPN" + "VPN", + "AKS" ], "severity": "Medium", "subcategory": "HA", @@ -12056,8 +12056,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-metric-alerts", "service": "AKS", "services": [ - "AKS", - "Monitor" + "Monitor", + "AKS" ], "severity": "High", "subcategory": "Alerting", @@ -12071,8 +12071,8 @@ "link": "https://learn.microsoft.com/azure/advisor/advisor-get-started", "service": "AKS", "services": [ - "AKS", - "Entra" + "Entra", + "AKS" ], "severity": "Low", "subcategory": "Compliance", @@ -12256,8 +12256,8 @@ "link": "https://learn.microsoft.com/azure/aks/monitor-aks", "service": "AKS", "services": [ - "AKS", - "Monitor" + "Monitor", + "AKS" ], "severity": "Low", "subcategory": "Compliance", @@ -12285,8 +12285,8 @@ "link": "https://learn.microsoft.com/azure/aks/spot-node-pool", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "subcategory": "Cost", @@ -12301,8 +12301,8 @@ "link": "https://learn.microsoft.com/azure/aks/concepts-scale", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "subcategory": "Cost", @@ -12316,8 +12316,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-overview", "service": "AKS", "services": [ - "AKS", - "Monitor" + "Monitor", + "AKS" ], "severity": "High", "subcategory": "Monitoring", @@ -12332,8 +12332,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-overview", "service": "AKS", "services": [ - "AKS", - "Monitor" + "Monitor", + "AKS" ], "severity": "High", "subcategory": "Monitoring", @@ -12347,8 +12347,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/containers/container-insights-analyze", "service": "AKS", "services": [ - "AKS", - "Monitor" + "Monitor", + "AKS" ], "severity": "Medium", "subcategory": "Monitoring", @@ -12362,8 +12362,8 @@ "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", "service": "AKS", "services": [ - "AKS", - "Monitor" + "Monitor", + "AKS" ], "severity": "Medium", "subcategory": "Monitoring", @@ -12378,11 +12378,11 @@ "link": "https://learn.microsoft.com/azure/virtual-machines/premium-storage-performance", "service": "AKS", "services": [ - "ServiceBus", + "Monitor", + "EventHubs", "AKS", "Storage", - "EventHubs", - "Monitor" + "ServiceBus" ], "severity": "Medium", "subcategory": "Monitoring", @@ -12397,9 +12397,9 @@ "service": "AKS", "services": [ "NVA", - "AKS", "LoadBalancer", - "Monitor" + "Monitor", + "AKS" ], "severity": "Medium", "subcategory": "Monitoring", @@ -12413,8 +12413,8 @@ "link": "https://learn.microsoft.com/azure/aks/aks-resource-health", "service": "AKS", "services": [ - "AKS", - "Monitor" + "Monitor", + "AKS" ], "severity": "Medium", "subcategory": "Monitoring", @@ -12647,8 +12647,8 @@ "service": "AKS", "services": [ "Storage", - "AKS", - "SQL" + "SQL", + "AKS" ], "severity": "Medium", "subcategory": "Storage", @@ -13459,8 +13459,8 @@ "service": "Azure OpenAI", "services": [ "AKV", - "Subscriptions", - "Monitor" + "Monitor", + "Subscriptions" ], "severity": "High", "subcategory": "Alerts", @@ -13602,8 +13602,8 @@ "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#batching", "service": "Azure OpenAI", "services": [ - "ServiceBus", - "Storage" + "Storage", + "ServiceBus" ], "severity": "Medium", "subcategory": "Elasticity segregation", @@ -13910,8 +13910,8 @@ "guid": "2bfe4564-b0d8-434a-948b-263e6dd60512", "service": "Azure OpenAI", "services": [ - "AzurePolicy", - "RBAC" + "RBAC", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Sensitive Data in Separate Instances", @@ -14217,8 +14217,8 @@ "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", "service": "Azure OpenAI", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "severity": "Medium", "subcategory": "Cost monitoring", @@ -14274,8 +14274,8 @@ "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/provisioned-throughput-onboarding#understanding-the-provisioned-throughput-purchase-model", "service": "Azure OpenAI", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "High", "subcategory": "Costing Model", @@ -14388,10 +14388,10 @@ "link": "https://github.com/Azure/aoai-apim/blob/main/README.md", "service": "Azure OpenAI", "services": [ - "APIM", - "LoadBalancer", "ACR", - "Entra" + "LoadBalancer", + "Entra", + "APIM" ], "severity": "Medium", "subcategory": "Load Balancing", @@ -14611,8 +14611,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-azure-policy", "service": "ACR", "services": [ - "AzurePolicy", - "ACR" + "ACR", + "AzurePolicy" ], "severity": "High", "subcategory": "Data Protection", @@ -14627,8 +14627,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-tutorial-sign-build-push", "service": "ACR", "services": [ - "AKV", - "ACR" + "ACR", + "AKV" ], "severity": "High", "subcategory": "Data Protection", @@ -14644,8 +14644,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/tutorial-customer-managed-keys", "service": "ACR", "services": [ - "AKV", - "ACR" + "ACR", + "AKV" ], "severity": "Medium", "subcategory": "Data Protection", @@ -14660,9 +14660,9 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication-managed-identity", "service": "ACR", "services": [ - "Entra", + "ACR", "RBAC", - "ACR" + "Entra" ], "severity": "High", "subcategory": "Identity and Access Control", @@ -14678,9 +14678,9 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication-managed-identity", "service": "ACR", "services": [ - "Entra", + "ACR", "RBAC", - "ACR" + "Entra" ], "severity": "High", "subcategory": "Identity and Access Control", @@ -14696,9 +14696,9 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-roles?tabs=azure-cli", "service": "ACR", "services": [ - "Entra", + "ACR", "RBAC", - "ACR" + "Entra" ], "severity": "High", "subcategory": "Identity and Access Control", @@ -14714,8 +14714,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/anonymous-pull-access#configure-anonymous-pull-access", "service": "ACR", "services": [ - "Entra", - "ACR" + "ACR", + "Entra" ], "severity": "Medium", "subcategory": "Identity and Access Control", @@ -14730,8 +14730,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication?tabs=azure-cli", "service": "ACR", "services": [ - "Entra", - "ACR" + "ACR", + "Entra" ], "severity": "High", "subcategory": "Identity and Access Control", @@ -14745,10 +14745,10 @@ "guid": "b3bec3d4-f343-47c1-936d-b55f27a71eee", "service": "ACR", "services": [ - "Entra", - "PrivateLink", + "ACR", "EventHubs", - "ACR" + "Entra", + "PrivateLink" ], "severity": "High", "subcategory": "Identity and Access Control", @@ -14763,9 +14763,9 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-enable-conditional-access-policy", "service": "ACR", "services": [ - "Entra", + "ACR", "AzurePolicy", - "ACR" + "Entra" ], "severity": "Medium", "subcategory": "Identity and Access Control", @@ -14780,9 +14780,9 @@ "link": "https://learn.microsoft.com/azure/container-registry/monitor-service", "service": "ACR", "services": [ - "Entra", + "ACR", "Monitor", - "ACR" + "Entra" ], "severity": "Medium", "subcategory": "Logging and Monitoring", @@ -14797,10 +14797,10 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-private-link", "service": "ACR", "services": [ + "ACR", "PrivateLink", "Firewall", - "VNet", - "ACR" + "VNet" ], "severity": "Medium", "subcategory": "Network Security", @@ -14816,8 +14816,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-access-selected-networks#disable-public-network-access", "service": "ACR", "services": [ - "PrivateLink", - "ACR" + "ACR", + "PrivateLink" ], "severity": "Medium", "subcategory": "Network Security", @@ -14833,8 +14833,8 @@ "link": "https://learn.microsoft.com/azure/container-registry/container-registry-skus", "service": "ACR", "services": [ - "PrivateLink", - "ACR" + "ACR", + "PrivateLink" ], "severity": "Medium", "subcategory": "Network Security", @@ -14849,8 +14849,8 @@ "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-containers-introduction", "service": "ACR", "services": [ - "Defender", - "ACR" + "ACR", + "Defender" ], "severity": "Low", "subcategory": "Network Security", @@ -14893,8 +14893,8 @@ "link": "https://learn.microsoft.com/azure/data-explorer/kusto/management/data-export/continuous-data-export", "service": "Azure Data Explorer", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "subcategory": "Replication", "text": "Leverage External Tables and Continuous data export overview to reduce costs", @@ -14935,8 +14935,8 @@ "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-create-solution#replicate-management-activities", "service": "Azure Data Explorer", "services": [ - "RBAC", - "Storage" + "Storage", + "RBAC" ], "subcategory": "Replication", "text": "Replicate all management activities such as creating new tables or managing user roles on each cluster.", @@ -15001,10 +15001,10 @@ "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#on-demand-data-recovery-configuration", "service": "Azure Data Explorer", "services": [ - "AzurePolicy", + "Cost", "Storage", "ASR", - "Cost" + "AzurePolicy" ], "subcategory": "DR Configuration", "text": "For applications, where cost is a concern and can withstand some downtime during failure, create on-demand data recovery cluster configuration", @@ -15083,8 +15083,8 @@ "link": "https://learn.microsoft.com/azure/reliability/reliability-traffic-manager?toc=%2Fazure%2Fdns%2Ftoc.json", "services": [ "TrafficManager", - "DNS", - "ASR" + "ASR", + "DNS" ], "severity": "Medium", "subcategory": "Azure DNS", @@ -15110,8 +15110,8 @@ "guid": "f7b95e06-e154-4e2a-a359-2828e6e20517", "link": "https://learn.microsoft.com/azure/dns/tutorial-dns-private-resolver-failover", "services": [ - "DNS", - "ASR" + "ASR", + "DNS" ], "severity": "Medium", "subcategory": "Azure DNS Resolver", @@ -15235,8 +15235,8 @@ "service": "AVS", "services": [ "AVS", - "Subscriptions", - "Entra" + "Entra", + "Subscriptions" ], "severity": "High", "subcategory": "Identity", @@ -15393,11 +15393,11 @@ "guid": "eb710a37-cbc1-4055-8dd5-a936a8bb7cf5", "service": "AVS", "services": [ + "ExpressRoute", "AVS", + "Monitor", "VPN", - "NetworkWatcher", - "ExpressRoute", - "Monitor" + "NetworkWatcher" ], "severity": "High", "subcategory": "Monitoring", @@ -15410,11 +15410,11 @@ "guid": "976e24f2-a7f8-426c-9253-2a92a2a7ed99", "service": "AVS", "services": [ - "VM", - "AVS", - "NetworkWatcher", "ExpressRoute", - "Monitor" + "AVS", + "Monitor", + "VM", + "NetworkWatcher" ], "severity": "Medium", "subcategory": "Monitoring", @@ -15428,9 +15428,9 @@ "service": "AVS", "services": [ "VM", - "NetworkWatcher", + "Monitor", "AVS", - "Monitor" + "NetworkWatcher" ], "severity": "Medium", "subcategory": "Monitoring", @@ -15443,8 +15443,8 @@ "guid": "563b4dc7-4a74-48b6-933a-d1a0916a6649", "service": "AVS", "services": [ - "AVS", - "ARS" + "ARS", + "AVS" ], "severity": "High", "subcategory": "Routing", @@ -15600,8 +15600,8 @@ "guid": "29e3eec2-1836-487a-8077-a2b5945bda43", "service": "AVS", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Security (network)", @@ -15615,11 +15615,11 @@ "guid": "334fdf91-c234-4182-a652-75269440b4be", "service": "AVS", "services": [ + "ExpressRoute", "AVS", "VPN", - "DDoS", - "ExpressRoute", - "VNet" + "VNet", + "DDoS" ], "severity": "Medium", "subcategory": "Security (network)", @@ -15645,8 +15645,8 @@ "guid": "9ccbd869-266a-4cca-874f-aa19bf39d95d", "service": "AVS", "services": [ - "AVS", - "Defender" + "Defender", + "AVS" ], "severity": "Medium", "subcategory": "Security (guest/VM)", @@ -15659,8 +15659,8 @@ "guid": "44c7c891-9ca1-4f6d-9315-ae524ba34d45", "service": "AVS", "services": [ - "AVS", - "Arc" + "Arc", + "AVS" ], "severity": "Medium", "subcategory": "Security (guest/VM)", @@ -15727,9 +15727,9 @@ "guid": "d88408f3-7273-44c8-96ba-280214590146", "service": "AVS", "services": [ - "AzurePolicy", "Storage", - "AVS" + "AVS", + "AzurePolicy" ], "severity": "High", "subcategory": "Governance (platform)", @@ -15742,8 +15742,8 @@ "guid": "d89f2e87-7784-424d-9167-85c6fa95b96a", "service": "AVS", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "High", "subcategory": "Governance (platform)", @@ -15769,8 +15769,8 @@ "guid": "bf39d95d-44c7-4c89-89ca-1f6d5315ae52", "service": "AVS", "services": [ - "AzurePolicy", - "AVS" + "AVS", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Governance (platform)", @@ -15783,8 +15783,8 @@ "guid": "4ba34d45-85e1-4213-abd7-bb012f7b95ef", "service": "AVS", "services": [ - "AVS", - "Cost" + "Cost", + "AVS" ], "severity": "Medium", "subcategory": "Governance (platform)", @@ -15797,8 +15797,8 @@ "guid": "6e043e2a-a359-4271-ae6e-205172676ae4", "service": "AVS", "services": [ - "AVS", - "Cost" + "Cost", + "AVS" ], "severity": "Low", "subcategory": "Governance (platform)", @@ -15837,9 +15837,9 @@ "guid": "48b262d6-cc5f-4512-a253-98e6db9d37da", "service": "AVS", "services": [ + "Defender", "VM", - "AVS", - "Defender" + "AVS" ], "severity": "Medium", "subcategory": "Governance (guest/VM)", @@ -15852,9 +15852,9 @@ "guid": "41741583-3ef7-4ad7-a6d3-733165c7acbe", "service": "AVS", "services": [ + "Arc", "VM", - "AVS", - "Arc" + "AVS" ], "severity": "Medium", "subcategory": "Governance (guest/VM)", @@ -15881,8 +15881,8 @@ "service": "AVS", "services": [ "VM", - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Governance (guest/VM)", @@ -15896,9 +15896,9 @@ "service": "AVS", "services": [ "VM", + "Backup", "AVS", - "AzurePolicy", - "Backup" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Governance (guest/VM)", @@ -15911,9 +15911,9 @@ "guid": "ee29711b-d352-4caa-ab79-b198dab81932", "service": "AVS", "services": [ - "AVS", + "Defender", "Monitor", - "Defender" + "AVS" ], "severity": "Medium", "subcategory": "Compliance", @@ -15926,8 +15926,8 @@ "guid": "c9fc9d1b-b780-436f-9e6b-fbb9ed503547", "service": "AVS", "services": [ - "AVS", - "Defender" + "Defender", + "AVS" ], "severity": "Medium", "subcategory": "Compliance", @@ -15979,8 +15979,8 @@ "guid": "e43a18a9-cd28-49ce-b6b1-7db8255461e2", "service": "AVS", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "High", "subcategory": "Monitoring", @@ -15994,8 +15994,8 @@ "guid": "6b84ee5d-f47d-42d9-8881-b1cd5d1e54a2", "service": "AVS", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "High", "subcategory": "Monitoring", @@ -16009,8 +16009,8 @@ "guid": "9659e396-80e7-4828-ac93-5657d02bff45", "service": "AVS", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "High", "subcategory": "Monitoring", @@ -16024,8 +16024,8 @@ "guid": "64b0d934-a348-4726-be79-d6b5c3a36495", "service": "AVS", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "High", "subcategory": "Monitoring", @@ -16039,8 +16039,8 @@ "service": "AVS", "services": [ "Storage", - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Monitoring", @@ -16053,8 +16053,8 @@ "guid": "9674c5ed-85b8-459c-9733-be2b1a27b775", "service": "AVS", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Low", "subcategory": "Monitoring", @@ -16067,10 +16067,10 @@ "guid": "a91be1f3-88f0-43a4-b2cd-463cbbbc8682", "service": "AVS", "services": [ - "AzurePolicy", "Storage", + "VM", "AVS", - "VM" + "AzurePolicy" ], "severity": "High", "subcategory": "Operations", @@ -16097,8 +16097,8 @@ "service": "AVS", "services": [ "Storage", - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Operations", @@ -16111,8 +16111,8 @@ "guid": "2aee3453-aec8-4339-848b-262d6cc5f512", "service": "AVS", "services": [ - "AVS", - "Arc" + "Arc", + "AVS" ], "severity": "Medium", "subcategory": "Operations", @@ -16125,8 +16125,8 @@ "guid": "925398e6-da9d-437d-ac43-bc6cd1d79a9b", "service": "AVS", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Operations", @@ -16152,9 +16152,9 @@ "guid": "17e7a8d9-0ae0-4e27-aee2-9711bd352caa", "service": "AVS", "services": [ - "AzurePolicy", + "Monitor", "AVS", - "Monitor" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Operations", @@ -16167,8 +16167,8 @@ "guid": "aee3553a-fc83-4392-98b2-62d6cc5f5129", "service": "AVS", "services": [ - "AVS", - "Defender" + "Defender", + "AVS" ], "severity": "Medium", "subcategory": "Security", @@ -16181,8 +16181,8 @@ "guid": "25398e6d-b9d3-47da-a43b-c6cd1d79a9b2", "service": "AVS", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Backup", @@ -16195,8 +16195,8 @@ "guid": "5e6bfbb9-ed50-4354-9cc4-47e826028a71", "service": "AVS", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -16209,8 +16209,8 @@ "guid": "f0f1cac6-d9ef-41d5-b832-d42e3611c818", "service": "AVS", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -16223,8 +16223,8 @@ "guid": "b0afbc51-0e43-4a18-a9cd-289bed6b17db", "service": "AVS", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "High", "subcategory": "Disaster Recovery", @@ -16237,8 +16237,8 @@ "guid": "8255461e-2aee-4345-9aec-8339248b262d", "service": "AVS", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -16251,8 +16251,8 @@ "guid": "6cc5f512-9253-498e-9da9-d37dac43bc6c", "service": "AVS", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "High", "subcategory": "Disaster Recovery", @@ -16266,9 +16266,9 @@ "service": "AVS", "services": [ "NVA", - "AVS", "ASR", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -16281,8 +16281,8 @@ "guid": "33bd2a09-17e7-4a8d-a0ae-0e27cee29711", "service": "AVS", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -16295,8 +16295,8 @@ "guid": "bd352caa-ab79-4b18-adab-81932c9fc9d1", "service": "AVS", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -16309,8 +16309,8 @@ "guid": "bb77036f-5e6b-4fbb-aed5-03547cc447e8", "service": "AVS", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -16388,8 +16388,8 @@ "guid": "0f1cac6d-9ef1-4d5e-a32e-42e3611c818b", "service": "AVS", "services": [ - "AzurePolicy", - "AVS" + "AVS", + "AzurePolicy" ], "severity": "Low", "subcategory": "Automated Deployment", @@ -16417,8 +16417,8 @@ "service": "AVS", "services": [ "AKV", - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Low", "subcategory": "Automated Connectivity", @@ -16471,9 +16471,9 @@ "guid": "d352caaa-b79b-4198-bab8-1932c9fc9d1b", "service": "AVS", "services": [ - "AzurePolicy", "Storage", - "AVS" + "AVS", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -16525,8 +16525,8 @@ "guid": "1dc15a1c-075e-4e9f-841a-cccd579376bc", "service": "AVS", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -16570,8 +16570,8 @@ "guid": "bc91a43d-90da-4e2c-a881-4706f7c1cbaf", "service": "AVS", "services": [ - "AVS", - "VPN" + "VPN", + "AVS" ], "severity": "Medium", "subcategory": "Networking", @@ -16611,8 +16611,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings", "service": "AVS", "services": [ - "VM", "Storage", + "VM", "AVS" ], "severity": "Medium", @@ -16628,8 +16628,8 @@ "service": "AVS", "services": [ "Storage", - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "Architecture", @@ -16644,8 +16644,8 @@ "service": "AVS", "services": [ "Storage", - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "Architecture", @@ -16659,8 +16659,8 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group", "service": "AVS", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "High", "subcategory": "Architecture", @@ -16688,8 +16688,8 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes", "service": "AVS", "services": [ - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "High", "subcategory": "Architecture", @@ -16703,8 +16703,8 @@ "link": "https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity", "service": "AVS", "services": [ - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "High", "subcategory": "Architecture", @@ -16726,11818 +16726,12089 @@ "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.App/containerApps", "checklist": "WAF checklist", - "description": "Disable image export to prevent data exfiltration. Note that this will prevent image import of images into another ACR instance.", - "guid": "ab91932c-9fc9-4d1b-a880-37f5e6bfcb9e", - "link": "https://learn.microsoft.com/azure/container-registry/data-loss-prevention", - "query": "resources | where type =~ 'Microsoft.ContainerRegistry/registries' | extend acrName = name, acrId = id | extend exportPolicyStatus = properties.policies.exportPolicy.status | extend compliant = iif(exportPolicyStatus =~ 'Disabled', true, false) | project acrName, acrId, exportPolicyStatus, compliant", - "service": "ACR", + "guid": "af416482-663c-4ed6-b195-b44c7068e09c", + "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#availability-zone-support", + "query": "resources | where type =~ 'Microsoft.App/managedEnvironments' | project name, resourceGroup, location, zoneRedundancy = tolower(tostring(properties.zoneRedundant)) | extend Compliance = iff(zoneRedundancy == 'true', true, false)", + "service": "Container Apps", "services": [ - "WAF", - "ACR" + "WAF" ], "severity": "High", - "text": "Disable Azure Container Registry image export", - "waf": "Security" + "text": "Leverage Availability Zones if regionally applicable", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.App/containerApps", "checklist": "WAF checklist", - "description": "Enable audit compliance visibility by enabling Azure Policy for Azure Container Registry", - "guid": "d503547c-d447-4e82-9128-a7100f1cac6d", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-azure-policy", - "service": "ACR", + "guid": "95bc80ec-6499-4d14-a7d2-7d296b1d8abc", + "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#set-up-zone-redundancy-in-your-container-apps-environment", + "query": "resources | where type =~ 'Microsoft.App/containerApps' | project name, resourceGroup, location, minReplicas = toint(properties.template.scale.minReplicas), maxReplicas = toint(properties.template.scale.maxReplicas) | extend Compliance = iff(minReplicas >= 1, true, false)", + "service": "Container Apps", "services": [ - "AzurePolicy", - "WAF", - "ACR" + "WAF" ], "severity": "High", - "text": "Enable Azure Policies for Azure Container Registry", - "waf": "Security" + "text": "Use more than one replica and enable Zone Redundancy.", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.App/containerApps", "checklist": "WAF checklist", - "description": "The Azure Key Vault (AKV) is used to store a signing key that can be utilized by?notation?with the notation AKV plugin (azure-kv) to sign and verify container images and other artifacts. The Azure Container Registry (ACR) allows you to attach these signatures using the?az?or?oras?CLI commands.", - "guid": "d345293c-7639-4637-a551-c5c04e401955", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-tutorial-sign-build-push", - "service": "ACR", + "guid": "ccaa4fc2-fdbc-4432-8bb7-f7e6469e4dc3", + "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#cross-region-disaster-recovery-and-business-continuity", + "service": "Container Apps", "services": [ - "AKV", - "WAF", - "ACR" + "WAF" ], "severity": "High", - "text": "Sign and Verify containers with notation (Notary v2)", - "waf": "Security" - }, - { - "arm-service": "microsoft.containerregistry/registries", - "checklist": "WAF checklist", - "description": "Azure Container Registry automatically encrypts images and other artifacts that you store. By default, Azure automatically encrypts the registry content at rest by using service-managed keys. By using a customer-managed key, you can supplement default encryption with an additional encryption layer.", - "graph": "resources | where type =~ 'Microsoft.ContainerRegistry/registries' | extend acrName = name, acrId = id | extend encryptionStatus = properties.encryption.status | extend compliant = iif(encryptionStatus == 'disabled', false, true) | project acrName, acrId, encryptionStatus, compliant", - "guid": "0bd05dc2-efd5-4d76-8d41-d2500cc47b49", - "link": "https://learn.microsoft.com/azure/container-registry/tutorial-customer-managed-keys", - "service": "ACR", - "services": [ - "AKV", - "WAF", - "ACR" - ], - "severity": "Medium", - "text": "Encrypt registry with a customer managed key", - "waf": "Security" + "text": "For cross-region DR, deploy container apps in multiple regions and follow active/active or active/passive application guidance.", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.App/containerApps", "checklist": "WAF checklist", - "description": "Use managed identities to secure ACRPull/Push RBAC access from client applications", - "guid": "8f42d78e-79dc-47b3-9bd2-a1a27e7a8e90", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication-managed-identity", - "service": "ACR", + "guid": "2ffada86-c031-4933-bf7d-0c45bc4e5919", + "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#cross-region-disaster-recovery-and-business-continuity", + "service": "Container Apps", "services": [ - "RBAC", - "WAF", - "ACR", - "Entra" + "FrontDoor", + "TrafficManager", + "WAF" ], "severity": "High", - "text": "Use Managed Identities to connect instead of Service Principals", - "waf": "Security" + "text": "Use Front Door or Traffic Manager to route traffic to the closest region", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "The local Administrator account is disabled by default and should not be enabled. Use either Token or RBAC-based access methods instead", - "graph": "resources | where type =~ 'microsoft.containerregistry/registries' | extend localAdminDisabled = properties.adminUserEnabled // Adjust this property as needed | extend compliant = iif(localAdminDisabled == 'false', true, false) // Check if local admin is disabled | project compliant, name, id, tags | distinct id, compliant", - "guid": "be0e38ce-e297-411b-b363-caaab79b198d", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication-managed-identity", - "service": "ACR", + "guid": "1fc2fc14-eea6-4e69-b8d9-a3edc218e687", + "link": "https://polite-sea-0995b240f.2.azurestaticapps.net/technical-delivery-playbook/azure-services/analytics/purview/", + "service": "Purview", "services": [ - "RBAC", "WAF" ], - "severity": "High", - "text": "Disable local authentication for management plane access", - "waf": "Security" + "severity": "Medium", + "text": "Leverage FTA Resillency Handbook", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Disable Administrator account and assign RBAC roles to principals for ACR Pull/Push operations", - "graph": "resources | where type =~ 'microsoft.containerregistry/registries' | extend localAdminDisabled = properties.adminUserEnabled // Adjust this property as needed | extend compliant = iif(localAdminDisabled == 'false', true, false) // Check if local admin is disabled | project compliant, name, id, tags | distinct id, compliant", - "guid": "387e5ced-126c-4d13-8af5-b20c6998a646", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-roles?tabs=azure-cli", - "service": "ACR", + "guid": "ab067acb-49e5-4b96-8332-4ecf8cc13318", + "link": "https://learn.microsoft.com/purview/disaster-recovery", + "service": "Purview", "services": [ - "RBAC", - "WAF", - "ACR", - "Entra" + "WAF" ], "severity": "High", - "text": "Assign AcrPull & AcrPush RBAC roles rather than granting Administrative access to identity principals", - "waf": "Security" + "text": "Plan for Data Center level outage", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Disable anonymous pull/push access", - "graph": "resources | where type =~ 'microsoft.containerregistry/registries' | extend compliant = iif(properties.anonymousPullEnabled == false, true, false) | project compliant, name, id, tags | distinct id, compliant", - "guid": "e338997e-41c7-47d7-acf6-a62a1194956d", - "link": "https://learn.microsoft.com/azure/container-registry/anonymous-pull-access#configure-anonymous-pull-access", - "service": "ACR", + "description": "1. Create the new account 2. Migrate configuration items 3. Run scans 4. Migrate custom typedefs and custom assets 5. Migrate relationships 6. Migrate glossary terms 7. Assign classifications to assets 8. Assign contacts to assets", + "guid": "da611702-69f4-4fb4-aa3d-3ef7f3176c4b", + "link": "https://learn.microsoft.com/purview/disaster-recovery", + "service": "Purview", "services": [ "WAF" ], "severity": "Medium", - "text": "Disable Anonymous pull access", - "waf": "Security" + "text": "Practice Failover for BCDR", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Token authentication doesn't support assignment to an AAD principal. Any tokens provided are able to be used by anyone who can access the token", - "guid": "698dc3a2-fd27-4b2e-8870-1a1252beedf6", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication?tabs=azure-cli", - "service": "ACR", + "guid": "97b15b8a-219a-44ab-bb57-879024d22678", + "link": "https://learn.microsoft.com/purview/disaster-recovery", + "service": "Purview", "services": [ - "WAF", - "Entra" + "Backup", + "WAF" ], "severity": "High", - "text": "Disable repository-scoped access tokens", - "waf": "Security" + "text": "Plan a backup strategy and take regular backups", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Deploy container images to an ACR behind a Private endpoint within a trusted network", - "guid": "b3bec3d4-f343-47c1-936d-b55f27a71eee", - "service": "ACR", + "guid": "6d20b56c-56a9-4581-89bf-8d8e5c586b7d", + "link": "https://learn.microsoft.com/purview/manage-kafka-dotnet", + "service": "Purview", "services": [ "EventHubs", - "PrivateLink", - "WAF", - "ACR" + "WAF" ], - "severity": "High", - "text": "Deploy images from a trusted environment", - "waf": "Security" + "severity": "Low", + "text": "Use Microsoft Purview's Event Hubs to subscribe and create entities to another account", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Only tokens with an ACR audience can be used for authentication. Used when enabling Conditional access policies for ACR", - "guid": "3a041fd3-2947-498b-8288-b3c6a56ceb54", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-enable-conditional-access-policy", - "service": "ACR", + "guid": "8cdc15ac-c075-4ee9-a130-a8889579e76b", + "link": "https://learn.microsoft.com/purview/deployment-best-practices", + "service": "Purview", "services": [ - "AzurePolicy", - "WAF", - "ACR", - "Entra" + "WAF" ], "severity": "Medium", - "text": "Disable Azure ARM audience tokens for authentication", - "waf": "Security" + "text": "Follow Purview accounts architectures and deployment best practices", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Set up a diagnostic setting to send 'repositoryEvents' & 'LoginEvents' to Log Analytics as the central destination for logging and monitoring. This allows you to monitor control plane activity on the ACR resource itself.", - "guid": "8a488cde-c486-42bc-9bd2-1be77f26e5e6", - "link": "https://learn.microsoft.com/azure/container-registry/monitor-service", - "service": "ACR", + "guid": "896e710a-7da7-4be9-a56d-14d3c49d997c", + "link": "https://learn.microsoft.com/purview/concept-best-practices-collections", + "service": "Purview", "services": [ - "Monitor", - "WAF", - "ACR", - "Entra" + "WAF" ], "severity": "Medium", - "text": "Enable diagnostics logging", - "waf": "Security" + "text": "Follow Collection Architectures and best practices", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Service supports disabling public network access either through using service-level IP ACL filtering rule (not NSG or Azure Firewall) or using a 'Disable Public Network Access' toggle switch", - "guid": "21d41d25-00b7-407a-b9ea-b40fd3290798", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-private-link", - "service": "ACR", + "guid": "b3d1325a-a225-4c6f-9e06-85edddea8a4b", + "link": "https://learn.microsoft.com/purview/concept-best-practices-asset-lifecycle", + "service": "Purview", "services": [ - "PrivateLink", - "Firewall", - "VNet", "WAF" ], "severity": "Medium", - "text": "Control inbound network access with Private Link", - "waf": "Security" + "text": "Follow Assest lifecycle best practices", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Disable public network access if inbound network access is secured using Private Link", - "graph": "resources | where type =~ 'Microsoft.ContainerRegistry/registries' | where sku.name =~ 'Premium' // Check for Premium SKU | extend publicAccessEnabled = properties.publicNetworkAccess | extend defaultAction = tostring(properties.networkRuleSet.defaultAction) // Extract defaultAction | extend compliant = iif(publicAccessEnabled != 'Enabled' or defaultAction == 'Deny', true, false) | project name, id, publicAccessEnabled, defaultAction, compliant", - "guid": "cd289ced-6b17-4db8-8554-62f2aee4553a", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-access-selected-networks#disable-public-network-access", - "service": "ACR", + "guid": "7cdeb3c6-1fc2-4fc1-9eea-6e69d8d9a3ed", + "link": "https://learn.microsoft.com/purview/concept-best-practices-automation", + "service": "Purview", "services": [ - "PrivateLink", "WAF" ], "severity": "Medium", - "text": "Disable Public Network access", - "waf": "Security" + "text": "Follow automation best practices", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Only the ACR Premium SKU supports Private Link access", - "graph": "resources | where type =~ 'Microsoft.ContainerRegistry/registries' | extend skuName = sku.name // Extract the SKU name | extend compliant = iif(skuName == 'Premium', true, false) // Check if SKU is Premium | project name, id, skuName, compliant", - "guid": "fc833934-8b26-42d6-ac5f-512925498f6d", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-skus", - "service": "ACR", + "guid": "c218e687-ab06-47ac-a49e-5b9603324ecf", + "link": "https://learn.microsoft.com/purview/disaster-recovery", + "service": "Purview", "services": [ - "PrivateLink", - "WAF", - "ACR" + "Backup", + "WAF" ], "severity": "Medium", - "text": "Use an Azure Container Registry SKU that supports Private Link (Premium SKU)", - "waf": "Security" + "text": "Follow Backup and Migration Best practices", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Azure Defender for containers or equivalent service should be used to scan container images for vulnerabilities", - "guid": "bad37dac-43bc-46ce-8d7a-a9b24604489a", - "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-containers-introduction", - "service": "ACR", + "guid": "8cc13318-da61-4170-869f-4fb4aa3d3ef7", + "link": "https://learn.microsoft.com/purview/concept-best-practices-glossary", + "service": "Purview", "services": [ - "WAF", - "ACR", - "Defender" - ], - "severity": "Low", - "text": "Enable Defender for Containers to scan Azure Container Registry for vulnerabilities", - "waf": "Security" - }, - { - "arm-service": "microsoft.containerregistry/registries", - "checklist": "WAF checklist", - "description": "Deploy trusted code that was validated and scanned for vulnerabilities according to DevSecOps practices.", - "guid": "4451e1a2-d345-4293-a763-9637a551c5c0", - "service": "ACR", - "services": [ - "WAF" + "WAF" ], "severity": "Medium", - "text": "Deploy validated container images", - "waf": "Security" + "text": "Follow Purview Glossary Best Practices", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Use the latest versions of supported platforms, programming languages, protocols, and frameworks.", - "guid": "4e401955-387e-45ce-b126-cd132af5b20c", - "service": "ACR", + "guid": "f3176c4b-97b1-45b8-a219-a4abeb578790", + "link": "https://learn.microsoft.com/purview/concept-workflow", + "service": "Purview", "services": [ "WAF" ], - "severity": "High", - "text": "Use up-to-date platforms, languages, protocols and frameworks", - "waf": "Security" + "severity": "Low", + "text": "Leverage Workflows ", + "waf": "Reliability" }, { - "arm-service": "Microsoft.DataFactory/datafactories", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "ab91932c-9fc9-4d1b-a881-37f5e6c0cb9e", - "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/paas-foundations-playbooks-ADF_v1.docx", - "service": "Azure Data Factory", + "guid": "24d22678-6d20-4b56-a56a-958119bf8d8e", + "link": "https://learn.microsoft.com/purview/concept-best-practices-security", + "service": "Purview", "services": [ "WAF" ], "severity": "Medium", - "text": "Leverage FTA Resiliency Playbook for Azure Data Factory", + "text": "Follow Purview Security Best Practices", "waf": "Reliability" }, { - "arm-service": "Microsoft.DataFactory/datafactories", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "e503547c-d447-4e82-9138-a7200f1cac6d", - "link": "https://learn.microsoft.com/azure/architecture/example-scenario/analytics/pipelines-disaster-recovery", - "service": "Azure Data Factory", + "guid": "5c586b7d-8cdc-415a-ac07-5ee9b130a888", + "link": "https://learn.microsoft.com/purview/concept-best-practices-lineage-azure-data-factory", + "service": "Purview", "services": [ "WAF" ], - "severity": "High", - "text": "Use zone redundant pipelines in regions that support Availability Zones", + "severity": "Medium", + "text": "Follow Purview Data Lineage Best Practices", "waf": "Reliability" }, { - "arm-service": "Microsoft.DataFactory/datafactories", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "9ef1d6e8-32e5-42e3-911c-818b1a0bc511", - "link": "https://learn.microsoft.com/azure/data-factory/source-control", - "service": "Azure Data Factory", + "guid": "9579e76b-896e-4710-a7da-7be9956d14d3", + "link": "https://learn.microsoft.com/purview/concept-best-practices-scanning", + "service": "Purview", "services": [ - "WAF", - "Backup" + "WAF" ], "severity": "Medium", - "text": "Use DevOps to Backup the ARM templates with Github/Azure DevOps integration ", + "text": "Follow Best Practices for Scanning Registered Sources", "waf": "Reliability" }, { - "arm-service": "Microsoft.DataFactory/datafactories", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "e43a18a9-cd29-49cf-b7b1-7db8255562f2", - "link": "https://learn.microsoft.com/azure/architecture/example-scenario/analytics/pipelines-disaster-recovery", - "service": "Azure Data Factory", + "guid": "c49d997c-b3d1-4325-aa22-5c6f4e0685ed", + "link": "https://learn.microsoft.com/purview/concept-best-practices-classification", + "service": "Purview", "services": [ - "VM", "WAF" ], "severity": "Medium", - "text": "Make sure you replicate the Self-Hosted Integration Runtime VMs in another region ", + "text": "Follow Classification Best Practices in Governance Portal", "waf": "Reliability" }, { - "arm-service": "Microsoft.DataFactory/datafactories", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "aee4563a-fd83-4393-98b2-62d6dc5f512a", - "link": "https://learn.microsoft.com/azure/architecture/example-scenario/analytics/pipelines-disaster-recovery", - "service": "Azure Data Factory", + "guid": "ddea8a4b-7cde-4b3c-91fc-2fc14eea6e69", + "link": "https://learn.microsoft.com/purview/sensitivity-labels-frequently-asked-questions", + "service": "Purview", "services": [ - "VNet", "WAF" ], "severity": "Medium", - "text": "Make sure you replicate or duplicate your network in the sister region. You have to make a copy of your Vnet in another region", + "text": "Perform Sensitivity Labelling in the Purview Data Map", "waf": "Reliability" }, { - "arm-service": "Microsoft.DataFactory/datafactories", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "If your ADF Pipelines use Key Vault you don't have to do anything to replicate Key Vault. Key Vault is a managed service and Microsoft takes care of it for you", - "guid": "25498f6d-bad3-47da-a43b-c6ce1d7aa9b2", - "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance", - "service": "Azure Data Factory", + "guid": "d8d9a3ed-c218-4e68-9ab0-67acb49e5b96", + "link": "https://learn.microsoft.com/purview/concept-data-share", + "service": "Purview", "services": [ - "AKV", + "Storage", "WAF" ], "severity": "Low", - "text": "If using Keyvault integration, use SLA of Keyvault to understand your availablity", + "text": "Leverage Azure Storage in-place data sharing with Microsoft Purview", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Using the correct approach to feed a datalake with cold data and having the Kusto query engine at your disposal at the same time, as in the short-term storage", - "guid": "ba7da7be-9951-4914-a384-5d997cb39132", - "link": "https://learn.microsoft.com/azure/data-explorer/kusto/management/data-export/continuous-data-export", - "service": "Azure Data Explorer", + "guid": "03324ecf-8cc1-4331-ada6-1170269f4fb4", + "link": "https://learn.microsoft.com/purview/concept-insights", + "service": "Purview", "services": [ - "Storage", - "WAF", - "Cost" + "WAF" ], - "text": "Leverage External Tables and Continuous data export overview to reduce costs", + "severity": "Low", + "text": "Leverage Data Estate Insights", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Azure Data Explorer provides an optional follower capability for a leader cluster to be followed by other follower clusters for read-only access to the leader's data and metadata. Changes in the leader, such as create, append, and drop are automatically synchronized to the follower. While the leaders could span Azure regions, the follower clusters should be hosted in the same region(s) as the leader. If the leader cluster is down or databases or tables are accidentally dropped, the follower clusters will lose access until access is recovered in the leader.", - "guid": "56a22586-f490-4641-addd-ea8a377cdeb3", - "link": "https://learn.microsoft.com/azure/data-explorer/follower?tabs=csharp", - "service": "Azure Data Explorer", + "guid": "aa3d3ef7-f317-46c4-a97b-15b8a219a4ab", + "link": "https://learn.microsoft.com/purview/catalog-adoption-insights", + "service": "Purview", "services": [ - "Storage", "WAF" ], - "text": "To share data, explore Leader-follower cluster configuration", + "severity": "Low", + "text": "Use Data stewardship and Catalog adoption", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "Azure Data Explorer doesn't support automatic protection against the outage of an entire Azure region. This disruption can happen during a natural disaster, like an earthquake. If you require a solution for a disaster recovery situation, do the following steps to ensure business continuity. In these steps, you'll replicate your clusters, management, and data ingestion in two Azure paired regions.", - "guid": "861bb2bc-14ae-4a6e-95d8-d9a3adc218e6", - "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-create-solution#create-multiple-independent-clusters", - "service": "Azure Data Explorer", + "guid": "eb578790-24d2-4267-a6d2-0b56c56a9581", + "link": "https://learn.microsoft.com/purview/concept-insights", + "service": "Purview", "services": [ - "ASR", "WAF" ], - "text": "To protect against regional failure, create Multiple independent clusters, preferably in two Azure Paired regions", + "severity": "Low", + "text": "Use Inventory and Ownership", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "436b0635-cb45-4e57-a603-324ace8cc123", - "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-create-solution#replicate-management-activities", - "service": "Azure Data Explorer", + "guid": "19bf8d8e-5c58-46b7-b8cd-c15acc075ee9", + "link": "https://learn.microsoft.com/purview/glossary-insights", + "service": "Purview", "services": [ - "RBAC", - "Storage", "WAF" ], - "text": "Replicate all management activities such as creating new tables or managing user roles on each cluster.", + "severity": "Low", + "text": "Leverage Insights for Glossary, Classifications, Sensitivity Labels", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "18ca6017-0265-4f4b-a46a-393af7f31728", - "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-create-solution", - "service": "Azure Data Explorer", + "guid": "b130a888-9579-4e76-a896-e710a7da7be9", + "link": "https://learn.microsoft.com/purview/compliance-manager", + "service": "Purview", "services": [ "WAF" ], - "text": "Ingest data into each cluster in parallel", + "severity": "Medium", + "text": "Generate assessment scores", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "This configuration is also called 'always-on'. For critical application deployments with no tolerance for outages, you should use multiple Azure Data Explorer clusters across Azure paired regions.", - "guid": "58a9c279-9c42-4bb6-9d0c-65556246b338", - "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#active-active-active-configuration", - "service": "Azure Data Explorer", + "guid": "956d14d3-c49d-4997-ab3d-1325aa225c6f", + "link": "https://learn.microsoft.com/purview/compliance-manager-scoring", + "service": "Purview", "services": [ - "WAF", - "ACR" + "WAF" ], - "text": "For critical application with no tolerance for outages, create Active-Active-Active (always-on) configuration", + "severity": "Medium", + "text": "Profiling- get summaries of data content", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "This configuration is identical to the active-active-active configuration, but only involves two Azure paired regions. Configure dual ingestion, processing, and curation. Users are routed to the nearest region. The cluster SKU must be the same across regions.", - "guid": "563a4dc7-4a74-48b6-922a-d190916a6649", - "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#active-active-configuration", - "service": "Azure Data Explorer", + "guid": "4e0685ed-ddea-48a4-a7cd-eb3c61fc2fc1", + "link": "https://learn.microsoft.com/purview/concept-policies-data-owner#microsoft-purview-policy-concepts", + "service": "Purview", "services": [ - "WAF", - "ACR" + "AzurePolicy", + "WAF" ], - "text": "For critical applications, create Active-Active configuration in two paired regions", + "severity": "Low", + "text": "Follow Microsoft Purview Data Owner access policies", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "The Active-Hot configuration is similar to the Active-Active configuration in dual ingest, processing, and curation. While the standby cluster is online for ingestion, process, and curation, it isn't available to query. The standby cluster doesn't need to be in the same SKU as the primary cluster. It can be of a smaller SKU and scale, which may result in it being less performant. In a disaster scenario, users are redirected to the standby cluster, which can optionally be scaled up to increase performance.", - "guid": "8fadfe27-7de2-483b-8ac3-52baa9b75708", - "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#active-hot-standby-configuration", - "service": "Azure Data Explorer", + "guid": "4eea6e69-d8d9-4a3e-bc21-8e687ab067ac", + "link": "https://learn.microsoft.com/purview/concept-self-service-data-access-policy", + "service": "Purview", "services": [ + "AzurePolicy", "WAF" ], - "text": "For applications, which required only read during failure, create Active-Hot standby configuration", + "severity": "Low", + "text": "Follow Self-service access policies", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "description": "This solution offers the least resiliency (highest RPO and RTO), is the lowest in cost and highest in effort. In this configuration, there's no data recovery cluster. Configure continuous export of curated data (unless raw and intermediate data is also required) to a storage account that is configured GRS (Geo Redundant Storage). A data recovery cluster is spun up if there is a disaster recovery scenario. At that time, DDLs, configuration, policies, and processes are applied. Data is ingested from storage with the ingestion property kustoCreationTime to over-ride the ingestion time that defaults to system time.", - "guid": "49aa8092-dc8e-4b9d-8bb7-3b26a5a67eba", - "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#on-demand-data-recovery-configuration", - "service": "Azure Data Explorer", + "guid": "b49e5b96-0332-44ec-b8cc-13318da61170", + "link": "https://learn.microsoft.com/purview/concept-policies-devops", + "service": "Purview", "services": [ - "Cost", - "Storage", - "ASR", "AzurePolicy", "WAF" ], - "text": "For applications, where cost is a concern and can withstand some downtime during failure, create on-demand data recovery cluster configuration", + "severity": "Low", + "text": "Follow DevOps policies", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Compute/virtualMachineScaleSets", "checklist": "WAF checklist", - "description": "All database objects, policies, and configurations should be persisted in source control so they can be released to the cluster from your release automation tool.", - "guid": "5a907e1e-348e-4f25-9c27-d32e8bbac757", - "link": "https://learn.microsoft.com/azure/data-explorer/devops", - "service": "Azure Data Explorer", + "description": "Automatic instance repairs ensure that unhealthy instances are promptly identified and replaced, maintaining a set of healthy instances within your scale set.", + "guid": "7e13c105-675c-41e9-95b4-59837ff7ae7c", + "link": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-automatic-instance-repairs", + "service": "VMSS", "services": [ - "AzurePolicy", + "VM", "WAF" ], - "text": "Wrap DevOps and source control around all your code", - "training": "https://learn.microsoft.com/learn/paths/secure-your-cloud-data/", + "severity": "Low", + "text": "Enable automatic instance repairs for enhanced VM Scale Sets resiliency", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "1559ab91-53e8-4908-ae28-b84c33b6b780", - "link": "https://learn.microsoft.com/azure/data-explorer/devops", - "service": "Azure Data Explorer", + "description": "Ensure that Azure Backup is utilized appropriately to meet your organization's resiliency requirements for Azure virtual machines (VMs).", + "guid": "4d874a74-8b66-42d6-b150-512a66498f6d", + "link": "https://learn.microsoft.com/azure/backup/backup-azure-vms-introduction", + "service": "VM", "services": [ + "VM", + "Backup", "WAF" ], - "text": "Design, develop, and implement validation routines to ensure all clusters are in-sync from a data perspective.", - "training": "https://learn.microsoft.com/learn/modules/azure-active-directory/", + "severity": "High", + "text": "Consider Azure Backup to meet your resiliency requirements for Azure VMs", "waf": "Reliability" }, { - "arm-service": "Microsoft.Kusto/clusters", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "8b9fe5c4-1049-4d40-9a82-2c3474d00f18", - "link": "https://learn.microsoft.com/azure/data-explorer/devops", - "service": "Azure Data Explorer", + "description": "Single Instance VMs using Premium SSD or Ultra Disk for all Operating System Disks and Data Disks are guaranteed to have Virtual Machine Connectivity of at least 99.9%", + "guid": "8052d88e-79d1-47b7-9b22-a5a67e7a8ed4", + "link": "https://learn.microsoft.com/azure/virtual-machines/disks-types", + "service": "VM", "services": [ + "VM", "WAF" ], - "text": "Be fully cognizant of what it takes to build a cluster from scratch. Leverage Infrastructure as a Code for your deployments", - "training": "https://learn.microsoft.com/learn/modules/implement-hybrid-identity-windows-server/", + "severity": "High", + "text": "Use Premium or Ultra disks for production VMs", "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "cdnresources | where type =~ 'microsoft.Cdn/profiles/secrets' | extend frontDoorId = substring(id, 0, indexof(id, '/secrets')) | where properties.parameters.type =~ 'CustomerCertificate' | extend compliant = properties.parameters.useLatestVersion == true | project compliant, id=frontDoorId, certificateName = name | distinct id, certificateName, compliant", - "guid": "f00a69de-7076-4734-a734-6e4552cad9e1", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-latest-version-for-customer-managed-certificates", - "service": "Front Door", + "description": "Azure automatically replicates managed disks within a region to ensure data durability and protect against single-point failures.", + "guid": "b31e38c3-f298-412b-8363-cffe179b599d", + "link": "https://learn.microsoft.com/azure/virtual-machines/managed-disks-overview", + "service": "VM", "services": [ - "AKV", - "WAF", - "FrontDoor" + "VM", + "WAF" ], - "severity": "Medium", - "text": "If you use customer-managed TLS certificates with Azure Front Door, use the 'Latest' certificate version. Reduce the risk of outages caused by manual certificate renewal.", - "waf": "Operations" + "severity": "High", + "text": "Ensure Managed Disks are used for all VMs", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'microsoft.cdn/profiles' and sku has 'AzureFrontDoor' | project name, cdnprofileid=tolower(id), tostring(tags), resourceGroup, subscriptionId,skuname=tostring(sku.name) | join kind= fullouter ( cdnresources | where type == 'microsoft.cdn/profiles/securitypolicies' | extend wafpolicyid=tostring(properties['parameters']['wafPolicy']['id']) | extend splitid=split(id, '/') | extend cdnprofileid=tolower(strcat_array(array_slice(splitid, 0, 8), '/')) | project secpolname=name, cdnprofileid, wafpolicyid ) on cdnprofileid | project name, cdnprofileid, secpolname, wafpolicyid,skuname | join kind = fullouter ( resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | extend managedrulesenabled=iff(tostring(properties.managedRules.managedRuleSets) != '[]', true, false), enabledState = tostring(properties.policySettings.enabledState) | project afdwafname=name, managedrulesenabled, wafpolicyid=id, enabledState, tostring(tags) ) on wafpolicyid | where name != '' | summarize associatedsecuritypolicies=countif(secpolname != ''), wafswithmanagedrules=countif(managedrulesenabled == 1) by name, id=cdnprofileid, tags,skuname | extend compliant = (associatedsecuritypolicies > 0 and wafswithmanagedrules > 0) | project id, compliant", - "guid": "e79d17b7-3b22-4a5a-97e7-a8ed4b30e38c", - "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", - "service": "Front Door", + "description": "Temporary disks are intended for short-term storage of non-persistent data such as page files, swap files, or SQL Server tempdb. Storing persistent data on temporary disks can lead to data loss during maintenance events or VM redeployment.", + "guid": "e0d5973c-d4ce-432c-8881-37f6f7c4c0d4", + "link": "https://learn.microsoft.com/azure/virtual-machines/managed-disks-overview#temporary-disk", + "service": "VM", "services": [ - "AzurePolicy", - "WAF", - "FrontDoor" + "Storage", + "VM", + "SQL", + "WAF" ], "severity": "Medium", - "text": "Use Azure Front Door with WAF policies to deliver and help protect global HTTP/S apps that span multiple Azure regions.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Security" + "text": "Do not use the Temp disk for anything that is not acceptable to be lost", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "3f29812b-2363-4cef-b179-b599de0d5973", - "link": "https://learn.microsoft.com/azure/frontdoor/origin-security?tabs=application-gateway&pivots=front-door-standard-premium#example-configuration", - "service": "Front Door", + "description": "Co-locate your compute, storage, networking, and data resources across an availability zone, and replicate this arrangement in other availability zones.", + "guid": "e514548d-2447-4ec6-9138-b8200f1ce16e", + "link": "https://learn.microsoft.com/azure/reliability/availability-zones-overview", + "service": "VM", "services": [ - "AppGW", - "AzurePolicy", - "WAF", - "FrontDoor" + "ACR", + "Storage", + "VM", + "WAF" ], "severity": "Medium", - "text": "When using Front Door and Application Gateway to help protect HTTP/S apps, use WAF policies in Front Door. Lock down Application Gateway to receive traffic only from Front Door.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Security" + "text": "Leverage Availability Zones for your VMs in regions where they are supported", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode", - "guid": "ae248989-b306-4591-9186-de482e3f0f0e", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings", - "service": "Front Door", + "description": "Use at least two VMs in Availability Sets to isolate VMs on different fault and update domains.", + "guid": "5a785d6f-e96c-496a-b884-4cf3b2b38c88", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "service": "VM", "services": [ - "AzurePolicy", - "WAF", - "FrontDoor" + "VM", + "WAF" ], - "severity": "High", - "text": "Deploy your WAF policy for Front Door in 'Prevention' mode' so that Web Application Firewall takes appropriate action to allow or deny traffic.", - "waf": "Security" + "severity": "Medium", + "text": "For regions that do not support Availability Zones deploy VMs into Availability Sets", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/origins' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups')) | extend compliant = properties['hostName'] !endswith '.trafficmanager.net' | project compliant, id=frontDoorId", - "guid": "062d5839-4d36-402f-bfa4-02811eb936e9", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#avoid-combining-traffic-manager-and-front-door", - "service": "Front Door", + "description": "Azure provides multiple options for VM redundancy to meet different requirements (Availability Zones, Virtual Machine Scale Sets, Availability Sets, Azure Site Recovery)", + "guid": "6ba2c021-4991-414a-9d3c-e574dccbd979", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "service": "VM", "services": [ - "EventHubs", - "TrafficManager", - "WAF", - "FrontDoor" + "VM", + "ASR", + "WAF" ], "severity": "High", - "text": "Avoid placing Traffic Manager behind Front Door.", - "waf": "Security" + "text": "Avoid running a production workload on a single VM", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/origins' | extend frontDoorId = substring(id, 0, indexof(id, '/origins')) | extend compliant = isempty(properties.originHostHeader) or (tostring(properties.hostName) =~ tostring(properties.originHostHeader)) | project id=frontDoorId, originName = name, compliant", - "guid": "5efeb96a-003f-4b18-8fcd-b4d84459c2b2", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-the-same-domain-name-on-front-door-and-your-origin", - "service": "Front Door", + "description": "Azure Site Recovery enables you to achieve low RTO (Recovery Time Objective) for your Azure and hybrid VMs by providing continuous replication and failover capabilities.", + "guid": "2a6bcca2-b5fe-4a1e-af3d-d95d48c7c891", + "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", + "service": "VM", "services": [ - "WAF", - "FrontDoor" + "VM", + "ASR", + "AVS", + "WAF" ], "severity": "High", - "text": "Use the same domain name on Azure Front Door and your origin. Mismatched host names can cause subtle bugs.", - "waf": "Security" + "text": "For Azure and on-premises VMs (Hyper-V/Phyiscal/VMware) with low RTO requirements use Azure Site Recovery", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/origins' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups')) | extend originGroupId = substring(id, 0, indexof(id, '/origins')) | join kind=inner (cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups' | extend originGroupName = name | extend hasHealthProbe = isnotnull(properties.healthProbeSettings)) on $left.originGroupId == $right.id | summarize numberOrigins = count() by originGroupId, subscriptionId, frontDoorId, hasHealthProbe, originGroupName | extend compliant = not(numberOrigins == 1 and hasHealthProbe) | project id = frontDoorId, compliant", - "guid": "0b5a380c-4bfb-47bc-b1d7-dcfef363a61b", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group", - "service": "Front Door", + "description": "By using Capacity Reservations, you can effectively manage capacity for critical workloads, ensuring resource availability in specified regions.", + "guid": "bd7bb012-f7b9-45e0-9e15-8e3ea3992c2d", + "link": "https://learn.microsoft.com/azure/virtual-machines/capacity-reservation-overview", + "service": "VM", "services": [ - "WAF", - "FrontDoor" + "WAF" ], "severity": "Low", - "text": "Disable health probes when there is only one origin in an Azure Front Door origin group.", - "waf": "Performance" + "text": "Use Capacity Reservations for critical workloads that require guaranteed capacity", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "5567048e-e5d7-4206-9c55-b5ed45d2cc0c", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#select-good-health-probe-endpoints", - "service": "Front Door", + "description": "By ensuring that the necessary quotas are increased in your DR region before testing failover with ASR, you can avoid any potential resource constraints during the recovery process for failed over VMs.", + "guid": "e6e2065b-3a76-4af4-a691-e8939ada4666", + "link": "https://learn.microsoft.com/azure/quotas/per-vm-quota-requests", + "service": "VM", "services": [ - "WAF", - "FrontDoor" + "VM", + "ASR", + "WAF" ], "severity": "Medium", - "text": "Select good health probe endpoints for Azure Front Door. Consider building health endpoints that check all of your application's dependencies.", + "text": "Increase quotas in DR region before testing failover with ASR", "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups/')) | extend compliant = (isnull(properties['healthProbeSettings']['probeRequestType']) or toupper(properties['healthProbeSettings']['probeRequestType']) == 'HEAD') | project compliant, id=frontDoorId", - "guid": "a13f72f3-8f5c-4864-95e5-75bf37fbbeb1", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes", - "service": "Front Door", + "description": "Scheduled Events is an Azure Metadata Service that provides information about upcoming maintenance events for virtual machines (VMs). By leveraging Scheduled Events, you can proactively prepare your applications for VM maintenance, minimizing disruption and improving the availability of your VMs.", + "guid": "6d3b475a-5c7a-4cbe-99bb-e64dd8902e87", + "link": "https://learn.microsoft.com/azure/virtual-machines/windows/scheduled-events", + "service": "VM", "services": [ - "WAF", - "FrontDoor" + "VM", + "WAF" ], "severity": "Low", - "text": "Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application.", - "waf": "Performance" + "text": "Utilize Scheduled Events to prepare for VM maintenance", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/customdomains' | extend frontDoorId = substring(id, 0, indexof(id, '/customdomains')) | extend compliant = (isnull(properties['tlsSettings']['certificateType']) or tolower(properties['tlsSettings']['certificateType']) =~ 'customercertificate') | project compliant, id = frontDoorId", - "guid": "af95c92d-d723-4f4a-98d7-8722324efd4d", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates", - "service": "Front Door", + "description": "Use Zone-redundant Storage (ZRS) in the primary region for scenarios that require high availability and for restricting replication to a particular country or region. For protection against regional disasters, use Geo-zone-redundant Storage (GZRS), which combines ZRS in the primary region with geo-replication to a secondary region?.", + "guid": "48c7c891-dcb1-4f7d-9769-ae568ba38d4a", + "link": "https://learn.microsoft.com/azure/storage/common/storage-redundancy", + "service": "Azure Storage", "services": [ - "AKV", - "FrontDoor", - "WAF", - "Cost" + "Storage", + "WAF" ], - "severity": "High", - "text": "Use managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals.", - "waf": "Operations" + "severity": "Medium", + "text": "Choose the most appropriate data redundancy option for Azure Storage based on your requirements", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "189ea962-3969-4863-8f5a-5ad808c2cf4b", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#define-your-waf-configuration-as-code", - "service": "Front Door", + "description": "Assigning a Delete lock to your storage account helps protect the availability of your data, minimizing the risk of disruptions to your business operations.", + "guid": "85e2213d-bd7b-4b01-8f7b-95e06e158e3e", + "link": "https://learn.microsoft.com/azure/storage/common/lock-account-resource", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Storage", + "WAF" ], - "severity": "Medium", - "text": "Define your Azure Front Door WAF configuration as code. By using code, you can more easily adopt new rule set version and gain additional protection.", - "waf": "Operations" + "severity": "Low", + "text": "Apply a Delete lock to prevent accidental or malicious deletion of storage accounts", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "cdnresources | where type == 'microsoft.cdn/profiles/afdendpoints/routes' | extend frontDoorId = substring(id, 0, indexof(id, '/afdendpoints')) | extend forwardingProtocol=tostring(properties.forwardingProtocol),supportedProtocols=properties.supportedProtocols,httpsRedirect=properties.httpsRedirect | extend compliant = forwardingProtocol =~ 'httpsonly' and (supportedProtocols has 'https' or httpsRedirect =~ 'enabled') | project id = frontDoorId, compliant", - "guid": "2e30abab-5478-417c-81bf-bf1ad4ed1ed4", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-end-to-end-tls", - "service": "Front Door", + "description": "Container soft delete protects your data from being accidentally deleted by maintaining the deleted data in the system for a specified period of time.", + "guid": "a3992c2d-e6e2-4065-a3a7-6af4a691e893", + "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-container-enable", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Storage", + "WAF" ], - "severity": "High", - "text": "Use end-to-end TLS with Azure Front Door. Use TLS for connections from your clients to Front Door, and from Front Door to your origin.", - "waf": "Security" + "severity": "Low", + "text": "Enable soft delete for Storage Account Containers", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "cdnresources | where type == 'microsoft.cdn/profiles/afdendpoints/routes' | extend frontDoorId = substring(id, 0, indexof(id, '/afdendpoints')) | extend forwardingProtocol=tostring(properties.forwardingProtocol),supportedProtocols=properties.supportedProtocols,httpsRedirect=properties.httpsRedirect | extend compliant = httpsRedirect =~ 'enabled' | project id = frontDoorId, compliant", - "guid": "10aa45af-166f-44c4-9f36-b6d592dac2ca", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-http-to-https-redirection", - "service": "Front Door", - "services": [ - "WAF", - "FrontDoor" - ], - "severity": "Medium", - "text": "Use HTTP to HTTPS redirection with Azure Front Door. Support older clients by redirecting them to an HTTPS request automatically.", - "waf": "Security" - }, - { - "arm-service": "microsoft.network/frontdoors", - "checklist": "WAF checklist", - "graph": "resources | where type =~ 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=~'Enabled') and (mode=~'Prevention')), enabledState, mode", - "guid": "28b9ee82-b2c7-45aa-bc98-6de6f59a095d", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#enable-the-waf", - "service": "Front Door", + "description": "Blob soft delete protects an individual blob and its versions, snapshots, and metadata from accidental deletes or overwrites by maintaining the deleted data in the system for a specified period of time.", + "guid": "9ada4666-7e13-4c10-96b9-153d89f89dc7", + "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-enable", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Storage", + "WAF" ], - "severity": "High", - "text": "Enable the Azure Front Door WAF. Protect your application from a range of attacks.", - "waf": "Security" + "severity": "Low", + "text": "Enable soft delete for blobs", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "2902d8cc-1b0c-4495-afad-624ab70f7bd6", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#tune-your-waf", - "service": "Front Door", + "description": "Azure Backup enhanced soft delete provides critical protection against ransomware attacks by retaining deleted backups, enabling recovery from potential ransomware encryption or deletion.", + "guid": "b44be3b1-a27f-48b9-b91b-e1038df03a82", + "link": "https://learn.microsoft.com/azure/backup/backup-azure-enhanced-soft-delete-about", + "service": "Azure Backup", "services": [ - "WAF", - "FrontDoor" + "Backup", + "WAF" ], - "severity": "High", - "text": "Tune the Azure Front Door WAF for your workload by configuring the WAF in Detection mode to reduce and fix false positive detections.", - "waf": "Security" + "severity": "Medium", + "text": "Enable Azure Backup enhanced soft delete for improved data protection and recovery", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "17ba124b-127d-42b6-9322-388d5b2bbcfc", - "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection", - "service": "Front Door", + "description": "Azure Backup's multi-user authorization enables fine-grained control over user access to backup resources, allowing you to restrict privileges and ensure proper authentication and authorization for backup operations.", + "guid": "2cd463cb-bbc8-4ac2-a9eb-c92a43da1dae", + "link": "https://learn.microsoft.com/azure/backup/multi-user-authorization-concept", + "service": "Azure Backup", "services": [ - "AzurePolicy", - "WAF", - "FrontDoor" + "Backup", + "WAF" ], - "severity": "High", - "text": "Enable request body inspection feature enabled in Azure Front Door WAF policy.", - "waf": "Security" + "severity": "Low", + "text": "Implement multi-user authorization for Azure Backup to ensure secure and controlled access to backup resources", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "49a98f2b-ec22-4a87-9415-6a10b00d6555", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#enable-default-rule-sets", - "service": "Front Door", + "description": "Azure Immutable Storage provides an additional layer of security by ensuring that backup data stored in the vault cannot be modified or deleted for a specified retention period. This helps safeguard your backups from ransomware attacks that may attempt to compromise or manipulate your backup data.", + "guid": "2cc88147-0607-4c1c-aa0e-614658dd458e", + "link": "https://learn.microsoft.com/azure/backup/backup-azure-immutable-vault-concept?source=recommendations&tabs=recovery-services-vault", + "service": "Azure Backup", "services": [ - "WAF", - "FrontDoor" + "Storage", + "Backup", + "WAF" ], - "severity": "High", - "text": "Enable the Azure Front Door WAF default rule sets. The default rule sets detect and block common attacks.", - "waf": "Security" + "severity": "Low", + "text": "Implement Immutable Storage for your vaults to protect against ransomware and prevent unauthorized modifications to backups", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "147a13d4-2a2f-4824-a524-f5855b52b946", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#enable-bot-management-rules", - "service": "Front Door", + "description": "To eliminate a single point of failure in your on-premises DNS services and ensure reliable DNS resolution during business continuity and disaster recovery scenarios, it is recommended to utilize Azure DNS Private Resolvers in multiple regions. By deploying two or more Azure DNS private resolvers across different regions, you can enable DNS failover and achieve resiliency in your DNS infrastructure.", + "guid": "43da1dae-2cc8-4814-9060-7c1cca0e6146", + "link": "https://learn.microsoft.com/azure/dns/tutorial-dns-private-resolver-failover", + "service": "DNS", "services": [ - "WAF", - "FrontDoor" + "ACR", + "ASR", + "DNS", + "WAF" ], - "severity": "High", - "text": "Enable the Azure Front Door WAF bot protection rule set. The bot rules detect good and bad bots.", - "waf": "Security" + "severity": "Low", + "text": "Implement DNS Failover using Azure DNS Private Resolvers", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.PowerBI/gateways", "checklist": "WAF checklist", - "guid": "d7dcdcb9-0d99-44b9-baab-ac7570ede79a", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#use-the-latest-ruleset-versions", - "service": "Front Door", + "description": "Use an on-premises data gateway cluster to avoid single points of failure and to load balance traffic across gateways.", + "guid": "89f89dc7-b44b-4e3b-8a27-f8b9e91be103", + "link": "https://learn.microsoft.com/data-integration/gateway/service-gateway-high-availability-clusters", + "service": "Data Gateways", "services": [ - "WAF", - "FrontDoor" + "ACR", + "WAF" ], "severity": "Medium", - "text": "Use the latest Azure Front Door WAF rule set version. Rule set updates are regularly updated to take account of the current threat landscape.", - "waf": "Security" + "text": "Use on-premises data gateway clusters to ensure high availability for business-critical data", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "b9620385-1cde-418f-914b-a84a06982ffc", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-rate-limiting", - "service": "Front Door", + "description": "When choosing the best option for deploying NVAs in Azure, it is crucial to consider the vendor's recommendations and validate that the specific design has been vetted and validated by the NVA vendor. The vendor should also provide the necessary NVA configuration for seamless integration in Azure.", + "guid": "8b1188b3-c6a4-46ce-a544-451e192d3442", + "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/nva-ha", + "service": "NVA", "services": [ - "WAF", - "FrontDoor" + "NVA", + "WAF" ], - "severity": "Medium", - "text": "Add rate limiting to the Azure Front Door WAF. Rate limiting blocks clients accidentally or intentionally sending large amounts of traffic in a short period of time.", - "waf": "Security" + "severity": "High", + "text": "Deploy Network Virtual Appliances (NVAs) in a vendor supported configuration for High Availability", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "6dc36c52-0124-4ffe-9eaf-23ec1282dedb", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#use-a-high-threshold-for-rate-limits", - "service": "Front Door", + "description": "Apply guidance from the Microsoft cloud security benchmark related to Storage", + "guid": "d237de14-3b16-4c21-b7aa-9b64604489a8", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/storage-security-baseline", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Storage", + "WAF" ], "severity": "Medium", - "text": "Use a high threshold for Azure Front Door WAF rate limits. High rate limit thresholds avoid blocking legitimate traffic, while still providing protection against extremely high numbers of requests that might overwhelm your infrastructure.", + "text": "Consider the 'Azure security baseline for storage'", "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "388a3d0e-0a43-4367-90b2-3dd2aeece5ee", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#geo-filter-traffic", - "service": "Front Door", + "description": "Azure Storage by default has a public IP address and is Internet-reachable. Private endpoints allow to securely expose Azure Storage only to those Azure Compute resources that need access, thus eliminating exposure to the public Internet", + "graph": "resources | where type =~ 'Microsoft.Storage/StorageAccounts' | where isnull(properties.privateEndpointConnections) or properties.privateEndpointConnections[0].properties.provisioningState != ('Succeeded') or (isnull(properties.networkAcls) and properties.publicNetworkAccess == 'Enabled') | extend compliant = (isnotnull(properties.privateEndpointConnections) and properties.privateEndpointConnections[0].properties.provisioningState == 'Succeeded' and properties.publicNetworkAccess == 'Disabled') | distinct id, compliant", + "guid": "f42d78e7-9d17-4a73-a22a-5a67e7a8ed4b", + "link": "https://learn.microsoft.com/azure/storage/common/storage-private-endpoints", + "service": "Azure Storage", "services": [ + "Storage", + "PrivateLink", "WAF" ], - "severity": "Low", - "text": "If you are not expecting traffic from all geographical regions, use geo-filters to block traffic from non-expected countries.", + "severity": "High", + "text": "Consider using private endpoints for Azure Storage", "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "00acd8a9-6975-414f-8491-2be6309893b8", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#specify-the-unknown-zz-location", - "service": "Front Door", + "description": "Newly created storage accounts are created using the ARM deployment model, so that RBAC, auditing etc. are all enabled. Ensure that there are no old storage accounts with classic deployment model in a subscription", + "guid": "30e37c3e-2971-41b2-963c-eee079b598de", + "link": "https://learn.microsoft.com/azure/virtual-machines/migration-classic-resource-manager-overview#migration-of-storage-accounts", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Subscriptions", + "Storage", + "RBAC", + "WAF" ], "severity": "Medium", - "text": "Specify the unknown (ZZ) location when geo-filtering traffic with the Azure Front Door WAF. Avoid accidentally blocking legitimate requests when IP addresses can't be geo-matched.", + "text": "Ensure older storage accounts are not using 'classic deployment model'", "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "4cea4050-7946-4a7c-89e6-b021b73c352d", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-diagnostic-settings-to-save-your-wafs-logs", - "service": "Front Door", + "description": "Leverage Microsoft Defender to learn about suspicious activity and misconfigurations.", + "graph": "resources | where type =~ 'Microsoft.Storage/StorageAccounts' | project storageAccountId = id | join kind=leftouter (resourceContainers | where type == 'microsoft.security/pricings' | where name == 'StorageAccounts' | project resourceId = id, pricingTier = properties.pricingTier) on $left.storageAccountId == $right.resourceId | where isnull(pricingTier) or pricingTier != 'Standard' | extend compliant = false | distinct storageAccountId, compliant", + "guid": "fc5972cd-4cd2-41b0-a803-7f5e6b4bfd3d", + "link": "https://learn.microsoft.com/azure/storage/common/azure-defender-storage-configure", + "service": "Azure Storage", "services": [ - "WAF", - "Monitor" + "Storage", + "Defender", + "WAF" ], - "severity": "Medium", - "text": "Capture logs and metrics by turning on Diagnostic Settings. Include resource activity logs, access logs, health probe logs, and WAF logs. Set up alerts.", - "waf": "Operations" + "severity": "High", + "text": "Enable Microsoft Defender for all of your storage accounts", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "845f5f91-9c21-4674-a725-5ce890850e20", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", - "service": "Front Door", + "description": "The soft-delete mechanism allows to recover accidentally deleted blobs.", + "guid": "503547c1-447e-4c66-828a-7100f1ce16dd", + "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-overview", + "service": "Azure Storage", "services": [ - "Sentinel", - "WAF", - "FrontDoor" + "Storage", + "WAF" ], "severity": "Medium", - "text": "Send Azure Front Door WAF logs to Microsoft Sentinel.", - "waf": "Operations" + "text": "Enable 'soft delete' for blobs", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "3bb0a854-ea3d-4212-bd8e-3f0cb7792b02", - "link": "https://learn.microsoft.com/azure/frontdoor/routing-methods", - "service": "Front Door", + "description": "Consider selectively disabling 'soft delete' for certain blob containers, for example if the application must ensure that deleted information is immediately deleted, e.g. for confidentiality, privacy or compliance reasons. ", + "guid": "3f1d5e87-2e52-4e36-81cc-58b4a4b1510e", + "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-enable", + "service": "Azure Storage", "services": [ - "WAF", - "Backup" + "Storage", + "WAF" ], "severity": "Medium", - "text": "Choose a routing method that supports your deployment strategy. The weighted method, which distributes traffic based on the configured weight coefficient, supports active-active models. A priority-based value that configures the primary region to receive all traffic and send traffic to the secondary region as a backup supports active-passive models. Combine the preceding methods with latency so that the origin with the lowest latency receives traffic.", - "waf": "Reliability" + "text": "Disable 'soft delete' for blobs", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups')) | extend healthprobe=tostring(properties.healthProbeSettings) | project origingroupname=name, id, tags, resourceGroup, subscriptionId, healthprobe, frontDoorId | join ( cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/Origins' | extend origingroupname = tostring(properties.originGroupName) ) on origingroupname | summarize origincount=count(), enabledhealthprobecount=countif(healthprobe != '') by origingroupname, id, tostring(tags), resourceGroup, subscriptionId, frontDoorId | extend compliant = origincount > 1 | project id = frontDoorId, compliant", - "guid": "c3a769e4-cc78-40a9-b36a-f9bcab19ec2d", - "link": "https://learn.microsoft.com/azure/frontdoor/quickstart-create-front-door", - "service": "Front Door", + "description": "Soft delete for containers enables you to recover a container after it has been deleted, for example recover from an accidental delete operation.", + "guid": "43a58a9c-2289-4c3d-9b57-d0c655462f2a", + "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-container-overview", + "service": "Azure Storage", "services": [ "WAF" ], "severity": "High", - "text": "Support redundancy by having multiple origins in one or more back-end pools. Always have redundant instances of your application and make sure each instance exposes an endpoint or origin. You can place those origins in one or more back-end pools.", - "waf": "Reliability" + "text": "Enable 'soft delete' for containers", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "999852be-2137-4179-8fc3-30d1df6fed1d", - "link": "https://learn.microsoft.com/azure/frontdoor/troubleshoot-issues#troubleshooting-steps", - "service": "Front Door", + "description": "Consider selectively disabling 'soft delete' for certain blob containers, for example if the application must ensure that deleted information is immediately deleted, e.g. for confidentiality, privacy or compliance reasons. ", + "guid": "3e3453a3-c863-4964-ab65-2d6c15f51296", + "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-container-enable", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Storage", + "WAF" ], "severity": "Medium", - "text": "Set a timeout on forwarding requests to the back end. Adjust the timeout setting according to your endpoints' needs. If you don't, Azure Front Door might close the connection before the origin sends the response. You can also lower the default timeout for Azure Front Door if all of your origins have a shorter timeout.", - "waf": "Reliability" + "text": "Disable 'soft delete' for containers", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "17bf6351-3e5e-41f1-87bb-d5ad0b4e3de6", - "link": "https://learn.microsoft.com/azure/frontdoor/routing-methods#23session-affinity", - "service": "Front Door", + "description": "Prevents accidental deletion of a storage account, by forcing the user to first remove the deletion lock, prior to deletion", + "guid": "5398e6de-d227-4dd1-92b0-6c21d7999a64", + "link": "https://learn.microsoft.com/azure/storage/common/lock-account-resource", + "service": "Azure Storage", "services": [ + "Storage", "WAF" ], - "severity": "Medium", - "text": "Decide if your application requires session affinity. If you have high reliability requirements, we recommend that you disable session affinity.", - "waf": "Reliability" + "severity": "High", + "text": "Enable resource locks on storage accounts", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "425bfb31-94c4-4007-b9ae-46da9fe57cc7", - "link": "https://learn.microsoft.com/azure/frontdoor/origin?pivots=front-door-standard-premium#origin-host-header", - "service": "Front Door", + "description": "Consider 'legal hold' or 'time-based retention' policies for blobs, so that is is impossible to delete the blob, the container, or the storage account. Please note that 'impossible' actually means 'impossible'; once a storage account contains an immutable blob, the only way to 'get rid' of that storage account is by cancelling the Azure subscription.", + "guid": "6f4389a8-f42c-478e-98c0-6a73a22a4956", + "link": "https://learn.microsoft.com/azure/storage/blobs/immutable-storage-overview", + "service": "Azure Storage", "services": [ + "Storage", + "Subscriptions", + "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "Send the host header to the back end. The back-end services should be aware of the host name so that they can create rules to accept traffic only from that host.", + "severity": "High", + "text": "Consider immutable blobs", "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "81a5398a-2414-450f-9fc3-e048bc65784c", - "link": "https://learn.microsoft.com/azure/frontdoor/front-door-caching", - "service": "Front Door", + "description": "Consider disabling unprotected HTTP/80 access to the storage account, so that all data transfers are encrypted, integrity protected, and the server is authenticated. ", + "graph": "resources | where type =~ 'Microsoft.Storage/StorageAccounts' | extend compliant = (properties.supportsHttpsTrafficOnly == false) | distinct id, compliant", + "guid": "e7a8dc4a-20e2-47c3-b297-11b1352beee0", + "link": "https://learn.microsoft.com/azure/storage/common/storage-require-secure-transfer", + "service": "Azure Storage", "services": [ + "Storage", "WAF" ], - "severity": "Medium", - "text": "Use caching for endpoints that support it.", - "waf": "Cost" + "severity": "High", + "text": "Require HTTPS, i.e. disable port 80 on the storage account", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups')) | extend healthprobe=tostring(properties.healthProbeSettings) | project origingroupname=name, id, tags, resourceGroup, subscriptionId, healthprobe, frontDoorId | join ( cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/Origins' | extend origingroupname = tostring(properties.originGroupName) ) on origingroupname | summarize origincount=count(), enabledhealthprobecount=countif(healthprobe != '') by origingroupname, id, tostring(tags), resourceGroup, subscriptionId, frontDoorId | extend compliant = origincount > 1 or (origincount == 1 and enabledhealthprobecount == 0) | project id = frontDoorId, compliant", - "guid": "34069d73-e4de-46c5-a36f-625f87575a56", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group", - "service": "Front Door", + "description": "When configuring a custom domain (hostname) on a storage account, check whether you need TLS/HTTPS; if so, you might have to put Azure CDN in front of your storage account.", + "guid": "79b588de-fc49-472c-b3cd-21bf77036e5e", + "link": "https://learn.microsoft.com/azure/storage/blobs/storage-custom-domain-name", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Storage", + "WAF" ], - "severity": "Low", - "text": "Disable health checks in single back-end pools. If you have only one origin configured in your Azure Front Door origin group, these calls are unnecessary. This is only recommended if you can't have multiple origins in your endpoint.", - "waf": "Cost" + "severity": "High", + "text": "When enforcing HTTPS (disabling HTTP), check that you do not use custom domains (CNAME) for the storage account.", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "c92d6786-cdd1-444d-9cad-934a192a276a", - "link": "https://learn.microsoft.com/azure/frontdoor/standard-premium/how-to-reports", - "service": "Front Door", + "description": "Requiring HTTPS when a client uses a SAS token to access blob data helps to minimize the risk of credential loss.", + "guid": "6b4bed3d-5035-447c-8347-dc56028a71ff", + "link": "https://learn.microsoft.com/azure/storage/common/storage-sas-overview", + "service": "Azure Storage", "services": [ "Storage", - "WAF", - "FrontDoor" + "WAF" ], "severity": "Medium", - "text": "We recommend using the Premium Tier for leveraging the Security reports while the Standard Azure Front Door Profile provides only traffic reports under built-in analytics/reports.", - "waf": "Operations" + "text": "Limit shared access signature (SAS) tokens to HTTPS connections only", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "440cf7de-30a1-4550-ab50-c9f6eac140cd", - "link": "https://learn.microsoft.com/azure/frontdoor/front-door-wildcard-domain", - "service": "Front Door", + "description": ". Enforcing the latest TLS version will reject request from clients using the older version. ", + "graph": "resources | where type == 'microsoft.storage/storageaccounts' | extend compliant = (isnull(properties.minimumTlsVersion) == false and properties.minimumTlsVersion in ('TLS1_2', 'TLS1_3')) | distinct id, compliant", + "guid": "e12be569-a18f-4562-8d5d-ce151b9e7d55", + "link": "https://learn.microsoft.com/azure/storage/common/transport-layer-security-configure-minimum-version", + "service": "Azure Storage", "services": [ - "AKV", + "Storage", "WAF" ], - "severity": "Medium", - "text": "Use wildcard TLS certificates when possible.", - "waf": "Operations" + "severity": "High", + "text": "Enforce the latest TLS version for a storage account", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "556e2733-6ca9-4edd-9cc7-26de66d46c2e", - "link": "https://learn.microsoft.com/azure/frontdoor/front-door-caching", - "service": "Front Door", + "description": "Microsoft Entra ID tokens should be favored over shared access signatures, wherever possible", + "guid": "e1ce15dd-3f0d-45e7-92d4-1e3611cc57b4", + "link": "https://learn.microsoft.com/azure/storage/common/authorize-data-access", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Storage", + "Entra", + "WAF" ], - "severity": "Medium", - "text": "Optimize your application query string for caching. For purely static content, ignore query strings to maximize your use of the cache. If your application uses query strings, consider including them in the cache key. Including the query strings in the cache key allows Azure Front Door to serve cached responses or other responses, based on your configuration.", - "waf": "Performance" + "severity": "High", + "text": "Use Microsoft Entra ID tokens for blob access", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "c0b7e55e-fcab-4e66-bdae-bd0290f6aece", - "link": "https://learn.microsoft.com/azure/frontdoor/standard-premium/how-to-compression", - "service": "Front Door", + "description": "When assigning a role to a user, group, or application, grant that security principal only those permissions that are necessary for them to perform their tasks. Limiting access to resources helps prevent both unintentional and malicious misuse of your data.", + "guid": "a4b1410d-4395-48a8-a228-9b3d6b57cfc6", + "service": "Azure Storage", "services": [ - "Storage", + "RBAC", "WAF" ], "severity": "Medium", - "text": "Use file compression when you're accessing downloadable content.", - "waf": "Performance" + "text": "Least privilege in IaM permissions", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'microsoft.network/frontdoors' and properties['resourceState'] !~ 'migrated' | extend compliant = false | project id, compliant", - "guid": "cb8eb8c0-aa73-4a26-a495-6eba8dc4a243", - "link": "https://learn.microsoft.com/azure/cdn/tier-migration", - "service": "Front Door", + "description": "A user delegation SAS is secured with Azure Active Directory (Azure AD) credentials and also by the permissions specified for the SAS. A user delegation SAS is analogous to a service SAS in terms of its scope and function, but offers security benefits over the service SAS. ", + "guid": "55461e1a-3e34-453a-9c86-39648b652d6c", + "link": "https://learn.microsoft.com/azure/storage/common/storage-sas-overview?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json#best-practices-when-using-sas", + "service": "Azure Storage", "services": [ - "WAF", - "FrontDoor" + "Storage", + "Entra", + "WAF" ], "severity": "High", - "text": "Consider migrating to Standard or Premium SKU if you are using Classic Azure Front Door currently as Classic Azure Front Door will be deprecated by March 2027.", - "waf": "Operations" + "text": "When using SAS, prefer 'user delegation SAS' over storage-account-key based SAS.", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "67c33697-15b1-4752-aeee-0b9b588defc4", - "link": "https://learn.microsoft.com/azure/architecture/guide/networking/global-web-applications/mission-critical-content-delivery", - "service": "Front Door", + "description": "Storage account keys ('shared keys') have very little audit capabilities. While it can be monitored on who/when fetched a copy of the keys, once the keys are in the hands of multiple people, it is impossible to attribute usage to a specific user. Solely relying on Entra ID authentication makes it easier to tie storage access to a user. ", + "graph": "resources | where type == 'microsoft.storage/storageaccounts' | extend allowSharedKeyAccess = tostring(properties.allowSharedKeyAccess) | extend compliant = (isnotempty(allowSharedKeyAccess) and allowSharedKeyAccess == 'false') | distinct id, compliant", + "guid": "15f51296-5398-4e6d-bd22-7dd142b06c21", + "link": "https://learn.microsoft.com/rest/api/storageservices/authorize-with-shared-key", + "service": "Azure Storage", "services": [ - "TrafficManager", + "Monitor", + "AKV", "Storage", "WAF", - "FrontDoor" + "Entra" ], - "severity": "Medium", - "text": "Consider using Traffic Manager load balancing Azure Front Door and a third party CDN provider CDN profile for mission critical high availability scenario. ", - "waf": "Reliability" + "severity": "High", + "text": "Consider disabling storage account keys, so that only Microsoft Entra ID access (and user delegation SAS) is supported.", + "waf": "Security" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "972cd4cd-25b0-4b70-96e9-eab4bfd32907", - "link": "https://learn.microsoft.com/azure/app-service/app-service-ip-restrictions?tabs=azurecli#restrict-access-to-a-specific-azure-front-door-instance", - "service": "Front Door", + "description": "Use Activity Log data to identify 'when', 'who', 'what' and 'how' the security of your storage account is being viewed or changed (i.e. storage account keys, access policies, etc.).", + "guid": "d7999a64-6f43-489a-af42-c78e78c06a73", + "link": "https://learn.microsoft.com/azure/storage/blobs/blob-storage-monitoring-scenarios#audit-account-activity", + "service": "Azure Storage", "services": [ - "AppSvc", + "Monitor", + "AKV", + "Storage", "WAF", - "FrontDoor" + "AzurePolicy" ], "severity": "High", - "text": "When using Front Door with origin as App services, consider locking down the traffic to app services only through Azure Front Door using access restrictions. ", + "text": "Consider using Azure Monitor to audit control plane operations on the storage account", "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "ab5351f6-383a-45ed-9c5e-b143b16db40a", - "link": "https://learn.microsoft.com/azure/aks/use-windows-hpc", - "service": "AKS", + "description": "A key expiration policy enables you to set a reminder for the rotation of the account access keys. The reminder is displayed if the specified interval has elapsed and the keys have not yet been rotated.", + "guid": "a22a4956-e7a8-4dc4-a20e-27c3e29711b1", + "link": "https://learn.microsoft.com/azure/storage/common/storage-account-keys-manage?tabs=azure-portal#create-a-key-expiration-policy", + "service": "Azure Storage", "services": [ - "AKS", + "Storage", + "AKV", + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "If required for AKS Windows workloads HostProcess containers can be used", - "waf": "Reliability" + "severity": "Medium", + "text": "When using storage account keys, consider enabling a 'key expiration policy'", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "a280dcf5-90ce-465d-b8e1-3f9ccbd46926", - "link": "https://learn.microsoft.com/azure/azure-functions/functions-kubernetes-keda", - "service": "AKS", + "description": "A SAS expiration policy specifies a recommended interval over which the SAS is valid. SAS expiration policies apply to a service SAS or an account SAS. When a user generates service SAS or an account SAS with a validity interval that is larger than the recommended interval, they'll see a warning.", + "guid": "352beee0-79b5-488d-bfc4-972cd3cd21bf", + "link": "https://learn.microsoft.com/azure/storage/common/sas-expiration-policy", + "service": "Azure Storage", "services": [ + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "Use KEDA if running event-driven workloads", - "waf": "Performance" + "severity": "Medium", + "text": "Consider configuring an SAS expiration policy", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "26886d20-b66c-457b-a591-19bf8e8f5c58", - "link": "https://dapr.io/", - "service": "AKS", + "description": "Stored access policies give you the option to revoke permissions for a service SAS without having to regenerate the storage account keys. ", + "guid": "77036e5e-6b4b-4ed3-b503-547c1347dc56", + "link": "https://learn.microsoft.com/rest/api/storageservices/define-stored-access-policy", + "service": "Azure Storage", "services": [ + "Storage", + "AKV", + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "Use Dapr to ease microservice development", - "waf": "Operations" + "severity": "Medium", + "text": "Consider linking SAS to a stored access policy", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (sku.tier=='Paid') | distinct id,compliant", - "guid": "71d41e36-10cc-457b-9a4b-1410d4395898", - "link": "https://learn.microsoft.com/azure/aks/uptime-sla", - "service": "AKS", + "guid": "028a71ff-e1ce-415d-b3f0-d5e772d41e36", + "link": "https://microsoft.github.io/code-with-engineering-playbook/continuous-integration/dev-sec-ops/secret-management/recipes/detect-secrets-ado/", + "service": "Azure Storage", "services": [ - "AKS", + "Storage", + "AKV", "WAF" ], - "severity": "High", - "text": "Use the SLA-backed AKS offering", - "waf": "Reliability" + "severity": "Medium", + "text": "Consider configuring your application's source code repository to detect checked-in connection strings and storage account keys.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "c1288b3c-6a57-4cfc-9444-51e1a3d3453a", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-scheduler", - "service": "AKS", + "description": "Ideally, your application should be using a managed identity to authenticate to Azure Storage. If that is not possible, consider having the storage credential (connection string, storage account key, SAS, service principal credential) in Azure KeyVault or an equivalent service.", + "guid": "11cc57b4-a4b1-4410-b439-58a8c2289b3d", + "link": "https://learn.microsoft.com/azure/architecture/framework/security/design-storage-keys", + "service": "Azure Storage", "services": [ - "WAF", - "Cost" + "Storage", + "Entra", + "WAF" ], - "severity": "Low", - "text": "Use Disruption Budgets in your pod and deployment definitions", - "waf": "Reliability" + "severity": "High", + "text": "Consider storing connection strings in Azure KeyVault (in scenarios where managed identities are not possible)", + "waf": "Security" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "3c763963-7a55-42d5-a15e-401955387e5c", - "link": "https://learn.microsoft.com/azure/container-registry/container-registry-geo-replication", - "service": "ACR", + "description": "Use near-term expiration times on an ad hoc SAS service SAS or account SAS. In this way, even if a SAS is compromised, it's valid only for a short time. This practice is especially important if you cannot reference a stored access policy. Near-term expiration times also limit the amount of data that can be written to a blob by limiting the time available to upload to it.", + "guid": "27138b82-1102-4cac-9eae-01e6e842e52f", + "link": "https://learn.microsoft.com/rest/api/storageservices/delegate-access-with-shared-access-signature", + "service": "Azure Storage", "services": [ - "WAF", - "ACR" + "Storage", + "AzurePolicy", + "WAF" ], "severity": "High", - "text": "If using a private registry, configure region replication to store images in multiple regions", - "waf": "Reliability" + "text": "Strive for short validity periods for ad-hoc SAS", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "f82cb8eb-8c0a-4a63-a25a-4956eaa8dc4a", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/aks/eslz-cost-governance-with-kubecost", - "service": "AKS", + "description": "When creating a SAS, be as specific and restrictive as possible. Prefer a SAS for a single resource and operation over a SAS which gives much broader access.", + "guid": "4721d928-c1b1-4cd5-81e5-4a29a9de399c", + "link": "https://learn.microsoft.com/rest/api/storageservices/delegate-access-with-shared-access-signature", + "service": "Azure Storage", "services": [ - "WAF", - "Cost" + "WAF" ], - "severity": "Low", - "text": "Use an external application such as kubecost to allocate costs to different users", - "waf": "Cost" + "severity": "Medium", + "text": "Apply a narrow scope to a SAS", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "4d3dfbab-9924-4831-a68d-fdf0d72f462c", - "link": "https://learn.microsoft.com/azure/aks/scale-down-mode", - "service": "AKS", + "description": "A SAS can include parameters on which client IP addresses or address ranges are authorized to request a resource using the SAS. ", + "guid": "fd7b28dc-9355-4562-82bf-e4564b0d834a", + "link": "https://learn.microsoft.com/rest/api/storageservices/create-account-sas", + "service": "Azure Storage", "services": [ "WAF" ], - "severity": "Low", - "text": "Use scale down mode to delete/deallocate nodes", - "waf": "Cost" + "severity": "Medium", + "text": "Consider scoping SAS to a specific client IP address, wherever possible", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "87e651ea-bc4a-4a87-a6df-c06a4b570ebc", - "link": "https://learn.microsoft.com/azure/aks/gpu-multi-instance", - "service": "AKS", + "description": "A SAS cannot constrain how much data a client uploads; given the pricing model of amount of storage over time, it might make sense to validate whether clients uploaded maliciously large contents.", + "guid": "348b263e-6dd6-4051-8a36-498f6dbad38e", + "service": "Azure Storage", "services": [ - "AKS", + "Storage", "WAF" ], - "severity": "Medium", - "text": "When required use multi-instance partitioning GPU on AKS Clusters", - "waf": "Cost" + "severity": "Low", + "text": "Consider checking uploaded data, after clients used a SAS to upload a file. ", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "2b72a08b-0410-4cd6-9093-e068a5cf27e8", - "link": "https://learn.microsoft.com/azure/aks/start-stop-nodepools", - "service": "AKS", + "description": "When accessing blob storage via SFTP using a 'local user account', the 'usual' RBAC controls do not apply. Blob access via NFS or REST might be more restrictive than SFTP access. Unfortunately, as of early 2023, local users are the only form of identity management that is currently supported for the SFTP endpoint", + "guid": "ad53cc7c-e1d7-4aaa-a357-1449ab8053d8", + "link": "https://learn.microsoft.com/azure/storage/blobs/secure-file-transfer-protocol-support#sftp-permission-model", + "service": "Azure Storage", "services": [ + "Storage", + "RBAC", + "Entra", "WAF" ], - "severity": "Low", - "text": "If running a Dev/Test cluster use NodePool Start/Stop", - "waf": "Cost" + "severity": "High", + "text": "SFTP: Limit the amount of 'local users' for SFTP access, and audit whether access is needed over time.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.addonProfiles.azurepolicy) and properties.addonProfiles.azurepolicy.enabled==true) | distinct id,compliant", - "guid": "9ca48e4a-85e2-4223-bce8-bb12307ca5f1", - "link": "https://learn.microsoft.com/azure/governance/policy/concepts/policy-for-kubernetes", - "service": "AKS", + "guid": "9f89dc7b-33be-42a1-a27f-7b9e91be1f38", + "link": "https://learn.microsoft.com/azure/storage/blobs/secure-file-transfer-protocol-known-issues#authentication-and-authorization", + "service": "Azure Storage", "services": [ - "AzurePolicy", - "AKS", "WAF" ], "severity": "Medium", - "text": "Use Azure Policy for Kubernetes to ensure cluster compliance", + "text": "SFTP: The SFTP endpoint does not support POSIX-like ACLs.", "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | project id,resourceGroup,name,pools=properties.agentPoolProfiles | project id,name,resourceGroup,poolcount=array_length(pools) | extend compliant = (poolcount > 1)", - "guid": "6f158e3e-a3a9-42c2-be7e-2165c3a87af4", - "link": "https://learn.microsoft.com/azure/aks/use-system-pools", - "service": "AKS", + "description": "Storage supports CORS (Cross-Origin Resource Sharing), i.e. an HTTP feature that enables web apps from a different domain to loosen the same-origin policy. When enabling CORS, keep the CorsRules to the least privilege.", + "guid": "cef39812-bd46-43cb-aac8-ac199ebb91a3", + "link": "https://learn.microsoft.com/rest/api/storageservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services", + "service": "Azure Storage", "services": [ + "Storage", + "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "Separate applications from the control plane with user/system node pools", + "severity": "High", + "text": "Avoid overly broad CORS policies", "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "a7a1f893-9bda-4477-98f2-4c116775c2ea", - "link": "https://learn.microsoft.com/azure/aks/use-system-pools", - "service": "AKS", + "description": "Data at rest is always encrypted server-side, and in addition might be encrypted client-side as well. Server-side encryption might happen using a platform-managed key (default) or customer-managed key. Client-side encryption might happen by either having the client supply an encryption/decryption key on a per-blob basis to Azure storage, or by completely handling encryption on the client-side. thus not relying on Azure Storage at all for confidentiality guarantees.", + "guid": "3d90cae2-cc88-4137-86f7-c0cbafe61464", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", + "service": "Azure Storage", "services": [ + "Storage", "WAF" ], - "severity": "Low", - "text": "Add taint to your system nodepool to make it dedicated", + "severity": "High", + "text": "Determine how data at rest should be encrypted. Understand the thread model for data.", "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "55b46a94-8008-4ae7-b7e4-b475b6c8bdbf", - "link": "https://learn.microsoft.com/azure/container-registry/", - "service": "AKS", + "guid": "8dd457e9-2713-48b8-8110-2cac6eae01e6", + "link": "https://learn.microsoft.com/azure/storage/common/customer-managed-keys-overview?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json&bc=%2Fazure%2Fstorage%2Fblobs%2Fbreadcrumb%2Ftoc.json", + "service": "Azure Storage", "services": [ - "WAF", - "ACR" + "WAF" ], "severity": "Medium", - "text": "Use a private registry for your images, such as ACR", + "text": "Determine which/if platform encryption should be used.", "waf": "Security" }, { - "arm-service": "microsoft.containerregistry/registries", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "59bce65d-e8a0-43f9-9879-468d66a786d6", - "link": "https://learn.microsoft.com/azure/security-center/container-security", - "service": "ACR", + "guid": "e842e52f-4721-4d92-ac1b-1cd521e54a29", + "link": "https://learn.microsoft.com/azure/storage/blobs/encryption-customer-provided-keys", + "service": "Azure Storage", "services": [ "WAF" ], "severity": "Medium", - "text": "Scan your images for vulnerabilities", + "text": "Determine which/if client-side encryption should be used.", "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "d167dd18-2b0a-4c24-8b99-9a646f8389a7", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-cluster-isolation", - "service": "AKS", + "description": "Anonymous access may present a security risk. We recommend that you disable anonymous access for optimal security. Disallowing anonymous access helps to prevent data breaches caused by undesired anonymous access.", + "graph": "resources | where type == 'microsoft.storage/storageaccounts' | extend compliant = (properties.allowBlobPublicAccess == 'false') | distinct id, compliant", + "guid": "659ae558-b937-4d49-a5e1-112dbd7ba012", + "link": "https://learn.microsoft.com/azure/storage/blobs/anonymous-read-access-configure?tabs=portal#allow-or-disallow-public-read-access-for-a-storage-account", + "service": "Azure Storage", "services": [ + "Storage", "WAF" ], "severity": "High", - "text": "Define app separation requirements (namespace/nodepool/cluster)", + "text": "Consider whether public blob anonymous access is needed, or whether it can be disabled for certain storage accounts. ", "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "5e3df584-eccc-4d97-a3b6-bcda3b50eb2e", - "link": "https://github.com/Azure/secrets-store-csi-driver-provider-azure", - "service": "AKS", + "guid": "cb8eb8c0-aa62-4a25-a495-6eaa8dc4a243", + "link": "https://learn.microsoft.com/azure/storage/common/storage-account-upgrade?tabs=azure-portal", + "service": "Azure Storage", "services": [ - "AKV", + "Storage", "WAF" ], - "severity": "Medium", - "text": "Store your secrets in Azure Key Vault with the CSI Secrets Store driver", - "waf": "Security" + "severity": "High", + "text": "Leverage a storagev2 account type for better performance and reliability", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "b03dda6d-58d7-4c89-8ddb-107d5769ae66", - "link": "https://learn.microsoft.com/azure/aks/update-credentials", - "service": "AKS", + "graph": "resources | where type =~ 'Microsoft.Storage/StorageAccounts' | extend compliant = (sku.name != 'Standard_LRS' and sku.name != 'Premium_LRS') | distinct id, compliant", + "guid": "e05bbe20-9d49-4fda-9777-8424d116785c", + "link": "https://learn.microsoft.com/azure/storage/common/storage-redundancy", + "service": "Azure Storage", "services": [ + "Storage", "WAF" ], "severity": "High", - "text": "If using Service Principals for the cluster, refresh credentials periodically (like quarterly)", - "waf": "Security" + "text": "Leverage GRS, ZRS or GZRS storage for the highest availability", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "e7ba73a3-0508-4f80-806f-527db30cee96", - "link": "https://learn.microsoft.com/azure/aks/use-kms-etcd-encryption", - "service": "AKS", + "guid": "2fa56c56-ad48-4408-be72-734c486ba280", + "link": "https://learn.microsoft.com/azure/storage/common/storage-disaster-recovery-guidance", + "service": "Azure Storage", "services": [ "WAF" ], "severity": "Medium", - "text": "If required add Key Management Service etcd encryption", - "waf": "Security" + "text": "For write operation after failover, use customer-Managed Failover ", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "ec8e4e42-0344-41b0-b865-9123e8956d31", - "link": "https://learn.microsoft.com/azure/confidential-computing/confidential-nodes-aks-overview", - "service": "AKS", + "guid": "dc0590cf-65de-48e1-909c-cbd579266bcc", + "link": "https://learn.microsoft.com/azure/storage/common/storage-disaster-recovery-guidance#microsoft-managed-failover", + "service": "Azure Storage", "services": [ - "AKS", "WAF" ], - "severity": "Low", - "text": "If required consider using Confidential Compute for AKS", - "waf": "Security" + "severity": "Medium", + "text": "Understand Microsoft-Managed Failover details", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "c9e95ffe-6dd1-4a17-8c5f-110389ca9b21", - "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-containers-enable", - "service": "AKS", + "guid": "a274faa1-abfe-49d5-9d04-c3c4919cb1b3", + "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-enable?tabs=azure-portal", + "service": "Azure Storage", "services": [ - "WAF", - "Defender" + "WAF" ], "severity": "Medium", - "text": "Consider using Defender for Containers", - "waf": "Security" + "text": "Enable Soft Delete", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.servicePrincipalProfile.clientId=='msi') | distinct id,compliant", - "guid": "ed127dd1-42b0-46b2-8c69-99a646f3389a", - "link": "https://learn.microsoft.com/azure/aks/use-managed-identity", - "service": "AKS", + "guid": "4620dc87-e948-4ce8-8426-f3e6e5d7bd85", + "link": "https://learn.microsoft.com/azure/sap/center-sap-solutions/overview", + "service": "SAP", "services": [ - "WAF", - "Entra" + "SAP", + "WAF" ], - "severity": "High", - "text": "Use managed identities instead of Service Principals", - "waf": "Security" + "severity": "Medium", + "text": "Azure Center for SAP solutions (ACSS) is an Azure offering that makes SAP a top-level workload on Azure. ACSS is an end-to-end solution that enables you to create and run SAP systems as a unified workload on Azure and provides a more seamless foundation for innovation. You can take advantage of the management capabilities for both new and existing Azure-based SAP systems.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-center-sap-solutions/?source=recommendations", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = isnotnull(properties.aadProfile) | distinct id,compliant", - "guid": "7e42c78e-78c0-46a6-8a21-94956e698dc4", - "link": "https://learn.microsoft.com/azure/aks/managed-aad", - "service": "AKS", + "guid": "5d75e99d-624d-4afe-91d9-e17adc580790", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-platform-automation-and-devops", + "service": "SAP", "services": [ - "WAF", - "Entra" + "SAP", + "WAF" ], "severity": "Medium", - "text": "Integrate authentication with AAD (using the managed integration)", - "waf": "Security" + "text": "Azure supports automating SAP deployments in Linux and Windows. SAP Deployment Automation Framework is an open-source orchestration tool that can deploy, install, and maintain SAP environments.", + "training": "https://github.com/Azure/sap-automation", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "a2fe27b2-e287-401a-8352-beedf79b488d", - "link": "https://learn.microsoft.com/azure/aks/control-kubeconfig-access", - "service": "AKS", + "guid": "d17f6f39-a377-48a2-931f-5ead3ebe33a8", + "link": "https://learn.microsoft.com/azure/well-architected/sap/design-areas/data-platform", + "service": "SAP", "services": [ + "SAP", "WAF" ], "severity": "Medium", - "text": "Limit access to admin kubeconfig (get-credentials --admin)", - "waf": "Security" + "text": "Perform a point-in-time recovery for your production databases at any point and in a time frame that meets your RTO; point-in-time recovery typically includes operator errors deleting data either on the DBMS layer or through SAP, incidentally", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "eec4962c-c3bd-421b-b77f-26e5e6b3bec3", - "link": "https://learn.microsoft.com/azure/aks/manage-azure-rbac", - "service": "AKS", + "guid": "c4b8e117-930b-4dbd-ae50-7bc5faf6f91a", + "service": "SAP", "services": [ - "RBAC", - "WAF", - "Entra" + "Backup", + "WAF" ], "severity": "Medium", - "text": "Integrate authorization with AAD RBAC", - "waf": "Security" + "text": "Test the backup and recovery times to verify that they meet your RTO requirements for restoring all systems simultaneously after a disaster.", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "d4f3537c-1346-4dc5-9027-a71ffe1bd05d", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-identity", - "service": "AKS", + "guid": "b651423c-8552-42db-a545-5cb50c05527a", + "link": "https://learn.microsoft.com/azure/reliability/cross-region-replication-azure", + "service": "SAP", "services": [ - "RBAC", - "AKS", + "ASR", + "Backup", + "Storage", + "SAP", + "SQL", "WAF" ], "severity": "High", - "text": "Use namespaces for restricting RBAC privilege in Kubernetes", - "waf": "Security" - }, - { - "arm-service": "microsoft.containerservice/managedClusters", - "checklist": "WAF checklist", - "guid": "d2e0d5d7-71d4-41e3-910c-c57b4a4b1410", - "link": "https://learn.microsoft.com/azure/aks/workload-identity-migration-sidecar", - "service": "AKS", - "services": [ - "WAF", - "Entra" - ], - "severity": "Medium", - "text": "For Pod Identity Access Management use Azure AD Workload Identity (preview)", - "waf": "Security" + "text": "You can replicate standard storage between paired regions, but you can't use standard storage to store your databases or virtual hard disks. You can replicate backups only between paired regions that you use. For all your other data, run your replication by using native DBMS features like SQL Server Always On or SAP HANA System Replication. Use a combination of Site Recovery, rsync or robocopy, and other third-party software for the SAP application layer.", + "training": "https://learn.microsoft.com/training/paths/ensure-business-continuity-implement-disaster-recovery/", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "f4dcf690-1b30-407d-abab-6f8aa780d3a3", - "link": "https://learn.microsoft.com/azure/aks/managed-aad#non-interactive-sign-in-with-kubelogin", - "service": "AKS", + "guid": "aa208dca-784f-46c6-9014-cc919c542dc9", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-zones", + "service": "SAP", "services": [ - "AKS", + "SAP", "WAF" ], "severity": "Medium", - "text": "For AKS non-interactive logins use kubelogin (preview)", - "waf": "Security" + "text": "When using Azure Availability Zones to achieve high availability, you must consider latency between SAP application servers and database servers. For zones with high latencies, operational procedures need to be in place to ensure that SAP application servers and database servers are running in the same zone at all times.", + "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.disableLocalAccounts==true) | distinct id,compliant", - "guid": "b085b1f2-3119-4771-8c9a-bbf4411810ec", - "link": "https://learn.microsoft.com/azure/aks/managed-aad#disable-local-accounts", - "service": "AKS", + "graph": "resources| where type =~ 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType =~ 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant", + "guid": "ba07c007-1f90-43e9-aa4f-601346b80352", + "link": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering", + "service": "SAP", "services": [ - "AKS", + "ASR", + "ExpressRoute", + "VPN", "WAF" ], - "severity": "Medium", - "text": "Disable AKS local accounts", - "waf": "Security" + "severity": "High", + "text": "Set up ExpressRoute connections from on-premises to the primary and secondary Azure disaster recovery regions. Also, as an alternative to using ExpressRoute, consider setting up VPN connections from on-premises to the primary and secondary Azure disaster recovery regions.", + "training": "https://learn.microsoft.com/azure/expressroute/use-s2s-vpn-as-backup-for-expressroute-privatepeering", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "36abb0db-c118-4f4c-9880-3f30f9a2deb6", - "link": "https://learn.microsoft.com/azure/aks/managed-aad#configure-just-in-time-cluster-access-with-azure-ad-and-aks", - "service": "AKS", + "guid": "d2b30195-b11d-4a8f-a672-28b2b4169a7c", + "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance", + "service": "SAP", "services": [ + "ACR", + "AKV", "WAF" ], "severity": "Low", - "text": "Configure if required Just-in-time cluster access", - "waf": "Security" + "text": "Replicate key vault contents like certificates, secrets, or keys across regions so you can decrypt data in the DR region.", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c4d7f4c6-79bf-45d0-aa05-ce8fc717e150", - "link": "https://learn.microsoft.com/azure/aks/managed-aad#use-conditional-access-with-azure-ad-and-aks", - "service": "AKS", + "guid": "05f1101d-250f-40e7-b2a1-b674ab50edbd", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-s4hana", + "service": "SAP", "services": [ - "AKS", - "WAF", - "Entra" + "VNet", + "ASR", + "SAP", + "WAF" ], - "severity": "Low", - "text": "Configure if required AAD conditional access for AKS", - "waf": "Security" + "severity": "Medium", + "text": "Peer the primary and disaster recovery virtual networks. For example, for HANA System Replication, an SAP HANA DB virtual network needs to be peered to the disaster recovery site's SAP HANA DB virtual network.", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "e1123a7c-a333-4eb4-a120-4ee3f293c9f3", - "link": "https://learn.microsoft.com/azure/aks/use-group-managed-service-accounts", - "service": "AKS", + "guid": "d3351bf7-628a-46de-917d-dfc11d3b6b40", + "link": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-service-levels", + "service": "SAP", "services": [ - "AKS", + "Storage", + "SAP", "WAF" ], "severity": "Low", - "text": "If required for Windows AKS workloads configure gMSA ", - "waf": "Security" + "text": "If you use Azure NetApp Files storage for your SAP deployments, at a minimum, create two Azure NetApp Files accounts in the Premium tier, in two regions.", + "training": "https://learn.microsoft.com/training/modules/choose-service-level-azure-netapp-files-hpc-applications/2-identify-decision-criteria", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "1f711a74-3672-470b-b8b8-a2148d640d79", - "link": "https://learn.microsoft.com/azure/aks/use-managed-identity#use-a-pre-created-kubelet-managed-identity", - "service": "AKS", + "guid": "726a1d3e-5508-4a06-9d54-93f4b50040c1", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", + "service": "SAP", "services": [ - "WAF", - "Entra" + "WAF" ], - "severity": "Medium", - "text": "For finer control consider using a managed Kubelet Identity", - "waf": "Security" + "severity": "High", + "text": "Native database replication technology should be used to synchronize the database in a HA pair.", + "training": "https://learn.microsoft.com/training/modules/implement-disaster-recovery-for-sap-workloads-azure/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "cbd8ac2a-aebc-4a2a-94da-1dbf3dc99248", - "link": "https://azure.github.io/application-gateway-kubernetes-ingress/setup/install-existing/", - "service": "AKS", + "graph": "resources | where type =~ 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr", + "guid": "6561f847-3db5-4ff8-9200-5ad3c3b436ad", + "link": "https://learn.microsoft.com/ja-jp/azure/virtual-network/virtual-networks-faq", + "service": "SAP", "services": [ - "AppGW", - "WAF", - "ACR" + "VNet", + "WAF" ], - "severity": "Medium", - "text": "If using AGIC, do not share an AppGW across clusters", + "severity": "High", + "text": "The CIDR for the primary virtual network (VNet) shouldn't conflict or overlap with the CIDR of the DR site's VNet", + "training": "https://learn.microsoft.com/training/paths/azure-fundamentals-describe-azure-architecture-services/?source=recommendations", "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnull(properties.addonProfiles.httpApplicationRouting) or properties.addonProfiles.httpApplicationRouting.enabled==false) | distinct id,compliant", - "guid": "8008ae7d-7e4b-4475-a6c8-bdbf59bce65d", - "link": "https://learn.microsoft.com/azure/aks/http-application-routing", - "service": "AKS", + "guid": "0258ed30-fe42-434f-87b9-58f91f908e0a", + "service": "SAP", "services": [ - "AKS", + "VM", + "ASR", + "Entra", "WAF" ], "severity": "High", - "text": "Do not use AKS HTTP Routing Add-On, use instead the managed NGINX ingress with the application routing add-on.", + "text": "Use Site Recovery to replicate an application server to a DR site. Site Recovery can also help with replicating central-services cluster VMs to the DR site. When you invoke DR, you'll need to reconfigure the Linux Pacemaker cluster on the DR site (for example, replace the VIP or SBD, run corosync.conf, and more).", + "training": "https://learn.microsoft.com/training/paths/ensure-business-continuity-implement-disaster-recovery/", "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "7bacd7b9-c025-4a9d-a5d2-25d6bc5439d9", - "link": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview", - "service": "AKS", + "guid": "8300cb30-766b-4084-b126-0dd8fb1269a1", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-business-continuity-and-disaster-recovery", + "service": "SAP", "services": [ + "SAP", "WAF" ], - "severity": "Medium", - "text": "For Windows workloads use Accelerated Networking", - "waf": "Performance" + "severity": "High", + "text": "Consider the availability of SAP software against single points of failure. This includes single points of failure within applications such as DBMSs utilized in SAP NetWeaver and SAP S/4HANA architectures, SAP ABAP and ASCS + SCS. Also, other tools such as SAP Web Dispatcher.", + "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/2-explore-high-availability-disaster-recovery-support-azure-for-sap-workloads?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (tolower(properties.networkProfile.loadBalancerSku)=='standard') | distinct id,compliant", - "guid": "ba7da7be-9952-4914-a384-5d997cb39132", - "link": "https://learn.microsoft.com/azure/aks/load-balancer-standard", - "service": "AKS", + "guid": "56402f11-ccbe-42c3-a2f6-c6f6f38ab579", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-supported-configurations", + "service": "SAP", "services": [ - "LoadBalancer", + "SAP", "WAF" ], "severity": "High", - "text": "Use the standard ALB (as opposed to the basic one)", + "text": "For SAP and SAP databases, consider implementing automatic failover clusters. In Windows, Windows Server Failover Clustering supports failover. In Linux, Linux Pacemaker or third-party tools like SIOS Protection Suite and Veritas InfoScale support failover.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "22fbe8d6-9b40-47ef-9011-25bb1a555a6b", - "link": "https://learn.microsoft.com/azure/aks/use-multiple-node-pools#add-a-node-pool-with-a-unique-subnet", - "service": "AKS", + "guid": "afae6bec-2671-49ae-bc69-140b8ec8d320", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", + "service": "SAP", "services": [ - "VNet", + "Storage", + "VM", "WAF" ], - "severity": "Medium", - "text": "If using Azure CNI, consider using different Subnets for NodePools", - "waf": "Security" + "severity": "High", + "text": "Azure doesn't support architectures in which the primary and secondary VMs share storage for DBMS data. For the DBMS layer, the common architecture pattern is to replicate databases at the same time and with different storage stacks than the ones that the primary and secondary VMs use.", + "training": "https://learn.microsoft.com/training/paths/ensure-business-continuity-implement-disaster-recovery/?source=recommendationshttps%3A%2F%2Flearn.microsoft.com%2Fja-jp%2Ftraining%2Fpaths%2Fensure-business-continuity-implement-disaster-recovery%2F%3Fsource%3Drecommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c3c39c98-6bb2-4c12-859a-114b5e3df584", - "link": "https://learn.microsoft.com/azure/private-link/private-link-overview", - "service": "AKS", + "guid": "ac614e95-6767-4bc3-b8a4-9953533da6ba", + "link": "https://learn.microsoft.com/azure/sap/workloads/dbms-guide-general", + "service": "SAP", "services": [ - "PrivateLink", - "VNet", + "Storage", + "SAP", "WAF" ], - "severity": "Medium", - "text": "Use Private Endpoints (preferred) or Virtual Network Service Endpoints to access PaaS services from the cluster", - "waf": "Security" + "severity": "High", + "text": "The DBMS data and transaction/redo log files are stored in Azure supported block storage or Azure NetApp Files. Azure Files or Azure Premium Files isn't supported as storage for DBMS data and/or redo log files with SAP workload.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-databases/2-explore-database-support-azure-for-sap-workloads", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.networkProfile.networkPlugin=='azure') | distinct id,compliant", - "guid": "a0f61565-9de5-458f-a372-49c831112dbd", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-network", - "service": "AKS", + "guid": "1f737179-8e7f-4e1a-a30c-e5a649a3092b", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-wsfc-shared-disk", + "service": "SAP", "services": [ + "SAP", "WAF" ], "severity": "High", - "text": "Choose the best CNI network plugin for your requirements (Azure CNI recommended)", + "text": "You can use Azure shared disks in Windows for ASCS + SCS components and specific high-availability scenarios. Set up your failover clusters separately for SAP application layer components and the DBMS layer. Azure doesn't currently support high-availability architectures that combine SAP application layer components and the DBMS layer into one failover cluster.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "7faf12e7-0943-4f63-8472-2da29c2b1cd6", - "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", - "service": "AKS", + "graph": "resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools =~ 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name =~ 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name =~ 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses))", + "guid": "a78b3d31-3170-44f2-b5d7-651a29f4ccf5", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-standard-load-balancer-outbound-connections", + "service": "SAP", "services": [ - "VNet", + "LoadBalancer", + "SAP", "WAF" ], "severity": "High", - "text": "If using Azure CNI, size your subnet accordingly considering the maximum number of pods per node", - "waf": "Performance" + "text": "Most failover clusters for SAP application layer components (ASCS) and the DBMS layer require a virtual IP address for a failover cluster. Azure Load Balancer should handle the virtual IP address for all other cases. One design principle is to use one load balancer per cluster configuration. We recommend that you use the standard version of the load balancer (Standard Load Balancer SKU).", + "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "22f54b29-bade-43aa-b1e8-c38ec9366673", - "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", - "service": "AKS", + "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-ha-ports-overview?source=recommendations", + "service": "SAP", "services": [ + "LoadBalancer", "WAF" ], "severity": "High", - "text": "If using Azure CNI, check the maximum pods/node (default 30)", - "waf": "Performance" + "text": "Make sure the Floating IP is enabled on the Load balancer", + "training": "https://learn.microsoft.com/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "For internal apps organizations often open the whole AKS subnet in their firewalls. This opens network access to the nodes too, and potentially to the pods as well (if using Azure CNI). If LoadBalancer IPs are in a different subnet, only this one needs to be available to the app clients. Another reason is that if the IP addresses in the AKS subnet are a scarce resource, consuming its IP addresses for services will reduce the maximum scalability of the cluster .", - "guid": "13c00567-4b1e-4945-a459-c373e7ed6162", - "link": "https://learn.microsoft.com/azure/aks/internal-lb", - "service": "AKS", + "guid": "c47cc4f3-f105-452c-845e-9b307b3856c1", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "service": "SAP", "services": [ - "AKS", - "VNet", "WAF" ], - "severity": "Low", - "text": "If using private-IP LoadBalancer services, use a dedicated subnet (not the AKS subnet)", - "waf": "Security" + "severity": "High", + "text": "Before you deploy your high-availability infrastructure, and depending on the region you choose, determine whether to deploy with an Azure availability set or an availability zone.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "43f63047-22d9-429c-8b1c-d622f54b29ba", - "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", - "service": "AKS", + "guid": "844f69c3-07e5-4ec1-bff7-4be27bcf5fea", + "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", + "service": "SAP", "services": [ + "VM", + "SAP", + "Entra", "WAF" ], "severity": "High", - "text": "Size the service IP address range accordingly (it is going to limit the cluster scalability)", + "text": "If you want to meet the infrastructure SLAs for your applications for SAP components (central services, application servers, and databases), you must choose the same high availability options (VMs, availability sets, availability zones) for all components.", "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "57bf217f-6dc8-481c-81e2-785773e9c00f", - "link": "https://learn.microsoft.com/azure/aks/use-byo-cni", - "service": "AKS", + "guid": "cbe05bbe-209d-4490-ba47-778424d11678", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "service": "SAP", "services": [ + "VM", + "RBAC", + "Entra", "WAF" ], - "severity": "Low", - "text": "If required add your own CNI plugin", - "waf": "Security" + "severity": "High", + "text": "Do not mix servers of different roles in the same availability set. Keep central services VMs, database VMs, application VMs in their own availability sets", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "4b3bb365-9458-44d9-9ed1-5c8f52890364", - "link": "https://learn.microsoft.com/azure/aks/use-multiple-node-pools#assign-a-public-ip-per-node-for-your-node-pools", - "service": "AKS", + "guid": "f2201000-d045-40a6-a79a-d7cdc01b4d86", + "link": "https://learn.microsoft.com/azure/virtual-machines/co-location", + "service": "SAP", "services": [ - "AKS", "WAF" ], - "severity": "Low", - "text": "If required configure Public IP per node in AKS", - "waf": "Performance" + "severity": "Medium", + "text": "You can't deploy Azure availability sets within an Azure availability zone unless you use proximity placement groups.", + "training": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "b3808b9f-a1cf-4204-ad01-3a923ce474db", - "link": "https://learn.microsoft.com/azure/aks/concepts-network", - "service": "AKS", + "guid": "9674e7c7-7796-4181-8920-09f4429543ba", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "service": "SAP", "services": [ + "VM", "WAF" ], - "severity": "Medium", - "text": "Use an ingress controller to expose web-based apps instead of exposing them with LoadBalancer-type services", + "severity": "High", + "text": "When you create availability sets, use the maximum number of fault domains and update domains available. For example, if you deploy more than two VMs in one availability set, use the maximum number of fault domains (three) and enough update domains to limit the effect of potential physical hardware failures, network outages, or power interruptions, in addition to Azure planned maintenance. The default number of fault domains is two, and you can't change it online later.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations", "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "ccb534e7-416e-4a1d-8e93-533b53199085", - "link": "https://learn.microsoft.com/azure/aks/nat-gateway", - "service": "AKS", + "guid": "ae4ecb95-b70f-428f-8b9a-4c5b7e3478a2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "service": "SAP", "services": [ + "SAP", + "Entra", "WAF" ], - "severity": "Low", - "text": "Use Azure NAT Gateway as outboundType for scaling egress traffic", + "severity": "High", + "text": "When you use Azure proximity placement groups in an availability set deployment, all three SAP components (central services, application server, and database) should be in the same proximity placement group.", "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "8ee9a69a-1b58-4b1e-9c61-476e110a160b", - "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni#dynamic-allocation-of-ips-and-enhanced-subnet-support", - "service": "AKS", + "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "service": "SAP", "services": [ + "ACR", + "SAP", "WAF" ], - "severity": "Medium", - "text": "Use Dynamic allocations of IPs in order to avoid Azure CNI IP exhaustion", + "severity": "High", + "text": "Use one proximity placement group per SAP SID. Groups don't span across Availability Zones or Azure regions", "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.networkProfile.outboundType=='userDefinedRouting') | distinct id,compliant", - "guid": "3b365a91-7ecb-4e48-bbe5-4cd7df2e8bba", - "link": "https://learn.microsoft.com/azure/aks/limit-egress-traffic", - "service": "AKS", + "guid": "bca3b10e-0ff5-4aec-ac16-4c4bd1a1c13f", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-business-continuity-and-disaster-recovery", + "service": "SAP", "services": [ - "NVA", + "SAP", + "Entra", "WAF" ], "severity": "High", - "text": "Filter egress traffic with AzFW/NVA if your security requirements mandate it", - "waf": "Security" + "text": "Use one of the following services to run SAP central services clusters, depending on the operating system.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = ((isnull(properties.apiServerAccessProfile.enablePrivateCluster) or properties.apiServerAccessProfile.enablePrivateCluster==false) and isnotnull(properties.apiServerAccessProfile.authorizedIPRanges)) | distinct id,compliant", - "guid": "c4581559-bb91-463e-a908-aed8c44ce3b2", - "link": "https://learn.microsoft.com/azure/aks/api-server-authorized-ip-ranges", - "service": "AKS", + "guid": "ed46b937-913e-4018-9c62-8393ab037e53", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-suse-multi-sid", + "service": "SAP", "services": [ + "VM", + "Entra", "WAF" ], "severity": "Medium", - "text": "If using a public API endpoint, restrict the IP addresses that can access it", - "waf": "Security" + "text": "Azure doesn't currently support combining ASCS and DB HA in the same Linux Pacemaker cluster; separate them into individual clusters. However, you can combine up to five multiple central-services clusters into a pair of VMs.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | where isnotnull(properties.apiServerAccessProfile.enablePrivateCluster) | extend compliant = (properties.apiServerAccessProfile.enablePrivateCluster==true) | distinct id, compliant", - "guid": "ecccd979-3b6b-4cda-9b50-eb2eb03dda6d", - "link": "https://learn.microsoft.com/azure/aks/private-clusters", - "service": "AKS", + "graph": "Resources | where type =~ 'Microsoft.Storage/storageAccounts' | where sku.name in~ ('Standard_LRS', 'Premium_LRS') | project name, id, tags, param1 = strcat('sku: ', sku.name)", + "guid": "f656e745-0cfb-453e-8008-0528fa21c933", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-business-continuity-and-disaster-recovery", + "service": "SAP", "services": [ + "Storage", + "VM", "WAF" ], - "severity": "High", - "text": "Use private clusters if your requirements mandate it", - "waf": "Security" + "severity": "Medium", + "text": "Deploy both VMs in the high-availability pair in an availability set or in availability zones. These VMs should be the same size and have the same storage configuration.", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | where isnotnull(properties.apiServerAccessProfile.enablePrivateCluster) | extend compliant = (properties.apiServerAccessProfile.enablePrivateCluster==true) | distinct id, compliant", - "guid": "ce7f2a7c-297c-47c6-adea-a6ff838db665", - "link": "https://learn.microsoft.com/azure/aks/use-network-policies", - "service": "AKS", + "guid": "7f684ebc-95da-425e-b329-e782dbed050f", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel-with-hana-ascs-ers-dialog-instance", + "service": "SAP", "services": [ - "AzurePolicy", - "AKS", + "SAP", "WAF" ], "severity": "Medium", - "text": "For Windows 2019 and 2022 AKS nodes Calico Network Policies can be used ", - "waf": "Security" + "text": "Azure supports installing and configuring SAP HANA and ASCS/SCS and ERS instances on the same high availability cluster running on Red Hat Enterprise Linux (RHEL).", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = isnotnull(properties.networkProfile.networkPolicy) | distinct id,compliant", - "guid": "58d7c892-ddb1-407d-9769-ae669ca48e4a", - "link": "https://learn.microsoft.com/azure/aks/use-network-policies", - "service": "AKS", + "guid": "07991f7d-6598-4d90-9431-45c62605d3a5", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-guide-storage", + "service": "SAP", "services": [ - "AzurePolicy", - "AKS", + "Storage", "WAF" ], "severity": "High", - "text": "Enable a Kubernetes Network Policy option (Calico/Azure)", - "waf": "Security" + "text": "Run all production systems on Premium managed SSDs and use Azure NetApp Files or Ultra Disk Storage. At least the OS disk should be on the Premium tier so you can achieve better performance and the best SLA.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-storage/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "85e2223e-ce8b-4b12-907c-a5f16f158e3e", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-network", - "service": "AKS", + "guid": "73cdaecc-7d74-48d8-a040-88416eebc98c", + "link": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-operations-storage", + "service": "SAP", "services": [ - "AzurePolicy", - "AKS", + "Storage", + "SAP", "WAF" ], "severity": "High", - "text": "Use Kubernetes network policies to increase intra-cluster security", - "waf": "Security" + "text": "You should run SAP HANA on Azure only on the types of storage that are certified by SAP. Note that certain volumes must be run on certain disk configurations, where applicable. These configurations include enabling Write Accelerator and using Premium storage. You also need to ensure that the file system that runs on storage is compatible with the DBMS that runs on the machine.", + "training": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-premium-ssd-v1?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "a3a92c2d-e7e2-4165-a3a8-7af4a7a1f893", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-network", - "service": "AKS", + "guid": "51904867-a70e-4fa0-b4ff-3e6292846d7c", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-overview-guide#storage", + "service": "SAP", "services": [ + "Storage", + "ASR", + "SAP", "WAF" ], "severity": "High", - "text": "Use a WAF for web workloads (UIs or APIs)", - "waf": "Security" - }, - { - "arm-service": "microsoft.containerservice/managedClusters", - "checklist": "WAF checklist", - "graph": "Resources | where type=~'microsoft.containerservice/managedclusters' | project resourceGroup,name,pools=properties.agentPoolProfiles | mv-expand pools | project subnetId=tostring(pools.vnetSubnetID) | where isnotempty(subnetId) | join (Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,enableDdosProtection=tostring(properties.enableDdosProtection),subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,enableDdosProtection,subnetId=tostring(subnets.id)) on subnetId | distinct id,resourceGroup,name,enableDdosProtection | extend compliant = (enableDdosProtection == 'true')", - "guid": "9bda4776-8f24-4c11-9775-c2ea55b46a94", - "link": "https://learn.microsoft.com/azure/virtual-network/ddos-protection-overview", - "service": "AKS", - "services": [ - "DDoS", - "AKS", - "VNet", - "WAF" - ], - "severity": "Medium", - "text": "Use DDoS Standard in the AKS Virtual Network", - "waf": "Security" + "text": "Consider configuring high availability depending on the type of storage you use for your SAP workloads. Some storage services available in Azure are not supported by Azure Site Recovery, so your high availability configuration may differ.", + "training": "https://learn.microsoft.com/training/modules/implement-disaster-recovery-for-sap-workloads-azure/2-explore-disaster-recovery-sap-workloads", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "Resources | where type=~'microsoft.containerservice/managedclusters' | project resourceGroup,name,pools=properties.agentPoolProfiles | mv-expand pools | project subnetId=tostring(pools.vnetSubnetID) | where isnotempty(subnetId) | join (Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,enableDdosProtection=tostring(properties.enableDdosProtection),subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,enableDdosProtection,subnetId=tostring(subnets.id)) on subnetId | distinct id,resourceGroup,name,enableDdosProtection | extend compliant = (enableDdosProtection == 'true')", - "guid": "6c46b91a-1107-4485-ad66-3183e2a8c266", - "link": "https://learn.microsoft.com/azure/aks/http-proxy", - "service": "AKS", + "guid": "1ac2d928-c9b7-42c6-ba18-23b1aea78693", + "link": "https://azure.microsoft.com/ja-jp/explore/global-infrastructure/products-by-region/", + "service": "SAP", "services": [ + "Storage", + "SAP", "WAF" ], - "severity": "Low", - "text": "If required add company HTTP Proxy", - "waf": "Security" + "severity": "High", + "text": "Different native Azure storage services (like Azure Files, Azure NetApp Files, Azure Shared Disk) may not be available in all regions. So to have similar SAP setup on the DR region after failover, ensure the respective storage service is offered in DR site.", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "e9855d04-c3c3-49c9-a6bb-2c12159a114b", - "link": "https://learn.microsoft.com/azure/aks/servicemesh-about", - "service": "AKS", + "guid": "925d1f8c-01f3-4a67-948e-aabf0a1fad60", + "link": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/optimize-your-azure-costs-by-automating-sap-system-start-stop/ba-p/2120675", + "service": "SAP", "services": [ + "Cost", + "SAP", "WAF" ], "severity": "Medium", - "text": "Consider using a service mesh for advanced microservice communication management", - "waf": "Security" + "text": "Automate SAP System Start-Stop to manage costs.", + "waf": "Cost" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "67f7a9ed-5b31-4f38-a3f3-9812b2463cff", - "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-metric-alerts", - "service": "AKS", + "guid": "71dc00cd-4392-4262-8949-20c05e6c0333", + "link": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-premium-ssd-v1", + "service": "SAP", "services": [ + "Cost", + "Storage", + "SAP", "WAF", - "Monitor" + "VM" ], - "severity": "High", - "text": "Configure alerts on the most critical metrics (see Container Insights for recommendations)", - "waf": "Operations" + "severity": "Low", + "text": "In the case of using Azure Premium Storage with SAP HANA, Azure Standard SSD storage can be used to select a cost-conscious storage solution. However, please note that choosing Standard SSD or Standard HDD Azure storage will affect the SLA of the individual VMs. Also, for systems with lower I/O throughput and low latency, such as non-production environments, lower series VMs can be used.", + "waf": "Cost" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "337453a3-cc63-4963-9a65-22ac19e80696", - "link": "https://learn.microsoft.com/azure/advisor/advisor-get-started", - "service": "AKS", + "guid": "9877f353-2591-4e8b-8381-e9043fed1010", + "link": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-premium-ssd-v1", + "service": "SAP", "services": [ + "Cost", + "Storage", + "SAP", "WAF", - "Entra" + "VM" ], "severity": "Low", - "text": "Check regularly Azure Advisor for recommendations on your cluster", - "waf": "Operations" + "text": "As a lower-cost alternative configuration (multipurpose), you can choose a low-performance SKU for your non-production HANA database server VMs. However, it is important to note that some VM types, such as E-series, are not HANA certified (SAP HANA Hardware Directory) or cannot achieve storage latency of less than 1ms.", + "waf": "Cost" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "3aa70560-e7e7-4968-be3d-628af35b2ced", - "link": "https://learn.microsoft.com/azure/aks/certificate-rotation", - "service": "AKS", + "graph": "resources | where type =~ 'microsoft.aad/domainservices' | extend replicaSets = properties.replicaSets | where array_length(replicaSets) < 2 | project name=name, id=id, tags=tags, param1=strcat('replicaSetLocation:', replicaSets[0].location)", + "guid": "fda1dbf3-dc95-4d48-a7c7-91dca0f6c565", + "link": "https://learn.microsoft.com/azure/well-architected/sap/design-areas/security", + "service": "SAP", "services": [ - "AKS", + "Subscriptions", + "RBAC", "WAF" ], - "severity": "Low", - "text": "Enable AKS auto-certificate rotation", - "waf": "Operations" + "severity": "High", + "text": "Enforce a RBAC model for management groups, subscriptions, resource groups and resources", + "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "e189c599-df0d-45a7-9dd4-ce32c1881370", - "link": "https://learn.microsoft.com/azure/aks/supported-kubernetes-versions", - "service": "AKS", + "guid": "45911475-e39e-4530-accc-d979366bcda2", + "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/scenario-azure-first-sap-identity-integration", + "service": "SAP", "services": [ - "AKS", + "SAP", + "Entra", "WAF" ], - "severity": "High", - "text": "Have a regular process to upgrade your kubernetes version periodically (quarterly, for example), or use the AKS autoupgrade feature", - "waf": "Operations" + "severity": "Medium", + "text": "Enforce Principal propagation for forwarding the identity from SAP cloud application to SAP on-premises (Including IaaS) through cloud connector", + "training": "https://learn.microsoft.com/training/modules/explore-identity-services/2-explore-azure-virtual-machine-auth-access-control", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "6f7c4c0d-4e51-4464-ad24-57ed67138b82", - "link": "https://learn.microsoft.com/azure/aks/node-updates-kured", - "service": "AKS", + "guid": "750ab1ab-039d-495d-94c7-c8929cb107d5", + "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/scenario-azure-first-sap-identity-integration", + "service": "SAP", "services": [ + "SAP", + "Entra", "WAF" ], - "severity": "High", - "text": "Use kured for Linux node upgrades in case you are not using node-image upgrade", - "waf": "Operations" + "severity": "Medium", + "text": "Implement SSO to SAP SaaS applications like SAP Analytics Cloud, SAP Cloud Platform, Business by design, SAP Qualtrics and SAP C4C with Azure AD using SAML.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "139c9580-ade3-426a-ba09-cf157d9f6477", - "link": "https://learn.microsoft.com/azure/aks/node-image-upgrade", - "service": "AKS", + "guid": "325ae525-ba34-4d46-a5e2-213ace7bb122", + "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial", + "service": "SAP", "services": [ + "SAP", "WAF" ], - "severity": "High", - "text": "Have a regular process to upgrade the cluster node images periodically (weekly, for example)", - "waf": "Operations" + "severity": "Medium", + "text": "Implement SSO to SAP NetWeaver-based web applications like SAP Fiori and SAP Web GUI by using SAML.", + "training": "https://learn.microsoft.com/training/modules/explore-identity-services/8-exercise-integrate-azure-active-directory-sap-netweaver", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "0102ce16-ee30-41e6-b882-e52e4621dd68", - "link": "https://learn.microsoft.com/azure/architecture/example-scenario/bedrock/bedrock-automated-deployments", - "service": "AKS", + "guid": "9eb54dad-7861-4e1c-973a-f3bb003fc9c1", + "service": "SAP", "services": [ + "SAP", "WAF" ], - "severity": "Low", - "text": "Consider gitops to deploy applications or cluster configuration to multiple clusters", - "waf": "Operations" + "severity": "Medium", + "text": "Implement SSO to SAP NetWeaver-based web applications like SAP Fiori and SAP Web GUI by using SAML.", + "training": "https://learn.microsoft.com/training/modules/explore-identity-services/6-exercise-integrate-azure-active-directory-sap-fiori", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "d7672c26-7602-4482-85a4-14527fbe855c", - "link": "https://learn.microsoft.com/azure/aks/command-invoke", - "service": "AKS", + "guid": "f29676ef-0c9c-4c4d-ab21-a55504c0c829", + "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial", + "service": "SAP", "services": [ - "AKS", + "SAP", "WAF" ], - "severity": "Low", - "text": "Consider using AKS command invoke on private clusters", - "waf": "Operations" + "severity": "Medium", + "text": "You can implement SSO to SAP GUI by using SAP NetWeaver SSO or a partner solution.", + "training": "https://learn.microsoft.com/training/modules/explore-identity-services/8-exercise-integrate-azure-active-directory-sap-netweaver", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "31d7aaab-7571-4449-ab80-53d89e89d17b", - "link": "https://learn.microsoft.com/azure/aks/node-auto-repair#node-autodrain", - "service": "AKS", + "guid": "23181aa4-1742-4694-9ff8-ae7d7d474317", + "service": "SAP", "services": [ + "AKV", + "SAP", "WAF" ], - "severity": "Low", - "text": "For planned events consider using Node Auto Drain", - "waf": "Operations" + "severity": "Medium", + "text": "For SSO for SAP GUI and web browser access, implement SNC / Kerberos/SPNEGO (simple and protected GSSAPI negotiation mechanism) due to its ease of configuration and maintenance. For SSO with X.509 client certificates, consider the SAP Secure Login Server, which is a component of the SAP SSO solution.", + "training": "https://learn.microsoft.com/training/modules/explore-identity-services/9-exercise-integrate-active-directory-sap-single-sign-on", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "ed0fda7f-211b-47c7-8b6e-c18873fb473c", - "link": "https://learn.microsoft.com/azure/aks/faq", - "service": "AKS", + "guid": "6c8bcbf4-5bbe-4609-b8a0-3e97778424d6", + "link": "https://blogs.sap.com/2017/07/12/sap-single-sign-on-protect-your-sap-landscape-with-x.509-certificates/", + "service": "SAP", "services": [ + "AKV", + "SAP", "WAF" ], - "severity": "High", - "text": "Develop own governance practices to make sure no changes are performed by operators in the node RG (aka 'infra RG')", - "waf": "Operations" + "severity": "Medium", + "text": "For SSO for SAP GUI and web browser access, implement SNC / Kerberos/SPNEGO (simple and protected GSSAPI negotiation mechanism) due to its ease of configuration and maintenance. For SSO with X.509 client certificates, consider the SAP Secure Login Server, which is a component of the SAP SSO solution.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.nodeResourceGroup !startswith 'MC_') | distinct id,compliant", - "guid": "73b32a5a-67f7-4a9e-b5b3-1f38c3f39812", - "link": "https://learn.microsoft.com/azure/aks/cluster-configuration", - "service": "AKS", + "guid": "16785d6f-a96c-496a-b885-18f482734c88", + "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial#configure-sap-netweaver-for-oauth", + "service": "SAP", "services": [ + "SAP", "WAF" ], - "severity": "Low", - "text": "Use custom Node RG (aka 'Infra RG') name", - "waf": "Operations" + "severity": "Medium", + "text": "Implement SSO by using OAuth for SAP NetWeaver to allow third-party or custom applications to access SAP NetWeaver OData services.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "b2463cff-e189-4c59-adf0-d5a73dd4ce32", - "link": "https://kubernetes.io/docs/setup/release/notes/", - "service": "AKS", + "guid": "a747c350-8d4c-449c-93af-393dbca77c48", + "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/saphana-tutorial", + "service": "SAP", "services": [ - "AKS", + "SAP", "WAF" ], "severity": "Medium", - "text": "Do not use deprecated Kubernetes APIs in your YAML manifests", - "waf": "Operations" + "text": "Implement SSO to SAP HANA", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c1881370-6f7c-44c0-b4e5-14648d2457ed", - "link": "https://learn.microsoft.com/azure-stack/aks-hci/adapt-apps-mixed-os-clusters", - "service": "AKS", + "guid": "c7bae5bf-daf9-4761-9c56-f92891890aa4", + "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration#connectivity-with-sap-rise", + "service": "SAP", "services": [ + "SAP", + "Entra", "WAF" ], - "severity": "Low", - "text": "Taint Windows nodes", - "waf": "Operations" + "severity": "Medium", + "text": "Consider Azure AD an identity provider for SAP systems hosted on RISE. For more information, see Integrating the Service with Azure AD.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "67138b82-0102-4ce1-9ee3-01e6e882e52e", - "link": "https://learn.microsoft.com/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-20H2%2Cwindows-10-20H2", - "service": "AKS", + "guid": "e4e48226-ce54-44b6-bb6b-bfa15bd8f753", + "link": "https://github.com/azuredevcollege/SAP/blob/master/sap-oauth-saml-flow/README.md", + "service": "SAP", "services": [ + "SAP", "WAF" ], - "severity": "Low", - "text": "Keep windows containers patch level in sync with host patch level", - "waf": "Operations" + "severity": "Medium", + "text": "For applications that access SAP, you might want to use principal propagation to establish SSO.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Via Diagnostic Settings at the cluster level", - "guid": "5b56ad48-408f-4e72-934c-476ba280dcf5", - "link": "https://learn.microsoft.com/azure/aks/monitor-aks", - "service": "AKS", + "guid": "59921095-4980-4fc1-a5b6-524a5a560c79", + "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-hana-cloud-platform-identity-authentication-tutorial", + "service": "SAP", "services": [ - "WAF", - "Monitor" + "SAP", + "Entra", + "WAF" ], - "severity": "Low", - "text": "Send master logs (aka API logs) to Azure Monitor or your preferred log management solution", - "waf": "Operations" + "severity": "Medium", + "text": "If you're using SAP BTP services or SaaS solutions that require SAP Identity Authentication Service (IAS), consider implementing SSO between SAP Cloud Identity Authentication Services and Azure AD to access those SAP services. This integration lets SAP IAS act as a proxy identity provider and forwards authentication requests to Azure AD as the central user store and identity provider.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "64d1a846-e28a-4b6b-9a33-22a635c15a21", - "link": "https://learn.microsoft.com/azure/aks/node-pool-snapshot", - "service": "AKS", + "guid": "a709c664-317e-41e4-9e34-67d9016a86f4", + "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-hana-cloud-platform-tutorial", + "service": "SAP", "services": [ + "SAP", "WAF" ], - "severity": "Low", - "text": "If required use nodePool snapshots", - "waf": "Cost" + "severity": "Medium", + "text": "Implement SSO to SAP BTP", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c5a5b252-1e44-4a59-a9d2-399c4d7b68d0", - "link": "https://learn.microsoft.com/azure/aks/spot-node-pool", - "service": "AKS", + "guid": "01f11b7f-38df-4251-9c76-4dec19abd3e8", + "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-successfactors-inbound-provisioning-cloud-only-tutorial", + "service": "SAP", "services": [ + "SAP", + "Entra", "WAF" ], - "severity": "Low", - "text": "Consider spot node pools for non time-sensitive workloads", - "waf": "Operations" + "severity": "Medium", + "text": "If you're using SAP SuccessFactors, consider using the Azure AD automated user provisioning. With this integration, as you add new employees to SAP SuccessFactors, you can automatically create their user accounts in Azure AD. Optionally, you can create user accounts in Microsoft 365 or other SaaS applications that are supported by Azure AD. Use write-back of the email address to SAP SuccessFactors.", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.addonProfiles.aciConnectorLinux) and properties.addonProfiles.aciConnectorLinux.enabled==true) | distinct id,compliant", - "guid": "c755562f-2b4e-4456-9b4d-874a748b662e", - "link": "https://learn.microsoft.com/azure/aks/concepts-scale", - "service": "AKS", + "description": "Keep your management group hierarchy reasonably flat, no more than four.", + "graph": "resourcecontainers| where type =~ 'microsoft.resources/subscriptions'| extend ManagementGroup = tostring(tags),mgmtChain = properties.managementGroupAncestorsChain| extend compliant =( array_length(mgmtChain) <= 4 and array_length(mgmtChain) > 1)", + "guid": "6ba28021-4591-4147-9e39-e5309cccd979", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups", + "service": "SAP", "services": [ - "AKS", + "Subscriptions", + "SAP", + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "Consider AKS virtual node for quick bursting", + "severity": "Medium", + "text": "enforce existing Management Group policies to SAP Subscriptions", + "training": "https://learn.microsoft.com/training/modules/enterprise-scale-organization/4-management-group-subscription-organization", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "6f8389a7-f82c-4b8e-a8c0-aa63a25a4956", - "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-overview", - "service": "AKS", + "graph": "Resources | summarize count()", + "guid": "366bcda2-750a-4b1a-a039-d95d54c7c892", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "service": "SAP", "services": [ - "WAF", - "Monitor" + "Subscriptions", + "SAP", + "WAF" ], "severity": "High", - "text": "Monitor your cluster metrics with Container Insights (or other tools like Prometheus)", + "text": "Integrate tightly coupled applications into the same SAP subscription to avoid additional routing and management complexity", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-subscriptions", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.addonProfiles.omsagent) and properties.addonProfiles.omsagent.enabled==true) | distinct id,compliant", - "guid": "eaa8dc4a-2436-47b3-9697-15b1752beee0", - "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-overview", - "service": "AKS", + "graph": "Resources | where type contains 'publicIPAddresses' and isnotempty(properties.ipAddress) | summarize count () by subscriptionId", + "guid": "9cb107d5-325a-4e52-9ba3-4d4685e2213a", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "service": "SAP", "services": [ + "Subscriptions", "WAF" ], "severity": "High", - "text": "Store and analyze your cluster logs with Container Insights (or other tools like Telegraf/ElasticSearch)", + "text": "Leverage Subscription as scale unit and scaling our resources, consider deploying subscription per environment eg. Sandbox, non-prod, prod ", + "training": "https://learn.microsoft.com/training/modules/configure-subscriptions/?source=recommendations", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "4621dd68-c5a5-4be2-bdb1-1726769ef669", - "link": "https://learn.microsoft.com/azure/azure-monitor/containers/container-insights-analyze", - "service": "AKS", + "graph": "QuotaResources | where type =~ 'microsoft.compute/locations/usages' | where subscriptionId in~ ('','') | mv-expand json = properties.value limit 400 | extend usagevCPUs = json.currentValue, QuotaLimit = json['limit'], quotaName = tostring(json['name'].localizedValue) | extend usagePercent = toint(usagevCPUs)*100 / toint(QuotaLimit) |where quotaName =~ 'Total Regional vCPUs' or quotaName =~ 'Total Regional Low-priority vCPUs' |project subscriptionId,quotaName,usagevCPUs,QuotaLimit,usagePercent,location,['json'] | order by ['usagePercent'] desc", + "guid": "ce7bb122-f7c9-45f0-9e15-4e3aa3592829", + "link": "https://learn.microsoft.com/azure/quotas/quotas-overview", + "service": "SAP", "services": [ - "WAF", - "Monitor" + "Subscriptions", + "VM", + "WAF" ], - "severity": "Medium", - "text": "Monitor CPU and memory utilization of the nodes", + "severity": "High", + "text": "Ensure quota increase as a part of subscription provisioning (e.g. total available VM cores within a subscription)", + "training": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "1a4835ac-9422-423e-ae80-b123081a5417", - "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", - "service": "AKS", + "guid": "ce4fab2f-433a-4d59-a5a9-3d1032e03ebc", + "link": "https://learn.microsoft.com/rest/api/reserved-vm-instances/quotaapi?branch=capacity", + "service": "SAP", "services": [ - "WAF", - "Monitor" + "WAF" ], - "severity": "Medium", - "text": "If using Azure CNI, monitor % of pod IPs consumed per node", + "severity": "Low", + "text": "The Quota API is a REST API that you can use to view and manage quotas for Azure services. Consider using it if necessary.", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "I/O in the OS disk is a critical resource. If the OS in the nodes gets throttled on I/O, this could lead to unpredictable behavior, typically ending up in node being declared NotReady", - "guid": "415833ea-3ad3-4c2d-b733-165c3acbe04b", - "link": "https://learn.microsoft.com/azure/virtual-machines/premium-storage-performance", - "service": "AKS", + "guid": "cbfad17b-f240-42bf-a1d8-f4f4cee661c8", + "link": "https://learn.microsoft.com/azure/quotas/quickstart-increase-quota-portal", + "service": "SAP", "services": [ - "ServiceBus", - "Storage", - "EventHubs", - "Monitor", + "Subscriptions", + "VM", "WAF" ], - "severity": "Medium", - "text": "Monitor OS disk queue depth in nodes", + "severity": "High", + "text": "If deploying to an availability zone, ensure that the VM's zone deployment is available once the quota has been approved. Submit a support request with the subscription, VM series, number of CPUs and availability zone required.", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "be209d39-fda4-4777-a424-d116785c2fa5", - "link": "https://learn.microsoft.com/azure/aks/load-balancer-standard", - "service": "AKS", + "guid": "e6e20617-3686-4af4-9791-f8935ada4332", + "link": "https://azure.microsoft.com/explore/global-infrastructure/products-by-region/", + "service": "SAP", "services": [ - "NVA", - "LoadBalancer", - "WAF", - "Monitor" + "WAF" ], - "severity": "Medium", - "text": "If not using egress filtering with AzFW/NVA, monitor standard ALB allocated SNAT ports", + "severity": "High", + "text": "Ensure required services and features are available within the chosen deployment regions eg. ANF , Zone etc.", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/migrate/azure-best-practices/multiple-regions?source=recommendations", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "74c2ee76-569b-4a79-a57e-dedf91b022c9", - "link": "https://learn.microsoft.com/azure/aks/aks-resource-health", - "service": "AKS", + "graph": "resources | extend compliant = isnotnull(['tags']) | project name, id, subscriptionId, resourceGroup, tags, compliant", + "guid": "4e138115-2318-41aa-9174-26943ff8ae7d", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-resource-organization", + "service": "SAP", "services": [ - "AKS", + "Cost", + "TrafficManager", "WAF" ], "severity": "Medium", - "text": "Subscribe to resource health notifications for your AKS cluster", + "text": "Leverage Azure resource tag for cost categorization and resource grouping (: BillTo, Department (or Business Unit), Environment (Production, Stage, Development), Tier (Web Tier, Application Tier), Application Owner, ProjectName)", + "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "b54eb2eb-03dd-4aa3-9927-18e2edb11726", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-scheduler", - "service": "AKS", + "guid": "2f7c95f0-6e15-44e3-aa35-92829e6e2061", + "link": "https://learn.microsoft.com/azure/backup/sap-hana-database-about", + "service": "SAP", "services": [ + "Backup", "WAF" ], "severity": "High", - "text": "Configure requests and limits in your pod specs", - "waf": "Operations" + "text": "Help protect your HANA database by using the Azure Backup service.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-backup-sap-workloads-azure-virtual-machines/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "769ef669-1a48-435a-a942-223ece80b123", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-scheduler", - "service": "AKS", + "guid": "302a2fbf-3745-4a5f-a365-c9d1a16ca22c", + "link": "https://learn.microsoft.com/azure/azure-netapp-files/azacsnap-introduction", + "service": "SAP", "services": [ + "Storage", + "VM", + "Entra", "WAF" ], "severity": "Medium", - "text": "Enforce resource quotas for namespaces", - "waf": "Operations" - }, - { - "arm-service": "microsoft.containerservice/managedClusters", - "checklist": "WAF checklist", - "guid": "081a5417-4158-433e-a3ad-3c2de733165c", - "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits", - "service": "AKS", - "services": [ - "Subscriptions", - "WAF" - ], - "severity": "High", - "text": "Ensure your subscription has enough quota to scale out your nodepools", - "waf": "Operations" + "text": "If you deploy Azure NetApp Files for your HANA, Oracle, or DB2 database, use the Azure Application Consistent Snapshot tool (AzAcSnap) to take application-consistent snapshots. AzAcSnap also supports Oracle databases. Consider using AzAcSnap on a central VM rather than on individual VMs.", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "f4fd0602-7ab5-46f1-b66a-e9dea9654a65", - "link": "https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/", - "service": "AKS", + "guid": "42d37218-a3a7-45df-bff6-1173e7f249ea", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-management-and-monitoring", + "service": "SAP", "services": [ + "SAP", "WAF" ], "severity": "High", - "text": "Configure Liveness and Readiness probes for all deployments", + "text": "Ensure time-zone matches between the operating system and the SAP system.", "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.autoScalerProfile)) | distinct id,compliant", - "guid": "90ce65de-8e13-4f9c-abd4-69266abca264", - "link": "https://learn.microsoft.com/azure/aks/concepts-scale", - "service": "AKS", + "guid": "c3c7abc0-716c-4486-893c-40e181d65539", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel-multi-sid", + "service": "SAP", "services": [ + "Entra", "WAF" ], "severity": "Medium", - "text": "Use the Cluster Autoscaler", - "waf": "Performance" + "text": "Don't group different application services in the same cluster. For example, don't combine DRBD and central services clusters on the same cluster. However, you can use the same Pacemaker cluster to manage approximately five different central services (multi-SID cluster).", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.austoscalerProfile)) | distinct id,compliant", - "guid": "831c2872-c693-4b39-a887-a561bada49bc", - "link": "https://learn.microsoft.com/azure/aks/custom-node-configuration", - "service": "AKS", + "guid": "a491dfc4-9353-4213-9217-eef0949f9467", + "link": "https://azure.microsoft.com/pricing/offers/dev-test/", + "service": "SAP", "services": [ - "AKS", + "Cost", "WAF" ], "severity": "Low", - "text": "Customize node configuration for AKS node pools", - "waf": "Performance" + "text": "Consider running dev/test systems in a snooze model to save and optimize Azure run costs.", + "waf": "Cost" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "faa19bfe-9d55-4d04-a3c4-919ca1b2d121", - "link": "https://learn.microsoft.com/azure/aks/concepts-scale", - "service": "AKS", + "guid": "b7056168-6199-4732-a514-cdbb2d5c9c54", + "link": "https://learn.microsoft.com/azure/lighthouse/overview", + "service": "SAP", "services": [ + "SAP", + "Entra", "WAF" ], "severity": "Medium", - "text": "Use the Horizontal Pod Autoscaler when required", - "waf": "Performance" + "text": "If you partner with customers by managing their SAP estates, consider Azure Lighthouse. Azure Lighthouse allows managed service providers to use Azure native identity services to authenticate to the customers' environment. It puts the control in the hands of customers, because they can revoke access at any time and audit service providers' actions.", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Larger nodes will bring higher performance and features such as ephemeral disks and accelerated networking, but they will increase the blast radius and decrease the scaling granularity", - "guid": "5ae124ba-34df-4585-bcdc-e9bd3bb0cdb3", - "link": "https://blog.cloudtrooper.net/2020/10/23/which-vm-size-should-i-choose-as-aks-node/", - "service": "AKS", + "guid": "4d116785-d2fa-456c-96ad-48408fe72734", + "link": "https://learn.microsoft.com/azure/update-manager/scheduled-patching?tabs=schedule-updates-single-machine%2Cschedule-updates-scale-overview", + "service": "SAP", "services": [ + "VM", "WAF" ], - "severity": "High", - "text": "Consider an appropriate node size, not too large or too small", - "waf": "Performance" + "severity": "Medium", + "text": "Use Azure Update Manager to check the status of available updates for a single VM or multiple VMs and consider scheduling regular patching.", + "training": "https://learn.microsoft.com/training/modules/keep-your-virtual-machines-updated/?source=recommendations", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "38800e6a-ae01-40a2-9fbc-ae5a06e5462d", - "link": "https://learn.microsoft.com/azure/aks/quotas-skus-regions#service-quotas-and-limits", - "service": "AKS", + "guid": "76c8bcbf-45bb-4e60-ad8a-03e97778424d", + "link": "https://learn.microsoft.com/azure/sap/workloads/lama-installation", + "service": "SAP", "services": [ - "AKS", + "SAP", "WAF" ], "severity": "Low", - "text": "If more than 5000 nodes are required for scalability then consider using an additional AKS cluster", - "waf": "Performance" + "text": "Optimize and manage SAP Basis operations by using SAP Landscape Management (LaMa). Use the SAP LaMa connector for Azure to relocate, copy, clone, and refresh SAP systems.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-remote-management/?source=recommendations", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9583c0f6-6083-43f6-aa6b-df7102c901bb", - "link": "https://learn.microsoft.com/azure/event-grid/event-schema-aks", - "service": "AKS", + "guid": "14591147-5e39-4e53-89cc-cd979366bcda", + "link": "https://learn.microsoft.com/azure/sap/monitor/about-azure-monitor-sap-solutions", + "service": "SAP", "services": [ - "AKS", + "SAP", + "Monitor", + "SQL", "WAF" ], - "severity": "Low", - "text": "Consider subscribing to EventGrid Events for AKS automation", - "waf": "Performance" + "severity": "Medium", + "text": "Use Azure Monitor for SAP solutions to monitor your SAP workloads(SAP HANA, high-availability SUSE clusters, and SQL systems) on Azure. Consider supplementing Azure Monitor for SAP solutions with SAP Solution Manager.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c5016d8c-c6c9-4165-89ae-673ef0fff19d", - "link": "https://learn.microsoft.com/azure/aks/manage-abort-operations", - "service": "AKS", + "guid": "2750ab1a-b039-4d95-b54c-7c8929cb107d", + "link": "https://learn.microsoft.com/azure/sap/workloads/vm-extension-for-sap", + "service": "SAP", "services": [ - "AKS", - "WAF" + "Monitor", + "SAP", + "WAF", + "VM", + "Entra" ], - "severity": "Low", - "text": "For long running operation on an AKS cluster consider event termination", - "waf": "Performance" + "severity": "High", + "text": "Run a VM Extension for SAP check. VM Extension for SAP uses the assigned managed identity of a virtual machine (VM) to access VM monitoring and configuration data. The check ensures that all performance metrics in your SAP application come from the underlying Azure Extension for SAP.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-enhanced-monitoring-extension-for-sap/?source=recommendations", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c4e37133-f186-4ce1-aed9-9f1b32f6e021", - "link": "https://learn.microsoft.com/azure/aks/use-azure-dedicated-hosts", - "service": "AKS", + "guid": "5325ae52-5ba3-44d4-985e-2213ace7bb12", + "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", + "service": "SAP", "services": [ - "AKS", + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "If required consider using Azure Dedicated Hosts for AKS nodes", - "waf": "Performance" + "severity": "Medium", + "text": "Use Azure Policy for access control and compliance reporting. Azure Policy provides the ability to enforce organization-wide settings to ensure consistent policy adherence and fast violation detection. ", + "training": "https://learn.microsoft.com/learn/paths/architect-infrastructure-operations/", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "where type=='microsoft.containerservice/managedclusters' | project id,resourceGroup,name,pools=properties.agentPoolProfiles | mvexpand pools | extend compliant = (pools.osDiskType=='Ephemeral') | project id,name=strcat(name,'-',pools.name), resourceGroup, compliant", - "guid": "24367b33-6971-45b1-952b-eee0b9b588de", - "link": "https://learn.microsoft.com/azure/aks/cluster-configuration", - "service": "AKS", + "guid": "523181aa-4174-4269-93ff-8ae7d7d47431", + "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-overview", + "service": "SAP", "services": [ + "SAP", + "NetworkWatcher", + "Monitor", "WAF" ], - "severity": "High", - "text": "Use ephemeral OS disks", - "waf": "Performance" + "severity": "Medium", + "text": "Use Connection Monitor in Azure Network Watcher to monitor latency metrics for SAP databases and application servers. Or collect and display network latency measurements by using Azure Monitor.", + "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/collecting-and-displaying-niping-network-latency-measurements/ba-p/1833979", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "f0ce315f-1120-4166-8206-94f2cf3a4d07", - "link": "https://learn.microsoft.com/azure/virtual-machines/disks-types", - "service": "AKS", + "guid": "73686af4-6791-4f89-95ad-a43324e13811", + "link": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/QualityCheck", + "service": "SAP", "services": [ - "AKS", + "VM", + "SAP", "WAF" ], - "severity": "High", - "text": "For non-ephemeral disks, use high IOPS and larger OS disks for the nodes when running many pods/node since it requires high performance for running multiple pods and will generate huge logs with default AKS log rotation thresholds", - "waf": "Performance" + "severity": "Medium", + "text": "Perform a quality check for SAP HANA on the provisioned Azure infrastructure to verify that provisioned VMs comply with SAP HANA on Azure best practices.", + "waf": "Operations" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "39c486ce-d5af-4062-89d5-18bb5fd795db", - "link": "https://learn.microsoft.com/azure/aks/use-ultra-disks", - "service": "AKS", + "guid": "616785d6-fa96-4c96-ad88-518f482734c8", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-zones", + "service": "SAP", "services": [ - "Storage", - "AKS", + "Subscriptions", + "SAP", "WAF" ], - "severity": "Low", - "text": "For hyper performance storage option use Ultra Disks on AKS", + "severity": "High", + "text": "For each Azure subscription, run a latency test on Azure availability zones before zonal deployment to choose low-latency zones for deployment of SAP on Azure.", + "training": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/AvZone-Latency-Test", "waf": "Performance" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9f7547c1-747d-4c56-868a-714435bd19dd", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-multi-region", - "service": "AKS", + "guid": "410adcba-db46-424f-a6c4-05ecde75c52e", + "link": "https://learn.microsoft.com/azure/advisor/advisor-how-to-improve-reliability", + "service": "SAP", "services": [ "Storage", - "SQL", + "ASR", "WAF" ], "severity": "Medium", - "text": "Avoid keeping state in the cluster, and store data outside (AzStorage, AzSQL, Cosmos, etc)", - "waf": "Performance" + "text": "Run the Resiliency Report to ensure that the configuration of the entire provisioned Azure infrastructure (Compute, Database, Networking, Storage, Site Recovery) complies with the configuration defined by Cloud Adaption Framework for Azure.", + "training": "https://learn.microsoft.com/training/paths/azure-well-architected-framework/", + "waf": "Reliability" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "24429eb7-2281-4376-85cc-57b4a4b18142", - "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-storage", - "service": "AKS", + "guid": "86ba2802-1459-4114-95e3-9e5309cccd97", + "link": "https://learn.microsoft.com/azure/sentinel/sap/deployment-overview", + "service": "SAP", "services": [ - "Storage", + "Sentinel", + "SAP", + "Monitor", "WAF" ], "severity": "Medium", - "text": "If using AzFiles Standard, consider AzFiles Premium and/or ANF for performance reasons", - "waf": "Performance" + "text": "Implement threat protection by using the Microsoft Sentinel solution for SAP. Use this solution to monitor your SAP systems and detect sophisticated threats throughout the business logic and application layers.", + "training": "https://learn.microsoft.com/training/modules/plan-microsoft-sentinel-deployment-sap/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "83958a8c-2689-4b32-ab57-cfc64546135a", - "link": "https://learn.microsoft.com/azure/aks/availability-zones#azure-disk-availability-zone-support", - "service": "AKS", + "graph": "resources | extend compliant = isnotnull(['tags']) | project name, id, subscriptionId, resourceGroup, tags, compliant", + "guid": "579266bc-ca27-45fa-a1ab-fe9d55d04c3c", + "link": "https://learn.microsoft.com/azure/cost-management-billing/costs/enable-tag-inheritance", + "service": "SAP", "services": [ - "Storage", + "Cost", "WAF" ], "severity": "Medium", - "text": "If using Azure Disks and AZs, consider having nodepools within a zone for LRS disk with VolumeBindingMode:WaitForFirstConsumer for provisioning storage in right zone or use ZRS disk for nodepools spanning multiple zones", + "text": "Azure tagging can be leveraged to logically group and track resources, automate their deployments, and most importantly, provide visibility on the incurred costs.", + "training": "https://learn.microsoft.com/training/modules/analyze-costs-create-budgets-azure-cost-management/?source=recommendations", + "waf": "Operations" + }, + { + "checklist": "WAF checklist", + "guid": "04b8e5e5-13cb-4b22-af62-5a8ecfcf0337", + "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-test-latency?tabs=windows", + "service": "SAP", + "services": [ + "VM", + "Monitor", + "WAF" + ], + "severity": "Low", + "text": "Use inter-VM latency monitoring for latency-sensitive applications.", "waf": "Performance" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "7bc1c396-2461-4698-b57f-30ca69525252", - "link": "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/considerations/regions", - "service": "VNet", + "guid": "07e5ed53-3d96-43d8-87ea-631b77da5aba", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-guide-storage", + "service": "SAP", "services": [ "ASR", + "SAP", + "Monitor", "WAF" ], "severity": "Medium", - "text": "Deploy your Azure landing zone connectivity resources in multiple regions, so that you can quickly support multi-region application landing zones and disaster recovery scenarios.", - "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", + "text": "Use Azure Site Recovery monitoring to maintain the health of the disaster recovery service for SAP application servers.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-storage/?source=recommendations", "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "70c15989-c726-42c7-b0d3-24b7375b9201", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/considerations-recommendations", - "service": "Entra", + "guid": "abb6af9c-982c-4cf1-83fb-329fafd1ee56", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-management-and-monitoring", + "service": "SAP", "services": [ - "WAF", - "Entra" + "Storage", + "SAP", + "WAF" ], "severity": "Medium", - "text": "Use one Entra tenant for managing your Azure resources, unless you have a clear regulatory or business requirement for multi-tenants.", - "training": "https://learn.microsoft.com/training/modules/deploy-resources-scopes-bicep/2-understand-deployment-scopes", - "waf": "Operations" + "text": "Exclude all the database file systems and executable programs from antivirus scans. Including them could lead to performance problems. Check with the database vendors for prescriptive details on the exclusion list. For example, Oracle recommends excluding /oracle//sapdata from antivirus scans.", + "waf": "Performance" }, { "checklist": "WAF checklist", - "guid": "6309957b-821a-43d1-b9d9-7fcf1802b747", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/automation", - "service": "Entra", + "guid": "c027f893-f404-41a9-b33d-39d625a14964", + "link": "https://sapit-forme-prod.authentication.eu11.hana.ondemand.com/login", + "service": "SAP", "services": [ - "WAF", - "Entra" + "SAP", + "WAF" ], "severity": "Low", - "text": "Use Multi-Tenant Automation approach to managing your Microsoft Entra ID Tenants.", - "training": "https://learn.microsoft.com/entra/architecture/multi-tenant-user-management-introduction/", - "waf": "Operations" + "text": "Consider collecting full database statistics for non-HANA databases after migration. For example, implement SAP note 1020260 - Delivery of Oracle statistics.", + "waf": "Performance" }, { "checklist": "WAF checklist", - "guid": "78e11934-499a-45ed-8ef7-aae5578f0ecf", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/lighthouse", - "service": "Entra", + "guid": "fdafb1f5-3eee-4354-a8c9-deb8127ebc2e", + "link": "https://learn.microsoft.com/azure/virtual-machines/workloads/oracle/configure-oracle-asm", + "service": "SAP", "services": [ + "Storage", + "SAP", "WAF" ], - "severity": "High", - "text": "Use Azure Lighthouse for Multi-Tenant Management with the same IDs.", - "training": "https://learn.microsoft.com/azure/lighthouse/concepts/cross-tenant-management-experience", - "waf": "Operations" + "severity": "Medium", + "text": "Consider using Oracle Automatic Storage Management (ASM) for all Oracle deployments that use SAP on Azure.", + "training": "https://learn.microsoft.com/training/paths/administer-infrastructure-resources-in-azure/?source=recommendations", + "waf": "Performance" }, { "checklist": "WAF checklist", - "guid": "5d82e6df-6f61-42f2-82e2-3132d293be3d", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", - "service": "Entra", + "guid": "33c5d5bf-daf3-4f0d-bd50-6010fdcec22e", + "link": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/announcement-sap-on-azure-oracle-performance-efficiency-scripts/ba-p/3725178", + "service": "SAP", "services": [ + "SAP", + "SQL", "WAF" ], - "severity": "High", - "text": "If you give a partner access to administer your tenant, use Azure Lighthouse.", - "training": "https://learn.microsoft.com/azure/lighthouse/how-to/onboard-customer", - "waf": "Cost" + "severity": "Medium", + "text": "For SAP on Azure running Oracle, a collection of SQL scripts can help you diagnose performance problems. Automatic Workload Repository (AWR) reports contain valuable information for diagnosing problems in the Oracle system. We recommend that you run an AWR report during several sessions and choose peak times for it, to ensure broad coverage for the analysis.", + "training": "https://learn.microsoft.com/ja-jp/azure/well-architected/oracle-iaas/performance-efficiency", + "waf": "Performance" }, { "checklist": "WAF checklist", - "guid": "348ef254-c27d-442e-abba-c7571559ab91", - "link": "https://learn.microsoft.com/azure/role-based-access-control/overview", - "service": "Entra", + "guid": "d89fd98d-23e4-4b40-a92e-32db9365522c", + "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-monitor-and-troubleshoot", + "service": "SAP", "services": [ - "RBAC", - "Subscriptions", - "WAF", - "ACR" + "ASR", + "SAP", + "Monitor", + "WAF" ], "severity": "High", - "text": "Enforce a RBAC model that aligns to your cloud operating model. Scope and Assign across Management Groups and Subscriptions.", - "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", - "waf": "Security" + "text": "Use Azure Site Recovery monitoring to maintain the health of the disaster recovery service for SAP application servers.", + "training": "https://learn.microsoft.com/training/modules/protect-on-premises-infrastructure-with-azure-site-recovery/?source=recommendations", + "waf": "Operations" }, { "checklist": "WAF checklist", - "guid": "12e7f983-f630-4472-8dd6-9c5b5c2622f5", - "link": "https://learn.microsoft.com/azure/active-directory/roles/security-planning#identify-microsoft-accounts-in-administrative-roles-that-need-to-be-switched-to-work-or-school-accounts", - "service": "Entra", + "guid": "5ba34d46-85e2-4213-ace7-bb122f7c95f0", + "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", + "service": "SAP", "services": [ + "AppGW", + "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Only use the authentication type Work or school account for all account types. Avoid using the Microsoft account", - "training": "https://learn.microsoft.com/learn/modules/explore-basic-services-identity-types/", + "text": "For secure delivery of HTTP/S apps, use Application Gateway v2 and ensure that WAF protection and policies are enabled.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/", "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "4b69bad3-3aad-45e8-a68e-1d76667313b4", - "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-groups-create-azure-portal", - "service": "Entra", + "guid": "fa9d30bc-1b82-4e4b-bfdf-6b017938b9e6", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", + "service": "SAP", "services": [ - "WAF", - "Entra" + "DNS", + "VM", + "SAP", + "WAF" ], "severity": "Medium", - "text": "Only use groups to assign permissions. Add on-premises groups to the Entra ID only group if a group management system is already in place.", - "training": "https://learn.microsoft.com/learn/paths/manage-identity-and-access/", - "waf": "Security" + "text": "If the virtual machine's DNS or virtual name is not changed during migration to Azure, Background DNS and virtual names connect many system interfaces in the SAP landscape, and customers are only sometimes aware of the interfaces that developers define over time. Connection challenges arise between various systems when virtual or DNS names change after migrations, and it's recommended to retain DNS aliases to prevent these types of difficulties.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/4-explore-name-resolution", + "waf": "Operations" }, { "checklist": "WAF checklist", - "guid": "53e8908a-e28c-484c-93b6-b7808b9fe5c4", - "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/overview", - "service": "Entra", + "guid": "a2858f78-105b-4f52-b7a9-5b0f4439743b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", + "service": "SAP", "services": [ - "AzurePolicy", - "WAF", - "Entra" + "DNS", + "VNet", + "SAP", + "WAF" ], - "severity": "High", - "text": "Enforce Microsoft Entra ID Conditional Access policies for any user with rights to Azure environments.", - "training": "https://learn.microsoft.com/learn/modules/plan-implement-administer-conditional-access/", - "waf": "Security" + "severity": "Medium", + "text": "Use different DNS zones to distinguish each environment (sandbox, development, preproduction, and production) from each other. The exception is for SAP deployments with their own VNet; here, private DNS zones might not be necessary.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/4-explore-name-resolution", + "waf": "Operations" }, { "checklist": "WAF checklist", - "guid": "1049d403-a923-4c34-94d0-0018ac6a9e01", - "link": "https://learn.microsoft.com/azure/active-directory/authentication/concept-mfa-howitworks", - "service": "Entra", + "description": "When configuring VNet peering, use the Allow traffic to remote virtual networks setting.", + "graph": "resources | where type =~ 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess =~ True)", + "guid": "a3592829-e6e2-4061-9368-6af46791f893", + "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-peering-overview", + "service": "SAP", "services": [ + "ACR", + "VNet", + "SAP", "WAF" ], - "severity": "High", - "text": "Enforce multi-factor authentication for any user with rights to the Azure environments.", - "training": "https://learn.microsoft.com/entra/identity/authentication/concept-mandatory-multifactor-authentication", - "waf": "Security" + "severity": "Medium", + "text": "Local and global VNet peering provide connectivity and are the preferred approaches to ensure connectivity between landing zones for SAP deployments across multiple Azure regions", + "training": "https://learn.microsoft.com/training/modules/configure-vnet-peering/?source=recommendations", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "14658d35-58fd-4772-99b8-21112df27ee4", - "link": "https://learn.microsoft.com/azure/active-directory/privileged-identity-management/pim-configure", - "service": "Entra", + "guid": "41742694-3ff8-4ae7-b7d4-743176c8bcbf", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-guide", + "service": "SAP", "services": [ - "WAF", - "Entra" + "NVA", + "SAP", + "WAF" ], - "severity": "Medium", - "text": "Enforce Microsoft Entra ID Privileged Identity Management (PIM) to establish zero standing access and least privilege.", - "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", - "waf": "Security" + "severity": "High", + "text": "It is not supported to deploy any NVA between SAP application and SAP Database server", + "training": "https://me.sap.com/notes/2731110", + "waf": "Performance" }, { "checklist": "WAF checklist", - "guid": "8b9fe5c4-1049-4d40-9a92-3c3474d00018", - "link": "https://learn.microsoft.com/entra/identity/domain-services/overview", - "service": "Entra", + "graph": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic =~ 'true') | distinct id,compliant", + "guid": "7d4bc7d2-c34a-452e-8f1d-6ae3c8eafcc3", + "link": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/?source=recommendations", + "service": "SAP", "services": [ - "WAF", - "Entra" + "ACR", + "SAP", + "VWAN", + "WAF" ], "severity": "Medium", - "text": "If planning to switch from Active Directory Domain Services to Entra domain services, evaluate the compatibility of all workloads.", - "training": "https://learn.microsoft.com/learn/modules/implement-hybrid-identity-windows-server/", - "waf": "Security" + "text": "Use Virtual WAN for Azure deployments in new, large, or global networks where you need global transit connectivity across Azure regions and on-premises locations. With this approach, you won't need to manually set up transitive routing for Azure networking, and you can follow a standard for SAP on Azure deployments.", + "training": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about", + "waf": "Operations" }, { "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.aad/domainservices' | extend replicaSets = properties.replicaSets | where array_length(replicaSets) < 2 | project name=name, id=id, tags=tags, param1=strcat('replicaSetLocation:', replicaSets[0].location)", - "guid": "0dd4e625-9c4b-4a56-b54a-4357bac12761", - "link": "https://learn.microsoft.com/entra/identity/domain-services/overview", - "service": "Entra", + "guid": "0cedb1f6-ae6c-492b-8b17-8061f50b16d3", + "link": "https://learn.microsoft.com/azure/well-architected/services/networking/network-virtual-appliances/reliability", + "service": "SAP", "services": [ - "WAF", - "Entra" + "NVA", + "VNet", + "WAF" ], "severity": "Medium", - "text": "When using Microsoft Entra Domain Services use replica sets. Replica sets will improve the resiliency of your managed domain and allow you to deploy to additional regions. ", - "training": "https://learn.microsoft.com/training/modules/understand-azure-active-directory/6-examine-azure-domain-services", - "waf": "Reliability" + "text": "Consider deploying network virtual appliances (NVAs) between regions only if partner NVAs are used. NVAs between regions or VNets aren't required if native NVAs are present. When you're deploying partner networking technologies and NVAs, follow the vendor's guidance to verify conflicting configurations with Azure networking.", + "training": "https://learn.microsoft.com/training/modules/control-network-traffic-flow-with-routes/?source=recommendations", + "waf": "Operations" }, { "checklist": "WAF checklist", - "guid": "1cf0b8da-70bd-44d0-94af-8d99cfc89ae1", - "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/concept-activity-logs-azure-monitor", - "service": "Entra", + "guid": "facc08c6-ea95-4641-91cd-fa09e573adbd", + "link": "https://learn.microsoft.com/azure/architecture/networking/hub-spoke-vwan-architecture", + "service": "SAP", "services": [ - "Entra", + "NVA", "WAF", - "Monitor" + "VWAN", + "SAP", + "VNet" ], "severity": "Medium", - "text": "Integrate Microsoft Entra ID logs with the platform-central Azure Monitor. Azure Monitor allows for a single source of truth around log and monitoring data in Azure, giving organizations a cloud native options to meet requirements around log collection and retention.", - "training": "https://learn.microsoft.com/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs", - "waf": "Security" + "text": "Virtual WAN manages connectivity between spoke VNets for virtual-WAN-based topologies (no need to set up user-defined routing [UDR] or NVAs), and maximum network throughput for VNet-to-VNet traffic in the same virtual hub is 50 gigabits per second. If necessary, SAP landing zones can use VNet peering to connect to other landing zones and overcome this bandwidth limitation.", + "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/?source=recommendations", + "waf": "Operations" }, { - "ammp": true, "checklist": "WAF checklist", - "guid": "984a859c-773e-47d2-9162-3a765a917e1f", - "link": "https://learn.microsoft.com/azure/active-directory/roles/security-emergency-access", - "service": "Entra", + "graph": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)", + "guid": "82734c88-6ba2-4802-8459-11475e39e530", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", + "service": "SAP", "services": [ - "WAF", - "Entra" + "VM", + "SAP", + "WAF" ], "severity": "High", - "text": "Implement an emergency access or break-glass accounts to prevent tenant-wide account lockout. MFA will be turned on by default for all users in Oct 2024. We recommend updating these accounts to use passkey (FIDO2) or configure certificate-based authentication for MFA. ", - "training": "https://learn.microsoft.com/entra/identity/role-based-access-control/security-emergency-access#exclude-at-least-one-account-from-conditional-access-policies", + "text": "Public IP assignment to VM running SAP Workload is not recommended.", + "training": "https://learn.microsoft.com/training/modules/design-ip-addressing-for-azure/?source=recommendations", "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "35037e68-9349-4c15-b371-228514f4cdff", - "link": "https://learn.microsoft.com/azure/active-directory/roles/best-practices", - "service": "Entra", + "graph": "Resources | where type contains 'publicIPAddresses' and isnotempty(properties.ipAddress) | summarize count () by subscriptionId", + "guid": "9cccd979-366b-4cda-8750-ab1ab039d95d", + "link": "https://learn.microsoft.com/training/modules/protect-on-premises-infrastructure-with-azure-site-recovery/?source=recommendations", + "service": "SAP", "services": [ - "RBAC", - "WAF", - "Entra" + "ASR", + "WAF" ], - "severity": "Medium", - "text": "Do not use on-premises synced accounts for Microsoft Entra ID role assignments, unless you have a scenario that specifically requires it.", - "training": "https://learn.microsoft.com/learn/modules/design-identity-security-strategy/", - "waf": "Security" + "severity": "High", + "text": "Consider reserving IP address on DR side when configuring ASR", + "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", + "waf": "Operations" }, { "checklist": "WAF checklist", - "guid": "d5d1e4e6-1465-48d3-958f-d77249b82111", - "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy", - "service": "Entra", + "guid": "54c7c892-9cb1-407d-9325-ae525ba34d46", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", + "service": "SAP", "services": [ - "WAF", - "Entra" + "WAF" ], - "severity": "Medium", - "text": "When using Microsoft Entra ID Application Proxy to give remote users access to applications, manage it as a Platform resource as you can only have one instance per tenant.", - "training": "https://learn.microsoft.com/learn/paths/implement-applications-external-access-azure-ad/", - "waf": "Security" + "severity": "High", + "text": "Avoid using overlapping IP address ranges for production and DR sites.", + "training": "https://learn.microsoft.com/training/modules/design-ip-addressing-for-azure/?source=recommendations", + "waf": "Operations" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "e8bbac75-7155-49ab-a153-e8908ae28c84", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/enterprise-scale/network-topology-and-connectivity", - "service": "VNet", + "guid": "6e154e3a-a359-4282-ae6e-206173686af4", + "link": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-delegate-subnet", + "service": "SAP", "services": [ + "Storage", "VNet", "WAF" ], "severity": "Medium", - "text": "Use a hub-and-spoke network topology for network scenarios that require maximum flexibility.", - "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", - "waf": "Security" + "text": "While Azure does help you to create multiple delegated subnets in a VNet, only one delegated subnet can exist in a VNet for Azure NetApp Files. Attempts to create a new volume will fail if you use more than one delegated subnet for Azure NetApp Files.", + "training": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-network-topologies?source=recommendations", + "waf": "Operations" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "7dd61623-a364-4a90-9eca-e48ebd54cd7d", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/traditional-azure-networking-topology", - "service": "VNet", + "graph": "resources | where type=~'microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant", + "guid": "d8a03e97-7784-424d-9167-85d6fa96c96a", + "link": "https://learn.microsoft.com/azure/well-architected/services/networking/azure-firewall?toc=%2Fazure%2Ffirewall%2Ftoc.json&bc=%2Fazure%2Ffirewall%2Fbreadcrumb%2Ftoc.json", + "service": "SAP", "services": [ - "VPN", - "Entra", - "DNS", - "NVA", "Firewall", - "ExpressRoute", - "VNet", "WAF" ], - "severity": "High", - "text": "Deploy shared networking services, including ExpressRoute gateways, VPN gateways, and Azure Firewall or partner NVAs in the central-hub virtual network. If necessary, also deploy DNS services.", - "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", - "waf": "Cost" + "severity": "Medium", + "text": "Use Azure Firewall to govern Azure outbound traffic to the internet, non-HTTP/S inbound connections, and East/West traffic filtering (if the organization requires it)", + "training": "https://learn.microsoft.com/training/paths/secure-networking-infrastructure/", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "143b16c3-1d7a-4a9b-9470-4489a8042d88", - "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", - "service": "VNet", + "guid": "91a65e40-be90-45b3-9f73-f3edbf8dc324", + "link": "https://learn.microsoft.com/azure/sap/workloads/expose-sap-process-orchestration-on-azure", + "service": "SAP", "services": [ - "DDoS", + "AppGW", + "SAP", "WAF" ], - "severity": "High", - "text": "Use a DDoS Network or IP protection plan for all public IP addresses in application landing zones.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "severity": "Medium", + "text": "Application Gateway and Web Application Firewall have limitations when Application Gateway serves as a reverse proxy for SAP web apps, as shown in the comparison between Application Gateway, SAP Web Dispatcher, and other third-party services.", + "training": "https://help.sap.com/docs/SUPPORT_CONTENT/si/3362959506.html", "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "e2e8abac-3571-4559-ab91-53e89f89dc7b", - "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/nva-ha", - "service": "NVA", + "guid": "5e39e530-9ccc-4d97-a366-bcda2750ab1a", + "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", + "service": "SAP", "services": [ - "NVA", + "ACR", + "FrontDoor", + "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "When deploying partner networking technologies or NVAs, follow the partner vendor's guidance.", - "waf": "Reliability" + "text": "Use Azure Front Door and WAF policies to provide global protection across Azure regions for inbound HTTP/S connections to a landing zone.", + "training": "https://learn.microsoft.com/training/paths/secure-application-delivery/", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "ce463dbb-bc8a-4c2a-aebc-92a43da1dae2", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-coexist-resource-manager#to-enable-transit-routing-between-expressroute-and-azure-vpn", - "service": "ExpressRoute", + "guid": "b039d95d-54c7-4c89-89cb-107d5325ae52", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", + "service": "SAP", "services": [ - "VPN", - "ARS", - "ExpressRoute", + "AppGW", + "FrontDoor", + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "If you need transit between ExpressRoute and VPN gateways in hub and spoke scenarios, use Azure Route Server.", - "training": "https://learn.microsoft.com/training/modules/intro-to-azure-route-server/", + "severity": "Medium", + "text": "Take advantage of Web Application Firewall policies in Azure Front Door when you're using Azure Front Door and Application Gateway to protect HTTP/S applications. Lock down Application Gateway to receive traffic only from Azure Front Door.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations", "waf": "Security" }, { - "arm-service": "Microsoft.Network/virtualHubs", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant", - "guid": "91b9d7d5-91e1-4dcb-8f1f-fa7e465646cc", - "link": "https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1", - "service": "ARS", + "guid": "5ada4332-4e13-4811-9231-81aa41742694", + "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", + "service": "SAP", "services": [ - "ARS", - "VNet", + "AppGW", + "LoadBalancer", "WAF" ], - "severity": "Low", - "text": "If using Route Server, use a /27 prefix for the Route Server subnet.", - "training": "https://learn.microsoft.com/training/modules/intro-to-azure-route-server/", + "severity": "Medium", + "text": "Use a web application firewall to scan your traffic when it's exposed to the internet. Another option is to use it with your load balancer or with resources that have built-in firewall capabilities like Application Gateway or third-party solutions.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations", "waf": "Security" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "cc881471-607c-41cc-a0e6-14658dd558f9", - "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-faq#can-i-create-a-peering-connection-to-a-vnet-in-a-different-region", - "service": "VNet", + "guid": "e73de7d5-6f36-4217-a526-e1a621ecddde", + "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", + "service": "SAP", "services": [ - "VNet", - "WAF", - "ACR" + "ACR", + "SAP", + "VWAN", + "WAF" ], "severity": "Medium", - "text": "For network architectures with multiple hub-and-spoke topologies across Azure regions, use global virtual network peerings between the hub VNets to connect the regions to each other.", - "training": "https://learn.microsoft.com/learn/paths/azure-administrator-manage-virtual-networks/", + "text": "Use Virtual WAN for Azure deployments in new, large, or global networks where you need global transit connectivity across Azure regions and on-premises locations. With this approach, you won't need to manually set up transitive routing for Azure networking, and you can follow a standard for SAP on Azure deployments.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/10-explore-azure-front-door", "waf": "Performance" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "4722d929-c1b1-4cd6-81f5-4b29bade39ad", - "link": "https://learn.microsoft.com/azure/azure-monitor/insights/network-insights-overview", - "service": "VNet", + "guid": "3c536a3e-1b6b-4e87-95ca-15edb47251c0", + "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", + "service": "SAP", "services": [ + "ACR", "WAF", - "Monitor" + "Backup", + "Storage", + "VNet", + "PrivateLink" ], "severity": "Medium", - "text": "Use Azure Monitor for Networks to monitor the end-to-end state of the networks on Azure.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/", - "waf": "Operations" + "text": "To prevent data leakage, use Azure Private Link to securely access platform as a service resources like Azure Blob Storage, Azure Files, Azure Data Lake Storage Gen2, Azure Data Factory, and more. Azure Private Endpoint can also help to secure traffic between VNets and services like Azure Storage, Azure Backup, and more. Traffic between your VNet and the Private Endpoint enabled service travels across the Microsoft global network, which prevents its exposure to the public internet.", + "training": "https://learn.microsoft.com/training/modules/design-implement-private-access-to-azure-services/?source=recommendations", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant", - "guid": "0e7c28ec-9366-4572-83b0-f4664b1d944a", - "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits", - "service": "VNet", + "graph": "Resources | where type =~ 'Microsoft.Network/NetworkInterfaces' | where properties.enableAcceleratedNetworking =~ 'false' | project name, subscriptionId, properties.enableAcceleratedNetworking", + "guid": "85e2213a-ce7b-4b12-8f7c-95f06e154e3a", + "link": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview?tabs=redhat", + "service": "SAP", "services": [ - "ExpressRoute", - "WAF", - "VNet" + "VM", + "SAP", + "WAF" ], - "severity": "Medium", - "text": "If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000).", - "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", - "waf": "Reliability" + "severity": "High", + "text": "Make sure that Azure accelerated networking is enabled on the VMs used in the SAP application and DBMS layers.", + "training": "https://learn.microsoft.com/training/paths/azure-fundamentals-describe-azure-architecture-services/?source=recommendations", + "waf": "Performance" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant", - "guid": "3d457936-e9b7-41eb-bdff-314b26450b12", - "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits", - "service": "VNet", + "guid": "3ff8ae7d-7d47-4431-96c8-bcbf45bbe609", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-multivip-overview", + "service": "SAP", "services": [ - "Storage", + "LoadBalancer", "WAF" ], "severity": "Medium", - "text": "Limit the number of routes per route table to 400.", - "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", - "waf": "Reliability" + "text": "Make sure that internal deployments for Azure Load Balancer are set up to use Direct Server Return (DSR). This setting (Enabling Floating IP) will reduce latency when internal load balancer configurations are used for high-availability configurations on the DBMS layer.", + "training": "https://learn.microsoft.com/ja-jp/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)", - "guid": "c76cb5a2-abe2-11ed-afa1-0242ac120002", - "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering", - "service": "VNet", + "graph": "Resources | where type =~ 'microsoft.network/networksecuritygroups' and isnull(properties.networkInterfaces) and isnull(properties.subnets) | project name, resourceGroup | sort by name asc", + "guid": "6791f893-5ada-4433-84e1-3811523181aa", + "link": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", + "service": "SAP", "services": [ "VNet", + "VM", + "SAP", "WAF" ], - "severity": "High", - "text": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings.", - "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", - "waf": "Reliability" + "severity": "Medium", + "text": "You can use application security group (ASG) and NSG rules to define network security access-control lists between the SAP application and DBMS layers. ASGs group virtual machines to help manage their security.", + "training": "https://learn.microsoft.com/training/modules/configure-network-security-groups/?source=recommendations", + "waf": "Security" }, { "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName)", - "guid": "9dcd6250-9c4a-4382-aa9b-5b84c64fc1fe", - "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant", - "service": "Load Balancers", + "guid": "45bbe609-d8a0-43e9-9778-424d616785d6", + "link": "https://me.sap.com/notes/2015553", + "service": "SAP", "services": [ - "LoadBalancer", + "VNet", + "SAP", "WAF" ], "severity": "High", - "text": "Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA.", - "waf": "Reliability" + "text": "Placing of the SAP application layer and SAP DBMS in different Azure VNets that aren't peered isn't supported.", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", + "waf": "Performance" }, { "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses))", - "guid": "48682fb1-1e86-4458-a686-518ebd47393d", - "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant", - "service": "Load Balancers", + "guid": "fa96c96a-d885-418f-9827-34c886ba2802", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "service": "SAP", "services": [ - "LoadBalancer", + "SAP", "WAF" ], - "severity": "High", - "text": "Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability.", - "waf": "Reliability" + "severity": "Medium", + "text": "For optimal network latency with SAP applications, consider using Azure proximity placement groups.", + "training": "https://learn.microsoft.com/azure/virtual-machines/co-location#planned-maintenance-and-proximity-placement-groups", + "waf": "Performance" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "de0d5973-cd4c-4d21-a088-137f5e6c4cfd", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-macsec", - "service": "ExpressRoute", + "guid": "18c8b61c-855a-4405-b6ed-266455e4f4ce", + "link": "https://me.sap.com/notes/2015553", + "service": "SAP", "services": [ - "ExpressRoute", + "SAP", "WAF" ], - "severity": "Medium", - "text": "When you're using ExpressRoute Direct, configure MACsec in order to encrypt traffic at the layer-two level between the organization's routers and MSEE. The diagram shows this encryption in flow.", - "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", - "waf": "Security" + "severity": "High", + "text": "It is NOT supported at all to run an SAP Application Server layer and DBMS layer split between on-premise and Azure. Both layers need to completely reside either on-premise or in Azure.", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", + "waf": "Performance" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "ed301d6e-872e-452e-9611-cc58b5a4b151", - "link": "https://learn.microsoft.com/azure/vpn-gateway/site-to-site-vpn-private-peering", - "service": "ExpressRoute", + "guid": "b65c878b-4b14-4f4e-92d8-d873936493f2", + "link": "https://me.sap.com/notes/2015553", + "service": "SAP", "services": [ - "VPN", - "ExpressRoute", + "Cost", + "VNet", + "SAP", "WAF" ], - "severity": "Medium", - "text": "For scenarios where MACsec isn't an option (for example, not using ExpressRoute Direct), use a VPN gateway to establish IPsec tunnels over ExpressRoute private peering.", - "training": "https://learn.microsoft.com/learn/paths/implement-network-security/", - "waf": "Security" + "severity": "High", + "text": "It isn't recommended to host the database management system (DBMS) and application layers of SAP systems in different VNets and connect them with VNet peering because of the substantial costs that excessive network traffic between the layers can produce. Recommend using subnets within the Azure virtual network to separate the SAP application layer and DBMS layer.", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", + "waf": "Cost" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "558fd772-49b8-4211-82df-27ee412e7f98", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", - "service": "ExpressRoute", + "guid": "402a9846-d515-4061-aff8-cd30088693fa", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel", + "service": "SAP", "services": [ - "WAF", - "ACR" + "LoadBalancer", + "WAF" ], "severity": "High", - "text": "Ensure no overlapping IP address spaces across Azure regions and on-premises locations are used.", - "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", - "waf": "Security" + "text": "If using Load Balancer with Linux guest operating systems, check that the Linux network parameter net.ipv4.tcp_timestamps is set to 0.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", + "waf": "Performance" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr", - "guid": "3f630472-2dd6-49c5-a5c2-622f54b69bad", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", - "service": "VNet", + "guid": "87585797-5551-4d53-bb7d-a94ee415734d", + "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration", + "service": "SAP", "services": [ + "VNet", + "SAP", "WAF" ], "severity": "Medium", - "text": "Use IP addresses from the address allocation ranges for private internets (RFC 1918).", - "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", + "text": "For SAP RISE/ECS deployments, virtual peering is the preferred way to establish connectivity with customer's existing Azure environment. Both the SAP vnet and customer vnet(s) are protected with network security groups (NSG), enabling communication on SAP and database ports through the vnet peering", "waf": "Security" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant", - "guid": "33aad5e8-c68e-41d7-9667-313b4f5664b5", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", - "service": "VNet", + "guid": "ff5136bd-dcf1-4d2b-ae52-39333efdf45a", + "link": "https://learn.microsoft.com/azure/backup/sap-hana-database-about", + "service": "SAP", "services": [ - "VNet", + "VM", + "SAP", + "Backup", "WAF" ], "severity": "High", - "text": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16).", - "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", - "waf": "Performance" + "text": "Review SAP HANA database backups for Azure VMs.", + "waf": "Cost" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "f348ef25-4c27-4d42-b8bb-ac7571559ab9", - "link": "https://learn.microsoft.com/azure/site-recovery/concepts-on-premises-to-azure-networking#retain-ip-addresses", - "service": "VNet", + "guid": "cafde29d-a0af-4bcd-87c0-0f299d63f0e8", + "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-monitor-and-troubleshoot", + "service": "SAP", "services": [ "ASR", + "SAP", + "Monitor", "WAF" ], - "severity": "High", - "text": "Do not use overlapping IP address ranges for production and disaster recovery sites.", - "training": "https://learn.microsoft.com/learn/paths/az-104-manage-virtual-networks/", - "waf": "Reliability" + "severity": "Medium", + "text": "Review Site Recovery built-in monitoring, where used for SAP.", + "waf": "Cost" }, { "checklist": "WAF checklist", - "graph": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)", - "guid": "0c47f486-656d-4699-8c30-edef5b8a93c4", - "link": "https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone", - "service": "Public IP Addresses", + "guid": "82d7b8de-d3f1-44a0-830b-38e200e82acf", + "link": "https://help.sap.com/docs/SAP_HANA_PLATFORM/c4d7c773af4a4e5dbebb6548d6e2d4f4/e3111d2ebb5710149510cc120646bf3f.html?locale=en-US", + "service": "SAP", "services": [ - "WAF", - "ACR" + "SAP", + "Monitor", + "WAF" ], "severity": "High", - "text": "Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. ", - "training": "https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing", - "waf": "Reliability" + "text": "Review the Monitoring the SAP HANA System Landscape guidance.", + "waf": "Operations" }, { - "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "153e8908-ae28-4c84-a33b-6b7808b9fe5c", - "link": "https://learn.microsoft.com/azure/dns/private-dns-getstarted-portal", - "service": "DNS", + "guid": "c823873a-2bec-4c2a-b684-a1ce8ae80efd", + "link": "https://learn.microsoft.com/azure/virtual-machines/workloads/oracle/oracle-database-backup-strategies", + "service": "SAP", "services": [ - "DNS", + "VM", + "Backup", "WAF" ], "severity": "Medium", - "text": "For environments where name resolution in Azure is all that's required, use Azure Private DNS for resolution with a delegated zone for name resolution (such as 'azure.contoso.com').", - "training": "https://learn.microsoft.com/learn/paths/az-104-manage-virtual-networks/", + "text": "Review Oracle Database in Azure Linux VM backup strategies.", "waf": "Operations" }, { - "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "41049d40-3a92-43c3-974d-00018ac6a9e0", - "link": "https://learn.microsoft.com/azure/dns/dns-private-resolver-overview", - "service": "DNS", + "guid": "2943b6d8-1d31-4e19-ade7-78e6b26d1962", + "link": "https://learn.microsoft.com/sql/relational-databases/tutorial-use-azure-blob-storage-service-with-sql-server-2016?view=sql-server-ver16", + "service": "SAP", "services": [ - "DNS", - "WAF", - "ACR" + "Storage", + "SQL", + "WAF" ], "severity": "Medium", - "text": "For environments where name resolution across Azure and on-premises is required and there is no existing enterprise DNS service like Active Directory, use Azure DNS Private Resolver to route DNS requests to Azure or to on-premises DNS servers.", - "training": "https://learn.microsoft.com/training/modules/intro-to-azure-dns-private-resolver/", - "waf": "Security" + "text": "Review the use of Azure Blob Storage with SQL Server 2016.", + "waf": "Operations" }, { - "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "1e6a83de-5de3-42c1-a924-81607d5d1e4e", - "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-name-resolution-for-vms-and-role-instances", - "service": "DNS", + "guid": "b82e650f-676d-417d-994d-fc33ca54ec14", + "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/automated-backup?view=azuresql", + "service": "SAP", "services": [ - "DNS", + "VM", + "Backup", "WAF" ], - "severity": "Low", - "text": "Special workloads that require and deploy their own DNS (such as Red Hat OpenShift) should use their preferred DNS solution.", - "training": "https://learn.microsoft.com/training/courses/az-700t00", + "severity": "Medium", + "text": "Review the use of Automated Backup v2 for Azure VMs.", "waf": "Operations" }, { - "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "614658d3-558f-4d77-849b-821112df27ee", - "link": "https://learn.microsoft.com/azure/dns/private-dns-autoregistration", - "service": "DNS", + "guid": "347c2dcc-e6eb-4b04-80c5-628b171aa62d", + "service": "SAP", "services": [ - "VM", - "DNS", - "VNet", "WAF" ], "severity": "High", - "text": "Enable auto-registration for Azure DNS to automatically manage the lifecycle of the DNS records for the virtual machines deployed within a virtual network.", - "training": "https://learn.microsoft.com/learn/paths/az-104-manage-virtual-networks/", + "text": "Enabling Write accelerator for M series when using premium disks(V1)", "waf": "Operations" }, { - "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "18c80eb0-582a-4198-bf5c-d8800b2d263b", - "link": "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/private-link-and-dns-integration-at-scale#private-link-and-dns-integration-in-hub-and-spoke-network-architectures", - "service": "DNS", + "guid": "b96512cf-996f-4b17-b9b8-6b16db1a2a94", + "link": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/AvZone-Latency-Test", + "service": "SAP", "services": [ - "DNS", "WAF" ], "severity": "Medium", - "text": "Implement a plan for managing DNS resolution between multiple Azure regions and when services fail over to another region", - "training": "https://learn.microsoft.com/learn/paths/az-104-manage-virtual-networks/", - "waf": "Reliability" + "text": "Test availability zone latency.", + "waf": "Performance" }, { - "arm-service": "microsoft.network/bastionHosts", "checklist": "WAF checklist", - "guid": "ee1ac551-c4d5-46cf-b035-d0a3c50d87ad", - "link": "https://learn.microsoft.com/azure/bastion/bastion-overview", - "service": "Bastion", + "guid": "9fd7ffd4-da11-49f6-a374-8d03e94c511d", + "link": "https://support.sap.com/en/offerings-programs/support-services/earlywatch-alert.html", + "service": "SAP", "services": [ - "Bastion", + "SAP", "WAF" ], "severity": "Medium", - "text": "Use Azure Bastion to securely connect to your network.", - "training": "https://learn.microsoft.com/training/modules/intro-to-azure-bastion/", - "waf": "Security" + "text": "Activate SAP EarlyWatch Alert for all SAP components.", + "training": "https://help.sap.com/docs/SUPPORT_CONTENT/techops/3362700736.html", + "waf": "Performance" }, { - "arm-service": "microsoft.network/bastionHosts", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant", - "guid": "6eab9eb6-762b-485e-8ea8-15aa5dba0bd0", - "link": "https://learn.microsoft.com/azure/bastion/bastion-faq#subnet", - "service": "Bastion", + "guid": "b9b140cf-413a-483d-aad2-8802c4e3c017", + "link": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/sap-on-azure-general-update-march-2019/ba-p/377456", + "service": "SAP", "services": [ - "Bastion", - "VNet", + "SAP", "WAF" ], "severity": "Medium", - "text": "Use Azure Bastion in a subnet /26 or larger.", - "training": "https://learn.microsoft.com/training/modules/intro-to-azure-bastion/", - "waf": "Security" + "text": "Review SAP application server to database server latency using SAP ABAPMeter report /SSA/CAT.", + "training": "https://me.sap.com/notes/0002879613", + "waf": "Performance" }, { - "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", "checklist": "WAF checklist", - "guid": "1d7aa9b6-4704-4489-a804-2d88e79d17b7", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", - "service": "WAF", + "guid": "62fbf0f8-51db-49e1-a961-bb5df7a35f80", + "service": "SAP", "services": [ - "AzurePolicy", - "WAF", - "FrontDoor", - "ACR" + "Monitor", + "SQL", + "WAF" ], "severity": "Medium", - "text": "Use Azure Front Door and WAF policies to provide global protection across Azure regions for inbound HTTP/S connections to a landing zone.", - "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", - "waf": "Security" + "text": "Review SQL Server performance monitoring using CCMS.", + "waf": "Performance" }, { - "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", "checklist": "WAF checklist", - "guid": "3b22a5a6-7e7a-48ed-9b30-e38c3f29812b", - "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", - "service": "WAF", + "guid": "35709da7-fc7d-4efe-bb20-2e91547b7390", + "link": "https://me.sap.com/notes/500235", + "service": "SAP", "services": [ - "AppGW", - "AzurePolicy", - "WAF", - "FrontDoor" + "VM", + "SAP", + "WAF" ], - "severity": "Low", - "text": "When using Azure Front Door and Azure Application Gateway to help protect HTTP/S apps, use WAF policies in Azure Front Door. Lock down Azure Application Gateway to receive traffic only from Azure Front Door.", - "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", - "waf": "Security" + "severity": "Medium", + "text": "Test network latency between SAP application layer VMs and DBMS VMs (NIPING).", + "training": "https://me.sap.com/notes/1100926/E", + "waf": "Performance" }, { - "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", "checklist": "WAF checklist", - "guid": "2363cefe-179b-4599-be0d-5973cd4cd21b", - "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", - "service": "WAF", + "guid": "9e9bb4c8-e934-4e4b-a13c-6f7c7c38eb43", + "link": "https://learn.microsoft.com/en-us/azure/sap/large-instances/hana-monitor-troubleshoot", + "service": "SAP", "services": [ - "VNet", + "SAP", + "Monitor", "WAF" ], - "severity": "High", - "text": "When WAFs and other reverse proxies are required for inbound HTTP/S connections, deploy them within a landing-zone virtual network and together with the apps that they're protecting and exposing to the internet.", - "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", - "waf": "Security" + "severity": "Medium", + "text": "Review SAP HANA studio alerts.", + "waf": "Performance" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "088137f5-e6c4-4cfd-9e50-4547c2447ec6", - "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-reference-architectures", - "service": "VNet", + "guid": "f1a92ab5-9509-4b57-86ff-b0ade361b694", + "link": "https://me.sap.com/notes/1969700", + "service": "SAP", "services": [ - "DDoS", - "VNet", + "SAP", "WAF" ], - "severity": "High", - "text": "Use Azure DDoS Network or IP Protection plans to help protect Public IP Addresses endpoints within the virtual networks.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Security" + "severity": "Medium", + "text": "Perform SAP HANA health checks using HANA_Configuration_Minichecks.", + "waf": "Performance" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "b034c01e-110b-463a-b36e-e3346e57f225", - "link": "https://learn.microsoft.com/azure/virtual-network/ip-services/default-outbound-access", - "service": "VNet", + "guid": "18dffcf3-248c-4039-a67c-dec8e3a5f804", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", + "service": "SAP", "services": [ + "VM", "WAF" ], - "severity": "High", - "text": "Plan for how to manage your network outbound traffic configuration and strategy before the upcoming breaking change. On September 30, 2025, default outbound access for new deployments will be retired and only explicit access configurations will be allowed.", - "training": "https://learn.microsoft.com/training/modules/configure-virtual-networks/", - "waf": "Reliability" + "severity": "Medium", + "text": "If you run Windows and Linux VMs in Azure, on-premises, or in other cloud environments, you can use the Update management center in Azure Automation to manage operating system updates, including security patches.", + "training": "https://learn.microsoft.com/azure/automation/update-management/overview", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "b1c82a3f-2320-4dfa-8972-7ae4823c8930", - "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-reference-architectures", - "service": "VNet", + "guid": "08951710-79a2-492a-adbc-06d7a401545b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", + "service": "SAP", "services": [ - "DDoS", + "SAP", "WAF" ], - "severity": "High", - "text": "Add diagnostic settings to save DDoS related logs for all the protected public IP addresses (DDoS IP or Network Protection).", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "severity": "Medium", + "text": "Routinely review the SAP security OSS notes because SAP releases highly critical security patches, or hot fixes, that require immediate action to protect your SAP systems.", + "training": "https://support.sap.com/en/my-support/knowledge-base/security-notes-news.html", "waf": "Security" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "3c5a808d-c695-4c14-a63c-c7ab7a510e41", - "link": "https://github.com/Azure/Enterprise-Scale/wiki/ALZ-Policies#corp", - "service": "Policy", + "guid": "1b8b394e-ae64-4a74-8933-357b523ea0a0", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "service": "SAP", "services": [ - "AzurePolicy", - "VM", + "SAP", + "SQL", "WAF" ], - "severity": "High", - "text": "Ensure there is a policy assignment to deny Public IP addresses directly tied to Virtual Machines. Use exclusions if public IPs are needed on specific VMs.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", + "severity": "Low", + "text": "For SAP on SQL Server, you can disable the SQL Server system administrator account because the SAP systems on SQL Server don't use the account. Ensure that another user with system administrator rights can access the server before disabling the original system administrator account.", "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "359c373e-7dd6-4162-9a36-4a907ecae48e", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/connectivity-to-azure", - "service": "ExpressRoute", + "guid": "5a76a033-ced9-4eef-9a43-5e4f96634c8e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "service": "SAP", "services": [ - "VPN", - "ExpressRoute", - "WAF", - "Backup" + "SQL", + "WAF" ], - "severity": "Medium", - "text": "Use ExpressRoute as the primary connection to Azure. Use VPNs as a source of backup connectivity.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Performance" + "severity": "High", + "text": "Disable xp_cmdshell. The SQL Server feature xp_cmdshell enables a SQL Server internal operating system command shell. It's a potential risk in security audits.", + "training": "https://me.sap.com/notes/3019299/E", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "You can use AS-path prepending and connection weights to influence traffic from Azure to on-premises, and the full range of BGP attributes in your own routers to influence traffic from on-premises to Azure.", - "guid": "f29812b2-363c-4efe-879b-599de0d5973c", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-routing", - "service": "ExpressRoute", + "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "service": "SAP", "services": [ - "ExpressRoute", + "Backup", + "Storage", + "SAP", + "SQL", "WAF" ], - "severity": "Medium", - "text": "When you use multiple ExpressRoute circuits or multiple on-prem locations, use BGP attributes to optimize routing.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Reliability" + "severity": "High", + "text": "Encrypting SAP HANA database servers on Azure uses SAP HANA native encryption technology. Additionally, if you are using SQL Server on Azure, use Transparent Data Encryption (TDE) to protect your data and log files and ensure that your backups are also encrypted.", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "graph": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant", - "guid": "d4cd21b0-8813-47f5-b6c4-cfd3e504547c", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku", - "service": "ExpressRoute", + "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", + "service": "SAP", "services": [ - "VPN", - "ExpressRoute", + "Storage", "WAF" ], "severity": "Medium", - "text": "Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Performance" + "text": "Azure Storage encryption is enabled for all Azure Resource Manager and classic storage accounts, and can't be disabled. Because your data is encrypted by default, you don't need to modify your code or applications to use Azure Storage encryption.", + "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant", - "guid": "7025b442-f6e9-4af6-b11f-c9574916016f", - "link": "https://learn.microsoft.com/azure/expressroute/plan-manage-cost", - "service": "ExpressRoute", + "graph": "Resources | join kind=leftouter (ResourceContainers | where type=~'microsoft.resources/subscriptions' | project SubName=name, subscriptionId) on subscriptionId | where type =~ 'microsoft.keyvault/vaults' | project type, name, SubName", + "guid": "ce9bd3bb-0cdb-43b5-9eb2-ec14eeaa3592", + "link": "https://learn.microsoft.com/azure/key-vault/general/overview", + "service": "SAP", "services": [ - "ExpressRoute", - "WAF", - "Cost" + "AKV", + "WAF" ], "severity": "High", - "text": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost.", - "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", - "waf": "Cost" + "text": "Use Azure Key Vault to store your secrets and credentials", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id", - "guid": "f4e7926a-ec35-476e-a412-5dd17136bd62", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local", - "service": "ExpressRoute", + "guid": "829e2edb-2173-4676-aff6-691b4935ada4", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", + "service": "SAP", "services": [ - "ExpressRoute", - "WAF", - "Cost" + "Subscriptions", + "RBAC", + "AzurePolicy", + "WAF" ], - "severity": "High", - "text": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU.", - "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", - "waf": "Cost" + "severity": "Medium", + "text": "It is recommended to LOCK the Azure Resources post successful deployment to safeguard against unauthorized changes. You can also enforce LOCK constraints and rules on your per-subscription basis using customized Azure policies(Custome role).", + "training": "https://learn.microsoft.com/training/modules/use-azure-resource-manager/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "graph": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant", - "guid": "2447ec66-138a-4720-8f1c-e16ed301d6e8", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways", - "service": "ExpressRoute", + "guid": "2223ece8-1b12-4318-8a54-17415833fb4a", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", + "service": "SAP", "services": [ - "ExpressRoute", + "AKV", + "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Reliability" + "text": "Provision Azure Key Vault with the soft delete and purge policies enabled to allow retention protection for deleted objects.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "72e52e36-11cc-458b-9a4b-1511e43a58a9", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/connectivity-to-azure", - "service": "ExpressRoute", + "guid": "e3c2df74-3165-4c3a-abe0-5bbe209d490d", + "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", + "service": "SAP", "services": [ - "ExpressRoute", + "RBAC", + "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "For scenarios that require bandwidth higher than 10 Gbps or dedicated 10/100-Gbps ports, use ExpressRoute Direct.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Performance" + "severity": "High", + "text": "Based on existing requirements, regulatory and compliance controls (internal/external) - Determine what Azure Policies and Azure RBAC role are needed", + "training": "https://learn.microsoft.com/training/paths/describe-azure-management-governance/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "c2299c4d-7b57-4d0c-9555-62f2b3e4563a", - "link": "https://learn.microsoft.com/azure/expressroute/about-fastpath", - "service": "ExpressRoute", + "guid": "a4777842-4d11-4678-9d2f-a56c56ad4840", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "service": "SAP", "services": [ - "ExpressRoute", + "Storage", + "SAP", + "Defender", "WAF" ], - "severity": "Medium", - "text": "When low latency is required, or throughput from on-premises to Azure must be greater than 10 Gbps, enable FastPath to bypass the ExpressRoute gateway from the data path.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Performance" + "severity": "High", + "text": "When enabling Microsoft Defender for Endpoint on SAP environment, recommend excluding data and log files on DBMS servers instead of targeting all servers. Follow your DBMS vendor's recommendations when excluding target files.", + "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/microsoft-defender-endpoint-mde-for-sap-applications-on-windows/ba-p/3912268", + "waf": "Security" }, { - "arm-service": "microsoft.network/virtualNetworkGateways", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant", - "guid": "4d873974-8b66-42d6-b15f-512a65498f6d", - "link": "https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway", - "service": "VPN", + "guid": "8fe72734-c486-4ba2-a0dc-0591cf65de8e", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/just-in-time-access-overview?tabs=defender-for-container-arch-aks", + "service": "SAP", "services": [ - "VPN", + "Defender", + "RBAC", + "SAP", "WAF" ], - "severity": "Medium", - "text": "Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available).", - "training": "https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/", - "waf": "Reliability" + "severity": "High", + "text": "Delegate an SAP admin custom role with just-in-time access of Microsoft Defender for Cloud.", + "training": "https://learn.microsoft.com/training/modules/secure-vms-with-azure-security-center/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/virtualNetworkGateways", "checklist": "WAF checklist", - "guid": "45866df8-cf85-4ca9-bbe2-65ec1478919e", - "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-highlyavailable", - "service": "VPN", + "guid": "1309cccd-5792-466b-aca2-75faa1abfe9d", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "service": "SAP", "services": [ - "VPN", + "SAP", + "WAF" + ], + "severity": "Low", + "text": "encrypt data in transit by integrating the third-party security product with secure network communications (SNC) for DIAG (SAP GUI), RFC, and SPNEGO for HTTPS", + "training": "https://learn.microsoft.com/azure/security/fundamentals/encryption-overview#encryption-of-data-in-transit", + "waf": "Security" + }, + { + "checklist": "WAF checklist", + "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", + "link": "https://learn.microsoft.com/azure/storage/common/storage-encryption-key-model-get?tabs=portal", + "service": "SAP", + "services": [ + "AKV", "WAF" ], "severity": "Medium", - "text": "Use redundant VPN appliances on-premises (active/active or active/passive).", - "training": "https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/", - "waf": "Reliability" + "text": "Default to Microsoft-managed keys for principal encryption functionality and use customer-managed keys when required.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "718cb437-b060-2589-8856-2e93a5c6633b", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-erdirect-about", - "service": "ExpressRoute", + "graph": "Resources | join kind=leftouter (ResourceContainers | where type=~'microsoft.resources/subscriptions' | project SubName=name, subscriptionId) on subscriptionId | where type =~ 'microsoft.keyvault/vaults' | project type, name, SubName", + "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "link": "https://learn.microsoft.com/ja-jp/azure/key-vault/general/best-practices", + "service": "SAP", "services": [ - "ExpressRoute", - "WAF", - "Cost" + "AKV", + "WAF" ], "severity": "High", - "text": "If using ExpressRoute Direct, consider using ExpressRoute Local circuits to the local Azure regions to save costs.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Cost" + "text": "Use an Azure Key Vault per application per environment per region.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "8042d88e-79d1-47b7-9b22-a5a67e7a8ed4", - "link": "https://learn.microsoft.com/azure/architecture/framework/services/networking/expressroute/reliability", - "service": "ExpressRoute", + "guid": "abc9634d-c44d-41e9-a530-e8444e16aa3c", + "link": "https://learn.microsoft.com/azure/key-vault/certificates/certificate-scenarios", + "service": "SAP", "services": [ - "ExpressRoute", + "AKV", + "SAP", "WAF" ], - "severity": "Medium", - "text": "When traffic isolation or dedicated bandwidth is required, such as for separating production and nonproduction environments, use different ExpressRoute circuits. It will help you ensure isolated routing domains and alleviate noisy-neighbor risks.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "severity": "High", + "text": "To control and manage disk encryption keys and secrets for non-HANA Windows and non-Windows operating systems, use Azure Key Vault. SAP HANA isn't supported with Azure Key Vault, so you must use alternate methods like SAP ABAP or SSH keys.", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/?source=recommendations", "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "b30e38c3-f298-412b-8363-cefe179b599d", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-monitoring-metrics-alerts", - "service": "ExpressRoute", + "guid": "209d490d-a477-4784-84d1-16785d2fa56c", + "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles", + "service": "SAP", "services": [ - "ExpressRoute", - "WAF", - "Monitor" + "Subscriptions", + "RBAC", + "SAP", + "WAF" ], - "severity": "Medium", - "text": "Monitor ExpressRoute availability and utilization using built-in Express Route Insights.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Operations" + "severity": "High", + "text": "Customize role-based access control (RBAC) roles for SAP on Azure spoke subscriptions to avoid accidental network-related changes", + "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "5bf68dc9-325e-4873-bf88-f8214ef2e5d2", - "link": "https://learn.microsoft.com/azure/expressroute/how-to-configure-connection-monitor", - "service": "ExpressRoute", + "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", + "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/", + "service": "SAP", "services": [ - "NetworkWatcher", - "WAF", - "ACR", - "Monitor" + "NVA", + "PrivateLink", + "SAP", + "WAF" ], - "severity": "Medium", - "text": "Use Connection Monitor for connectivity monitoring across the network, especially between on-premises and Azure.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Operations" + "severity": "High", + "text": "Isolate DMZs and NVAs from the rest of the SAP estate, configure Azure Private Link, and securely manage and control the SAP on Azure resources", + "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2)", - "guid": "e0d5973c-d4cd-421b-8881-37f5e6c4cfd3", - "link": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution", - "service": "ExpressRoute", + "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", + "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", + "service": "SAP", "services": [ - "ExpressRoute", + "Storage", + "VM", "WAF" ], - "severity": "Medium", - "text": "Use ExpressRoute circuits from different peering locations for redundancy.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Reliability" + "severity": "Low", + "text": "Consider using Microsoft anti-malware software on Azure to protect your virtual machines from malicious files, adware, and other threats.", + "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "cf3fe65c-fec0-495a-8edc-9675200f2add", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-coexist-resource-manager", - "service": "ExpressRoute", + "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", + "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", + "service": "SAP", "services": [ - "VPN", - "ExpressRoute", + "Defender", "WAF" ], - "severity": "Medium", - "text": "Use site-to-site VPN as failover of ExpressRoute, if only using a single ExpressRoute circuit.", - "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", - "waf": "Reliability" + "severity": "Low", + "text": "For even more powerful protection, consider using Microsoft Defender for Endpoint.", + "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation))", - "guid": "72105cc8-aaea-4ee1-8c7a-ad25977afcaf", - "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub", - "service": "ExpressRoute", + "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "service": "SAP", "services": [ - "Storage", "VNet", + "SAP", "WAF" ], "severity": "High", - "text": "If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated.", - "waf": "Reliability" + "text": "Isolate the SAP application and database servers from the internet or from the on-premises network by passing all traffic through the hub virtual network, which is connected to the spoke network by virtual network peering. The peered virtual networks guarantee that the SAP on Azure solution is isolated from the public internet.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "d581a947-69a2-4783-942e-9df3664324c8", - "link": "https://learn.microsoft.com/azure/expressroute/designing-for-high-availability-with-expressroute#active-active-connections", - "service": "ExpressRoute", + "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "service": "SAP", "services": [ - "ExpressRoute", - "WAF", - "ACR" + "SAP", + "WAF" ], - "severity": "High", - "text": "If using ExpressRoute, your on-premises routing should be dynamic: in the event of a connection failure it should converge to the remaining connection of the circuit. Load should be shared across both connections ideally as active/active, although active/passive is supported too.", - "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", - "waf": "Reliability" + "severity": "Low", + "text": "For internet-facing applications like SAP Fiori, make sure to distribute load per application requirements while maintaining security levels. For Layer 7 security, you can use a third-party Web Application Firewall (WAF) available in the Azure Marketplace.", + "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations", + "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "b258f058-b9f6-46cd-b28d-990106f0c3f8", - "link": "https://learn.microsoft.com/azure/expressroute/designing-for-high-availability-with-expressroute", - "service": "ExpressRoute", + "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", + "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions", + "service": "SAP", "services": [ - "ExpressRoute", + "AKV", + "SAP", + "Monitor", "WAF" ], "severity": "Medium", - "text": "Ensure the two physical links of your ExpressRoute circuit are connected to two distinct edge devices in your network.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "text": "To enable secure communication in Azure Monitor for SAP solutions, you can choose to use either a root certificate or a server certificate. We highly recommend that you use root certificates.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations", + "waf": "Security" + }, + { + "arm-service": "microsoft.web/sites", + "checklist": "WAF checklist", + "description": "Leverage zone-redundancy to ensure high availability in the event of zone-level failures. Use Premium V2/V3 or Isolated v2 tiers, which provide support for zone-redundant deployments and ensure minimal downtime during disasters.", + "guid": "b32e1aa1-4813-4602-88fe-27ca2891f421", + "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/app-service-web-app/zone-redundant?source=recommendations", + "service": "App Services", + "services": [ + "AppSvc", + "WAF" + ], + "severity": "Low", + "text": "Implement a baseline highly available zone-redundant web application architecture. Ensure your Azure App Service is on Premium V2/V3 or Isolated v2 tiers for zone-redundant support.", "waf": "Reliability" }, { - "arm-service": "microsoft.network/expressRouteCircuits", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "fe2a1b53-6fbd-4c67-b58a-85d7c7a0afcb", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-bfd", - "service": "ExpressRoute", + "description": "Leverage staging slots for zero-downtime deployments and automated backups to ensure disaster recovery. Choose the appropriate tier (Standard or Premium) based on the number of slots and disaster recovery requirements.", + "graph": "resources | where type =~ 'microsoft.web/serverfarms' | extend compliant = (sku.tier == 'Premium' or sku.tier == 'Standard') | distinct id,compliant", + "guid": "e4b31c6a-2e3f-4df1-8e8b-9c3aa5a27820", + "link": "https://learn.microsoft.com/azure/app-service/overview-hosting-plans", + "service": "App Services", "services": [ + "ASR", + "Backup", "WAF" ], "severity": "Medium", - "text": "Ensure Bidirectional Forwarding Detection (BFD) is enabled and configured on customer or provider edge routing devices.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "text": "Use Premium and Standard tiers for staging slots and automated backups. Align your backup retention period with disaster recovery needs.", "waf": "Reliability" }, { - "arm-service": "microsoft.network/expressRouteCircuits", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "669b215a-ce43-4371-8f6f-11047f6490f1", - "link": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering", - "service": "ExpressRoute", + "description": "Availability Zones provide physical isolation across datacenters in a region, reducing downtime during outages. Verify your region supports Availability Zones and use Premium V2/V3 tiers for zone-redundant deployments.", + "guid": "a7e2e6c2-491f-4fa4-a82b-521d0bc3b202", + "link": "https://learn.microsoft.com/azure/reliability/migrate-app-service", + "service": "App Services", "services": [ - "ExpressRoute", + "ACR", "WAF" ], "severity": "High", - "text": "Connect the ExpressRoute Gateway to two or more circuits from different peering locations for higher resiliency.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "text": "Leverage Availability Zones where regionally applicable (Premium V2/V3 tier required). Check region support for Availability Zones.", "waf": "Reliability" }, { - "arm-service": "microsoft.network/expressRouteCircuits", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "3f79ed00-203b-4c95-9efd-691505f5a1f9", - "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-howto-setup-alerts-virtual-network-gateway-log", - "service": "ExpressRoute", + "description": "Enable health checks to detect unhealthy instances in real-time and automatically replace them to maintain high availability and application reliability.", + "graph": "appserviceresources | where type =~ 'microsoft.web/sites/config' | extend compliant = (properties.HealthCheckPath != '') | distinct id,compliant", + "guid": "1275e4a9-7b6a-43c3-a9cd-5ee18d8995ad", + "link": "https://learn.microsoft.com/azure/app-service/monitor-instances-health-check", + "service": "App Services", "services": [ - "VNet", - "ExpressRoute", - "WAF", - "Monitor" + "AppSvc", + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Configure diagnostic logs and alerts for ExpressRoute virtual network gateway.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Operations" + "text": "Implement health checks to monitor and detect issues with App Service instances. Health checks enable automatic instance replacement on failure.", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/expressRouteCircuits", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "5234c93f-b651-41dd-80c1-234177b91ced", - "link": "https://learn.microsoft.com/azure/expressroute/virtual-network-connectivity-guidance", - "service": "ExpressRoute", + "description": "Follow best practices for configuring backups and restores in Azure App Service and ASE to guarantee data availability and ensure recovery during disaster scenarios.", + "guid": "35a91c5d-4ad6-4d9b-8e0f-c47db9e6d1e7", + "link": "https://learn.microsoft.com/azure/app-service/manage-backup", + "service": "App Services", "services": [ - "ExpressRoute", - "WAF", - "VNet" + "AppSvc", + "Backup", + "WAF" ], - "severity": "Medium", - "text": "Do not use ExpressRoute circuits for VNet-to-VNet communication.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", - "waf": "Performance" + "severity": "High", + "text": "Refer to backup and restore best practices for Azure App Service and App Service Environments (ASE) to ensure data availability and recovery.", + "waf": "Reliability" + }, + { + "arm-service": "microsoft.web/sites", + "checklist": "WAF checklist", + "description": "Ensure high availability by incorporating scaling, fault tolerance, monitoring, and zone redundancy into your App Service architecture. Leverage health checks and availability zones to maintain uptime.", + "guid": "e68cd0ec-afc6-4bd8-a27f-7860ad9a0db2", + "link": "https://learn.microsoft.com/azure/architecture/framework/services/compute/azure-app-service/reliability", + "service": "App Services", + "services": [ + "AppSvc", + "Monitor", + "WAF" + ], + "severity": "High", + "text": "Implement Azure App Service reliability best practices, including auto-scaling, fault tolerance, health checks, and zone redundancy.", + "waf": "Reliability" }, { + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "8ac6a9e0-1e6a-483d-b5de-32c199248160", - "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about", - "service": "N/A", + "description": "Prepare for disaster recovery by implementing region failover strategies. Utilize active-active and active-passive configurations, automated failover, and Infrastructure as Code (IaC) for seamless failover during outages.", + "guid": "bd2a865c-0835-4418-bb58-4df91a5a9b3f", + "link": "https://learn.microsoft.com/azure/app-service/manage-disaster-recovery#recover-app-content-only", + "service": "App Services", "services": [ - "WAF", - "ACR" + "ASR", + "AppSvc", + "WAF" ], "severity": "Low", - "text": "Do not send Azure traffic to hybrid locations for inspection. Instead, follow the principle 'traffic in Azure stays in Azure' so that communication across resources in Azure occurs via the Microsoft backbone network.", - "waf": "Performance" + "text": "Familiarize with App Service region failover, including active-active and active-passive configurations, automated failover, and IaC deployment.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "e6c4cfd3-e504-4547-a244-7ec66138a720", - "link": "https://learn.microsoft.com/azure/firewall/overview", - "service": "Firewall", + "description": "Azure App Service offers built-in reliability features, including scaling, fault tolerance, and service-level agreements (SLAs). Leverage these features to maintain consistent performance during outages.", + "guid": "f3d2f1e4-e6d4-4b7a-a5a5-e2a9b2c6f293", + "link": "https://learn.microsoft.com/azure/reliability/reliability-app-service", + "service": "App Services", "services": [ - "Firewall", + "AppSvc", "WAF" ], "severity": "High", - "text": "Use Azure Firewall to govern Azure outbound traffic to the internet, non-HTTP/S inbound connections, and East/West traffic filtering (if the organization requires it).", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Security" + "text": "Familiarize with reliability support in Azure App Service, including scaling options, SLAs, and automated recovery mechanisms.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "5a4b1511-e43a-458a-ac22-99c4d7b57d0c", - "link": "https://learn.microsoft.com/azure/firewall-manager/policy-overview", - "service": "Firewall", + "description": "Enabling 'Always On' for Function Apps ensures that the app does not go idle, maintaining its availability and responsiveness at all times.", + "guid": "c7b5f3d1-0569-4fd2-9f32-c0b64e9c0c5e", + "link": "https://learn.microsoft.com/azure/azure-functions/dedicated-plan#always-on", + "service": "App Services", "services": [ - "ACR", - "Firewall", - "AzurePolicy", - "RBAC", + "AppSvc", "WAF" ], "severity": "Medium", - "text": "Create a global Azure Firewall policy to govern security posture across the global network environment and assign it to all Azure Firewall instances. Allow for granular policies to meet requirements of specific regions by delegating incremental firewall policies to local security teams via Azure role-based access control.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Security" + "text": "Ensure 'Always On' is enabled for Function Apps running on App Service plans to prevent idling and ensure continuous availability.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "655562f2-b3e4-4563-a4d8-739748b662d6", - "link": "https://learn.microsoft.com/azure/firewall-manager/deploy-trusted-security-partner", - "service": "Firewall", + "description": "Health checks monitor the health of App Service instances, enabling automatic replacement of unhealthy instances to maintain high availability.", + "guid": "a3b4d5f6-758c-4f9d-9e1a-d7c6b7e8f9ab", + "link": "https://learn.microsoft.com/azure/app-service/monitor-instances-health-check", + "service": "App Services", "services": [ - "Firewall", + "AppSvc", + "Monitor", "WAF" ], - "severity": "Low", - "text": "Configure supported partner SaaS security providers within Firewall Manager if the organization wants to use such solutions to help protect outbound connections.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Security" + "severity": "Medium", + "text": "Monitor App Service instances using Health checks to detect unhealthy instances and automatically replace them.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant", - "guid": "14d99880-2f88-47e8-a134-62a7d85c94af", - "link": "https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules", - "service": "Firewall", + "guid": "c7d3e5f9-a19c-4833-8ca6-1dcb0128e129", + "link": "https://learn.microsoft.com/azure/azure-monitor/app/availability-overview", + "service": "App Services", "services": [ - "DNS", - "Firewall", + "Monitor", "WAF" ], - "severity": "High", - "text": "Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Security" + "severity": "Medium", + "text": "Monitor availability and responsiveness of web app or website using Application Insights availability tests, ensuring proactive detection of performance issues and downtime.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant", - "guid": "c10d51ef-f999-455d-bba0-5c90ece07447", - "link": "https://learn.microsoft.com/azure/firewall/premium-features", - "service": "Firewall", + "guid": "b4e3f2d5-a5c6-4d7e-8b2f-c5d9e7a8f0ea", + "link": "https://learn.microsoft.com/azure/azure-monitor/app/availability-standard-tests", + "service": "App Services", "services": [ - "Firewall", + "Monitor", "WAF" ], - "severity": "High", - "text": "Use Azure Firewall Premium to enable additional security features.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-firewall/", - "waf": "Security" + "severity": "Low", + "text": "Use Application Insights Standard test to monitor availability and responsiveness of web app or website", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant", - "guid": "e9c8f584-6d5e-473b-8dc5-acc9fbaab4e3", - "link": "https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules", - "service": "Firewall", + "description": "Azure Key Vault ensures secrets are encrypted, securely stored, and accessed only by authorized applications. It supports audit logging, and secret versioning, and reduces the risk of accidental exposure of sensitive information.", + "guid": "834ac932-223e-4ce8-8b12-3071a5416415", + "link": "https://learn.microsoft.com/azure/app-service/app-service-key-vault-references", + "service": "App Services", "services": [ - "Firewall", + "AKV", + "AppSvc", "WAF" ], "severity": "High", - "text": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection.", + "text": "Use Azure Key Vault to store any secrets the application needs. Key Vault provides a secure, managed, and audited environment for storing secrets, and integrates seamlessly with App Service via App Service Key Vault References for enhanced security.", "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant", - "guid": "b9d0dff5-bdd4-4cd8-88ed-5811610b2b2c", - "link": "https://learn.microsoft.com/azure/firewall/premium-features#idps", - "service": "Firewall", + "description": "Managed Identity eliminates the need for hard-coded credentials by allowing App Service to authenticate to Azure Key Vault securely. This reduces the risk of credential exposure and simplifies secret management for enhanced security.", + "guid": "833ea3ad-2c2d-4e73-8165-c3acbef4abe1", + "link": "https://learn.microsoft.com/azure/app-service/app-service-key-vault-references", + "service": "App Services", "services": [ - "Firewall", + "AKV", + "AppSvc", + "Entra", "WAF" ], "severity": "High", - "text": "Configure Azure Firewall IDPS mode to Deny for additional protection.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-firewall/", + "text": "Use Managed Identity to securely connect to Azure Key Vault for accessing secrets, through App Service Key Vault References.", "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant", - "guid": "a3784907-9836-4271-aafc-93535f8ec08b", - "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview", - "service": "Firewall", + "description": "Storing TLS certificates in Azure Key Vault enhances security by providing centralized, secure management and automated renewal of certificates. This reduces the risk of manual handling errors and certificate expiration.", + "guid": "f8d39fda-4776-4831-9c11-5775c2ea55b4", + "link": "https://learn.microsoft.com/azure/app-service/configure-ssl-certificate", + "service": "App Services", "services": [ - "VWAN", - "NVA", - "Storage", - "Firewall", - "VNet", + "AKV", + "AppSvc", + "Entra", "WAF" ], "severity": "High", - "text": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance.", + "text": "Use Azure Key Vault to securely store and manage TLS certificates for App Service.", "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "715d833d-4708-4527-90ac-1b142c7045ba", - "link": "https://learn.microsoft.com/azure/firewall/firewall-structured-logs", - "service": "Firewall", + "description": "To minimize exposure and improve security, isolate systems processing sensitive data. Leverage separate App Service Plans or App Service Environments for isolation, and use different subscriptions or management groups to enforce stricter boundaries and governance.", + "guid": "6ad48408-ee72-4734-a475-ba18fdbf590c", + "link": "https://learn.microsoft.com/azure/app-service/overview-hosting-plans", + "service": "App Services", "services": [ - "Storage", - "Firewall", + "Subscriptions", + "AppSvc", "WAF" ], "severity": "Medium", - "text": "Add diagnostic settings to save logs, using the Resource Specific destination table, for all Azure Firewall deployments.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Operations" - }, - { - "arm-service": "Microsoft.Network/azureFirewalls", - "checklist": "WAF checklist", - "guid": "e960fc6b-4ab2-4db6-9609-3745135f9ffa", - "link": "https://learn.microsoft.com/azure/firewall-manager/migrate-to-policy", - "service": "Firewall", - "services": [ - "AzurePolicy", - "Firewall", - "WAF" - ], - "severity": "High", - "text": "Migrate from Azure Firewall Classic rules (if exist) to Firewall Policy.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Operations" - }, - { - "arm-service": "Microsoft.Network/azureFirewalls", - "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant", - "guid": "22d6419e-b627-4d95-9e7d-019fa759387f", - "link": "https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size", - "service": "Firewall", - "services": [ - "Firewall", - "VNet", - "WAF" - ], - "severity": "High", - "text": "Use a /26 prefix for your Azure Firewall subnets.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-firewall/", + "text": "Isolate systems that process sensitive information using separate App Service Plans, App Service Environments (ASE), and consider different subscriptions or management groups for enhanced security.", "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "828cec2e-af6c-40c2-8fa2-1b681ee63eb7", - "link": "https://learn.microsoft.com/azure/firewall-manager/rule-hierarchy", - "service": "Firewall", + "description": "Local disks on App Service are not encrypted and sensitive data should not be stored on those. (For example: D:\\\\Local and %TMP%).", + "guid": "e65de8e0-3f9b-4cbd-9682-66abca264f9a", + "link": "https://learn.microsoft.com/azure/app-service/operating-system-functionality#file-access", + "service": "App Services", "services": [ - "AzurePolicy", + "AppSvc", + "TrafficManager", "WAF" ], "severity": "Medium", - "text": "Arrange rules within the firewall policy into Rule Collection Groups and Rule Collections and based on their frequency of use.", - "training": "https://learn.microsoft.com/training/modules/intro-to-azure-firewall-manager/", - "waf": "Performance" + "text": "Do not store sensitive data on local disk", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "0da83bb1-2f39-49af-b5c9-835fc455e3d1", - "link": "https://learn.microsoft.com/azure/firewall/ip-groups", - "service": "Firewall", + "description": "Use Microsoft Entra ID or B2C for secure user authentication and Single Sign-On (SSO) across applications. Integrate using the built-in App Service Authentication/Authorization feature for streamlined security and compliance with modern authentication protocols like OpenID Connect.", + "guid": "919ca0b2-c121-459e-814b-933df574eccc", + "link": "https://learn.microsoft.com/azure/app-service/overview-authentication-authorization", + "service": "App Services", "services": [ - "Storage", + "ACR", + "AppSvc", + "Entra", "WAF" ], "severity": "Medium", - "text": "Use IP Groups or IP prefixes to reduce number of IP table rules.", - "waf": "Performance" + "text": "Use Microsoft Entra ID or B2C for secure authentication and Single Sign-On (SSO).", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "c44c6f0e-1642-4a61-a17b-0922f835c93a", - "link": "https://learn.microsoft.com/azure/firewall/tutorial-firewall-dnat", - "service": "Firewall", + "description": "Ensure all code deployments to App Service originate from a controlled, secured environment, such as a well-managed DevOps pipeline. This practice mitigates the risk of deploying unauthorized or malicious code by enforcing version control, code verification, and secure hosting.", + "guid": "3f9bcbd4-6826-46ab-aa26-4f9a19aed9c5", + "link": "https://learn.microsoft.com/azure/app-service/deploy-best-practices", + "service": "App Services", "services": [ + "AppSvc", "WAF" ], - "severity": "Medium", - "text": "Do not use wildcards as a source IP for DNATS, such as * or any, you should specify source IPs for incoming DNATs.", - "training": "https://learn.microsoft.com/training/modules/introduction-to-azure-virtual-networks/", - "waf": "Performance" + "severity": "High", + "text": "Deploy code to App Service from a trusted and secure environment.", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "7371dc21-251a-47a3-af14-6e01b9da4757", - "link": "https://learn.microsoft.com/azure/firewall/integrate-with-nat-gateway", - "service": "Firewall", + "description": "Disable basic authentication for FTP/FTPS and WebDeploy/SCM to enhance security by enforcing Microsoft Entra ID secured endpoints for deployment. This ensures that only authenticated users using Microsoft Entra ID credentials can access deployment services, including the SCM site.", + "guid": "5d04c2c3-919c-4a0b-8c12-159e114b933d", + "link": "https://learn.microsoft.com/azure/app-service/deploy-configure-credentials#disable-basic-authentication", + "service": "App Services", "services": [ - "WAF", - "Monitor" + "Entra", + "WAF" ], - "severity": "Medium", - "text": "Prevent SNAT Port exhaustion by monitoring SNAT port usage, evaluating NAT Gateway settings, and ensuring seamless failover. If the port count approaches the limit, it’s a sign that SNAT exhaustion might be imminent.", - "training": "https://learn.microsoft.com/training/modules/introduction-to-azure-virtual-networks/", - "waf": "Performance" + "severity": "High", + "text": "Disable basic authentication for FTP/FTPS and WebDeploy/SCM.", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "346840b8-1064-496e-8396-4b1340172d52", - "link": "https://learn.microsoft.com/azure/firewall/premium-features#tls-inspection", - "service": "Firewall", + "description": "Wherever possible, use Managed Identity to securely connect to Microsoft Entra ID-secured resources without storing credentials. If this is not feasible, store secrets in Azure Key Vault and access them using Managed Identity to maintain security and reduce the risk of credential exposure.", + "guid": "f574eccc-d9bd-43ba-bcda-3b54eb2eb03d", + "link": "https://learn.microsoft.com/azure/app-service/overview-managed-identity?tabs=portal%2Chttp", + "service": "App Services", "services": [ - "Firewall", + "AKV", + "Entra", "WAF" ], "severity": "High", - "text": "If you are using Azure Firewall Premium, enable TLS Inspection.", - "waf": "Performance" + "text": "Use Managed Identity to connect to Microsoft Entra ID secured resources.", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "39990a13-915c-45f9-a2d3-562d7d6c4b7c", - "link": "https://learn.microsoft.com/azure/firewall/premium-features#web-categories", - "service": "Firewall", + "description": "When using images stored in Azure Container Registry, pull these images using a Managed Identity to avoid storing credentials. This ensures secure access to container images and reduces the risk of credential exposure.", + "guid": "d9a25827-18d2-4ddb-8072-5769ee6691a4", + "link": "https://learn.microsoft.com/azure/app-service/configure-custom-container#use-managed-identity-to-pull-image-from-azure-container-registry", + "service": "App Services", "services": [ - "ServiceBus", + "ACR", + "Entra", "WAF" ], - "severity": "Low", - "text": "Use web categories to allow or deny outbound access to specific topics.", - "waf": "Performance" + "severity": "High", + "text": "Pull container images from Azure Container Registry using a Managed Identity.", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "6eff7e6c-6c4a-43d7-be3f-6641c2cb3d4a", - "link": "https://learn.microsoft.com/azure/architecture/example-scenario/gateway/application-gateway-before-azure-firewall", - "service": "Firewall", + "description": "Configure diagnostic settings to send telemetry and security logs (including HTTP, platform, and audit logs) to Log Analytics. Centralized logging enhances monitoring, threat detection, and compliance reporting.", + "guid": "47768314-c115-4775-a2ea-55b46ad48408", + "link": "https://learn.microsoft.com/azure/app-service/troubleshoot-diagnostic-logs", + "service": "App Services", "services": [ + "AppSvc", + "Monitor", + "Entra", "WAF" ], "severity": "Medium", - "text": "As part of your TLS inspection, plan for receiving traffic from Azure App Gateways for inspection.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-application-gateway/", - "waf": "Performance" + "text": "Send App Service runtime and security logs to Log Analytics for centralized monitoring and alerting.", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant", - "guid": "94f3eede-9aa3-4088-92a3-bb9a56509fad", - "link": "https://learn.microsoft.com/azure/firewall/dns-details", - "service": "Firewall", + "description": "Set up a diagnostic setting to send the activity log to Log Analytics as the central destination for logging and monitoring. This allows you to monitor control plane activity on the App Service resource itself.", + "guid": "ee72734b-475b-4a18-bdbf-590ce65de8e0", + "link": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log", + "service": "App Services", "services": [ - "DNS", - "Firewall", + "AppSvc", + "Monitor", + "Entra", "WAF" ], "severity": "Medium", - "text": "Enable Azure Firewall DNS proxy configuration.", - "training": "https://learn.microsoft.com/training/courses/az-700t00/", + "text": "Send App Service activity logs to Log Analytics", "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "1dc04554-dece-4ffb-a49e-5c683e09f8da", - "link": "https://learn.microsoft.com/azure/firewall/firewall-diagnostics", - "service": "Firewall", + "description": "Use regional VNet integration, Network Security Groups (NSGs), and User-Defined Routes (UDRs) to control outbound network access. Route traffic through a Network Virtual Appliance (NVA), such as Azure Firewall, and monitor firewall logs to ensure traffic is properly controlled and secure.", + "guid": "c12159e1-14b9-433d-b574-ecccd9bd3baf", + "link": "https://learn.microsoft.com/azure/app-service/overview-vnet-integration", + "service": "App Services", "services": [ - "Firewall", + "AppSvc", + "Monitor", + "NVA", "WAF", - "Monitor" + "Firewall", + "VNet" ], - "severity": "High", - "text": "Integrate Azure Firewall with Azure Monitor and enable diagnostic logging to store and analyze firewall logs and metrics.", - "training": "https://learn.microsoft.com/training/courses/az-700t00/", - "waf": "Operations" + "severity": "Medium", + "text": "Control outbound network access for App Service using VNet integration, NSGs, UDRs, and firewalls.", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "64e7000e-3c06-485e-b455-ced7f454cba3", - "link": "https://learn.microsoft.com/azure/well-architected/service-guides/azure-firewall", - "service": "Firewall", + "description": "Provide a stable outbound IP by using VNet integration with a NAT Gateway or Network Virtual Appliance (NVA) like Azure Firewall. This enables the receiving party to allow-list based on IP, if necessary. For communications with Azure services, use mechanisms like Service Endpoints or private endpoints to avoid relying on static IPs, ensuring secure and efficient connectivity.", + "guid": "cda3b54e-b2eb-403d-b9a2-582718d2ddb1", + "link": "https://learn.microsoft.com/azure/app-service/networking/nat-gateway-integration", + "service": "App Services", "services": [ + "NVA", "WAF", - "Backup" + "Firewall", + "Storage", + "VNet", + "PrivateLink" ], "severity": "Low", - "text": "Implement backups for your firewall rules", - "training": "https://learn.microsoft.com/training/courses/az-104t00/", - "waf": "Operations" + "text": "Ensure a stable IP for outbound communications by using VNet NAT Gateway or Azure Firewall.", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false'", - "guid": "d38ad60c-bc9e-4d49-b699-97e5d4dcf707", - "link": "https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell", - "service": "Firewall", + "description": "Control inbound network access by configuring App Service Access Restrictions, Service Endpoints, or Private Endpoints. Ensure appropriate restrictions are set for both the web app and the SCM (deployment) site to limit unauthorized access and enhance security.", + "guid": "0725769e-e669-41a4-a34a-c932223ece80", + "link": "https://learn.microsoft.com/azure/app-service/networking-features#access-restrictions", + "service": "App Services", "services": [ - "Firewall", - "WAF", - "ACR" + "PrivateLink", + "AppSvc", + "WAF" ], "severity": "High", - "text": "Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance.", - "training": "https://learn.microsoft.com/training/courses/az-104t00/", - "waf": "Reliability" + "text": "Control inbound network access using Access Restrictions, Service Endpoints, or Private Endpoints.", + "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled'", - "guid": "e8143efa-0301-4d62-be54-ca7b5ce566dc", - "link": "https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview", - "service": "Firewall", + "description": "Protect App Service from malicious inbound traffic by deploying a Web Application Firewall (WAF) using Azure Application Gateway or Azure Front Door. Ensure WAF logs are monitored regularly to detect and respond to security threats.", + "guid": "b123071a-5416-4415-a33e-a3ad2c2de732", + "link": "https://learn.microsoft.com/azure/app-service/networking/app-gateway-with-service-endpoints", + "service": "App Services", "services": [ - "DDoS", - "Firewall", - "VNet", - "WAF" + "AppSvc", + "Monitor", + "AppGW", + "WAF", + "FrontDoor" ], "severity": "High", - "text": "Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. ", - "waf": "Reliability" + "text": "Use a Web Application Firewall (WAF) in front of App Service.", + "waf": "Security" }, { - "arm-service": "microsoft.network/applicationGateways", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "d301d6e8-72e5-42e3-911c-c58b5a4b1511", - "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", - "service": "App Gateway", + "description": "To prevent the Web Application Firewall (WAF) from being bypassed, lock down access to App Service by using Access Restrictions, Service Endpoints, and Private Endpoints. This ensures that all traffic is routed through the WAF, providing a secure front layer of protection.", + "guid": "165c3acb-ef4a-4be1-b8d3-9fda47768314", + "link": "https://learn.microsoft.com/azure/app-service/networking-features#access-restrictions", + "service": "App Services", "services": [ - "VNet", + "PrivateLink", + "AppSvc", "WAF" ], "severity": "High", - "text": "Do not disrupt control-plane communication for Azure PaaS services injected into a virtual networks, such as with a 0.0.0.0/0 route or an NSG rule that blocks control plane traffic.", - "training": "https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn", + "text": "Ensure the WAF cannot be bypassed by securing access to App Service.", "waf": "Security" }, { - "arm-service": "microsoft.network/expressRouteCircuits", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "b3e4563a-4d87-4397-98b6-62d6d15f512a", - "link": "https://learn.microsoft.com/azure/private-link/private-endpoint-overview", - "service": "ExpressRoute", + "description": "Ensure that the minimum TLS policy is set to 1.2 or higher, with a preference for TLS 1.3, to enhance security through stronger encryption protocols. TLS 1.3 provides additional security improvements and faster handshake times, reducing vulnerabilities associated with older versions.", + "graph": "appserviceresources | where type =~ 'microsoft.web/sites/config' | extend compliant = (properties.MinTlsVersion>=1.2) | distinct id,compliant", + "guid": "c115775c-2ea5-45b4-9ad4-8408ee72734b", + "link": "https://learn.microsoft.com/azure/app-service/configure-ssl-bindings#enforce-tls-versions", + "service": "App Services", "services": [ - "PrivateLink", - "ExpressRoute", + "AppSvc", + "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Access Azure PaaS services from on-premises via private endpoints and ExpressRoute private peering. This method avoids transiting over the public internet.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "text": "Set minimum TLS policy to 1.2 or higher, preferably 1.3, in App Service configuration.", "waf": "Security" }, { - "arm-service": "Microsoft.Network/virtualNetworks", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc", - "guid": "4704489a-8042-4d88-b79d-17b73b22a5a6", - "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview", - "service": "VNet", + "description": "Configure App Service to enforce HTTPS-only, automatically redirecting all HTTP traffic to HTTPS. Additionally, implement HTTP Strict Transport Security (HSTS) in your code or via a Web Application Firewall (WAF) to ensure browsers only access the site over HTTPS, enhancing security by preventing downgrade attacks.", + "graph": "where (type=='microsoft.web/sites' and (kind == 'app' or kind == 'app,linux' )) | extend compliant = (properties.httpsOnly==true) | distinct id,compliant", + "guid": "475ba18f-dbf5-490c-b65d-e8e03f9bcbd4", + "link": "https://learn.microsoft.com/azure/app-service/configure-ssl-bindings#enforce-https", + "service": "App Services", "services": [ - "VNet", + "AppSvc", "WAF" ], "severity": "High", - "text": "Don't enable virtual network service endpoints by default on all subnets.", - "training": "https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn", + "text": "Use HTTPS only and consider enabling HTTP Strict Transport Security (HSTS).", "waf": "Security" }, { - "arm-service": "Microsoft.Network/azureFirewalls", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "7e7a8ed4-b30e-438c-9f29-812b2363cefe", - "link": "azure/private-link/inspect-traffic-with-azure-firewall", - "service": "Firewall", + "description": "Do not use wildcards (*) in your CORS configuration, as this permits unrestricted access from any origin, compromising security. Instead, explicitly specify trusted origins that are allowed to access the service, ensuring controlled access.", + "guid": "68266abc-a264-4f9a-89ae-d9c55d04c2c3", + "link": "https://learn.microsoft.com/azure/app-service/app-service-web-tutorial-rest-api", + "service": "App Services", "services": [ - "DNS", - "NVA", - "PrivateLink", - "Firewall", + "Storage", "WAF" ], - "severity": "Medium", - "text": "Filter egress traffic to Azure PaaS services using FQDNs instead of IP addresses in Azure Firewall or an NVA to prevent data exfiltration. If using Private Link you can block all FQDNs, otherwise allow only the required PaaS services.", - "training": "https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn", - "waf": "Security" - }, - { - "arm-service": "microsoft.network/expressRouteCircuits", - "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant", - "guid": "f2aad7e3-bb03-4adc-8606-4123d342a917", - "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway", - "service": "ExpressRoute", - "services": [ - "VPN", - "ExpressRoute", - "WAF", - "VNet" - ], "severity": "High", - "text": "Use at least a /27 prefix for your Gateway subnets.", + "text": "Avoid using wildcards for CORS; specify allowed origins explicitly.", "waf": "Security" }, { - "arm-service": "Microsoft.Network/networkSecurityGroups", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)", - "guid": "11deb39d-8299-4e47-bbe0-0fb5a36318a8", - "link": "https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags", - "service": "NSG", + "description": "Remote debugging should not be enabled in production as it opens additional ports, increasing the attack surface. Although App Service automatically turns off remote debugging after 48 hours, it is recommended to disable it manually in production to maintain a secure environment.", + "graph": "appserviceresources | where type =~ 'microsoft.web/sites/config' | extend compliant = (properties.RemoteDebuggingEnabled == false) | distinct id,compliant", + "guid": "d9bd3baf-cda3-4b54-bb2e-b03dd9a25827", + "link": "https://learn.microsoft.com/azure/app-service/configure-common#configure-general-settings", + "service": "App Services", "services": [ - "VNet", + "AppSvc", "WAF" ], "severity": "High", - "text": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity.", + "text": "Turn off remote debugging in production environments.", "waf": "Security" }, { - "arm-service": "Microsoft.Network/networkSecurityGroups", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant", - "guid": "872e52e3-611c-4c58-a5a4-b1511e43a58a", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation", - "service": "NSG", + "description": "Enable Defender for App Service. This (amongst other threats) detects communications to known malicious IP addresses. Review the recommendations from Defender for App Service as part of your operations.", + "guid": "18d2ddb1-0725-4769-be66-91a4834ac932", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-app-service-introduction", + "service": "App Services", "services": [ - "VNet", - "WAF", - "ACR" + "Defender", + "AppSvc", + "WAF" ], "severity": "Medium", - "text": "Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones).", - "training": "https://learn.microsoft.com/learn/paths/implement-network-security/", + "text": "Enable Defender for Cloud - Defender for App Service", "waf": "Security" }, { - "arm-service": "Microsoft.Network/networkSecurityGroups", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "a4d87397-48b6-462d-9d15-f512a65498f6", - "link": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", - "service": "NSG", + "description": "Azure provides DDoS Basic protection on its network, which can be improved with intelligent DDoS Standard capabilities which learns about normal traffic patterns and can detect unusual behavior. DDoS Standard applies to a Virtual Network so it must be configured for the network resource in front of the app, such as Application Gateway or an NVA.", + "guid": "223ece80-b123-4071-a541-6415833ea3ad", + "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", + "service": "App Services", "services": [ "NVA", - "VNet", "WAF", - "Entra" + "EventHubs", + "AppGW", + "VNet", + "DDoS" ], "severity": "Medium", - "text": "Use NSGs and application security groups to micro-segment traffic within the landing zone and avoid using a central NVA to filter traffic flows.", - "training": "https://learn.microsoft.com/learn/paths/implement-network-security/", + "text": "Enable DDOS Protection Standard on the WAF VNet", "waf": "Security" }, { - "arm-service": "Microsoft.Network/networkSecurityGroups", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant", - "guid": "dfe237de-143b-416c-91d7-aa9b64704489", - "link": "https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview", - "service": "NSG", + "description": "When using images stored in Azure Container Registry, ensure they are pulled over a virtual network by using a private endpoint and configuring the app setting 'WEBSITE_PULL_IMAGE_OVER_VNET'. This ensures secure communication between App Service and the registry, preventing exposure to the public internet.", + "guid": "2c2de732-165c-43ac-aef4-abe1f8d39fda", + "link": "https://learn.microsoft.com/azure/app-service/configure-custom-container#use-an-image-from-a-network-protected-registry", + "service": "App Services", "services": [ - "NetworkWatcher", + "ACR", + "AppSvc", + "WAF", "VNet", - "WAF" + "PrivateLink" ], "severity": "Medium", - "text": "Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows.", - "training": "https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/", + "text": "Pull container images over a Virtual Network from Azure Container Registry.", "waf": "Security" }, { - "arm-service": "Microsoft.Network/networkSecurityGroups", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900)", - "guid": "0390417d-53dc-44d9-b3f4-c8832f359b41", - "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits", - "service": "NSG", + "description": "Perform a penetration test on the web application in accordance with Azure's penetration testing rules of engagement. This helps identify vulnerabilities and security weaknesses that can be addressed before they are exploited.", + "guid": "eb2eb03d-d9a2-4582-918d-2ddb10725769", + "link": "https://learn.microsoft.com/azure/security/fundamentals/pen-testing", + "service": "App Services", "services": [ - "VNet", "WAF" ], "severity": "Medium", - "text": "Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules.", - "training": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", - "waf": "Reliability" + "text": "Conduct a penetration test on the web application.", + "waf": "Security" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "412e7f98-3f63-4047-82dd-69c5b5c2622f", - "link": "https://learn.microsoft.com/azure/virtual-wan/scenario-any-to-any", - "service": "VWAN", + "description": "Ensure that only trusted code, which has been validated and scanned for vulnerabilities, is deployed to production following DevSecOps practices. This minimizes the risk of introducing security vulnerabilities into the application environment.", + "guid": "19aed9c5-5d04-4c2c-9919-ca0b2c12159e", + "link": "https://learn.microsoft.com/azure/architecture/solution-ideas/articles/devsecops-in-azure", + "service": "App Services", "services": [ - "VWAN", "WAF" ], "severity": "Medium", - "text": "Use Virtual WAN if your scenario is explicitly described in the list of Virtual WAN routing designs.", - "training": "https://learn.microsoft.com/learn/modules/introduction-azure-virtual-wan/", - "waf": "Operations" + "text": "Deploy validated and vulnerability-scanned code.", + "waf": "Security" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "54b69bad-33aa-4d5e-ac68-e1d76667313b", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/virtual-wan-network-topology#virtual-wan-network-design-recommendationst", - "service": "VWAN", + "description": "Ensure that the latest versions of supported platforms, programming languages, protocols, and frameworks are used. Regular updates mitigate the risk of security vulnerabilities and ensure compatibility with security patches.", + "guid": "114b933d-f574-4ecc-ad9b-d3bafcda3b54", + "link": "https://learn.microsoft.com/azure/app-service/overview-patch-os-runtime", + "service": "App Services", "services": [ - "VWAN", - "WAF", - "ACR" + "WAF" ], - "severity": "Medium", - "text": "Use a Virtual WAN hub per Azure region to connect multiple landing zones together across Azure regions via a common global Azure Virtual WAN.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", - "waf": "Performance" + "severity": "High", + "text": "Use up-to-date platforms, languages, protocols and frameworks", + "waf": "Security" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant", - "guid": "7d5d1e4e-6146-458d-9558-fd77249b8211", - "link": "https://learn.microsoft.com/azure/virtual-wan/howto-firewall", - "service": "VWAN", + "description": "Leverage Auto-Healing in Azure App Service to automatically restart instances or trigger custom actions based on pre-defined failure conditions like memory thresholds, HTTP errors, or specific event logs.", + "guid": "60b3a935-33e5-45c9-87c7-53882e395b46", + "link": "https://learn.microsoft.com/azure/app-service/overview-diagnostics", + "service": "App Services", "services": [ - "Firewall", + "AppSvc", "WAF" ], "severity": "Medium", - "text": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs.", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Security" + "text": "Use Auto-Healing with custom rules to restart App Service instances automatically when failures occur.", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "6667313b-4f56-464b-9e98-4a859c773e7d", - "link": "https://learn.microsoft.com/azure/virtual-wan/migrate-from-hub-spoke-topology", - "service": "VWAN", + "description": "Configure Azure Monitor alerts based on Application Insights metrics for response times, failure rates, and overall availability. Alerts help detect issues proactively and reduce mean-time-to-recovery (MTTR).", + "guid": "e52e4514-02a7-4e81-a98e-88ce1b18e557", + "link": "https://learn.microsoft.com/azure/azure-monitor/app/alerts", + "service": "App Services", "services": [ - "VWAN", + "Monitor", "WAF" ], "severity": "Medium", - "text": "Ensure that your virtual WAN network architecture aligns to an identified architecture scenario.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "text": "Set up alerts for critical Application Insights metrics, such as response time and failure rates.", "waf": "Reliability" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "guid": "261623a7-65a9-417e-8f34-8ef254c27d42", - "link": "https://learn.microsoft.com/azure/virtual-wan/azure-monitor-insights", - "service": "VWAN", + "description": "Use Azure Policy to enforce security, compliance, and governance configurations for App Service. Policies can ensure that critical settings such as TLS versions, backup configurations, and network restrictions are enforced across all App Service instances.", + "guid": "361e886f-ca40-4ead-a8e9-1379c642ae9c", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "service": "App Services", "services": [ - "VWAN", + "ACR", + "AppSvc", + "Backup", "WAF", - "Monitor" + "AzurePolicy" ], - "severity": "Medium", - "text": "Use Azure Monitor Insights for Virtual WAN to monitor the end-to-end topology of the Virtual WAN, status, and key metrics.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", - "waf": "Operations" + "severity": "High", + "text": "Apply Azure Policy to enforce compliance across App Service configurations.", + "waf": "Governance" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant", - "guid": "727c77e1-b9aa-4a37-a024-129d042422c1", - "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan", - "service": "VWAN", + "description": "Leverage Azure Cost Management to track and forecast App Service expenses. Set up alerts for budget thresholds to avoid overspending, and optimize costs based on resource utilization trends.", + "guid": "42eb48f0-28ff-497c-b2c0-a8fa1f989832", + "link": "https://learn.microsoft.com/azure/cost-management-billing/", + "service": "App Services", "services": [ - "VWAN", + "Cost", + "AppSvc", + "Monitor", "WAF" ], - "severity": "Medium", - "text": "Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", - "waf": "Reliability" + "severity": "Low", + "text": "Monitor App Service costs using Azure Cost Management and create cost alerts.", + "waf": "Cost" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "microsoft.web/sites", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant", - "guid": "d49ac006-6670-4bc9-9948-d3e0a3a94f4d", - "link": "https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference", - "service": "VWAN", + "description": "If you have predictable and steady usage of App Service, purchasing Reserved Instances can significantly reduce long-term costs. Commit to one or three years for lower pricing compared to pay-as-you-go.", + "guid": "e489221b-487e-48a3-aaab-48e3d205ca12", + "link": "https://learn.microsoft.com/azure/cost-management-billing/reservations/", + "service": "App Services", "services": [ - "VPN", - "ExpressRoute", + "AppSvc", + "Cost", + "ARS", + "Storage", "WAF" ], "severity": "Medium", - "text": "Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", - "waf": "Reliability" + "text": "Purchase reserved instances for App Service plans to optimize long-term costs.", + "waf": "Cost" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "2586b854-237e-47f1-84a1-d45d4cd2310d", - "link": "https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing#labels", - "service": "VWAN", + "guid": "3b7a56de-5020-4642-b3cb-c976e80b6d6d", + "link": "https://learn.microsoft.com/azure/logic-apps/single-tenant-overview-compare", + "service": "Logic Apps", "services": [ - "VWAN", "WAF" ], - "severity": "Medium", - "text": "Configure label-based propagation in Virtual WAN, otherwise connectivity between virtual hubs will be impaired.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "severity": "High", + "text": "Select the right Logic App hosting plan based on your business & SLO requirements", "waf": "Reliability" }, { - "arm-service": "microsoft.network/virtualWans", + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant", - "guid": "9c75dfef-573c-461c-a698-68598595581a", - "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation", - "service": "VWAN", + "guid": "3d7008bd-6bc1-4b03-8aa8-ec2a3b55786a", + "link": "https://learn.microsoft.com/azure/logic-apps/set-up-zone-redundancy-availability-zones?tabs=standard#next-steps", + "service": "Logic Apps", "services": [ "WAF" ], "severity": "High", - "text": "Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "text": "Protect logic apps from region failures with zone redundancy and availability zones", "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "5c986cb2-9131-456a-8247-6e49f541acdc", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "Policy", + "guid": "1cda768f-a206-445d-8234-56f6a6e7286e", + "link": "https://learn.microsoft.com/azure/logic-apps/business-continuity-disaster-recovery-guidance?toc=%2Fazure%2Freliability%2Ftoc.json&bc=%2Fazure%2Freliability%2Fbreadcrumb%2Ftoc.json", + "service": "Logic Apps", "services": [ - "AzurePolicy", "WAF" ], "severity": "High", - "text": "Leverage Azure Policy strategically, define controls for your environment, using Policy Initiatives to group related policies.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", - "waf": "Security" + "text": "Consider a Cross-Region DR strategy for critical workloads", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "d8a2adb1-17d6-4326-af62-5ca44e5695f2", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "Policy", + "guid": "82118ec5-ed6f-4c68-9471-eb0da98a1b34", + "link": "https://learn.microsoft.com/azure/app-service/environment/intro", + "service": "Logic Apps", "services": [ - "AzurePolicy", - "RBAC", + "AppSvc", "WAF" ], - "severity": "Medium", - "text": "Map regulatory and compliance requirements to Azure Policy definitions and Azure role assignments.", - "training": "https://learn.microsoft.com/training/modules/governance-security/", - "waf": "Security" + "severity": "High", + "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "223ace8c-b123-408c-a501-7f154e3ab369", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "Policy", + "guid": "74275fa5-9e08-4c7e-b096-13b538fe1501", + "link": "https://learn.microsoft.com/training/modules/deploy-azure-functions/", + "service": "Logic Apps", "services": [ - "AzurePolicy", - "Subscriptions", "WAF" ], "severity": "Medium", - "text": "Establish Azure Policy definitions at the intermediate root management group so that they can be assigned at inherited scopes.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", - "waf": "Security" + "text": "Leverage Azure DevOps or GitHub to streamline CI/CD and safeguard your Logic App code", + "waf": "Operations" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "3829e7e3-1618-4368-9a04-77a209945bda", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "Policy", + "guid": "ac1d6380-f866-4bbd-a9b4-b1ee5d7908b8", + "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#availability-zones", + "service": "IoT", "services": [ - "AzurePolicy", "WAF" ], "severity": "High", - "text": "Manage policy assignments at the highest appropriate level with exclusions at bottom levels, if required.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", - "waf": "Security" + "text": "Leverage Availability Zones if regionally applicable (this is automatically enabled)", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "43334f24-9116-4341-a2ba-527526944008", - "link": "https://learn.microsoft.com/security/benchmark/azure/mcsb-asset-management#am-2-use-only-approved-services", - "service": "Policy", + "guid": "35f651e8-0124-4ef7-8c57-658e38609e6e", + "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#microsoft-initiated-failover", + "service": "IoT", "services": [ - "AzurePolicy", - "Subscriptions", "WAF" ], - "severity": "Low", - "text": "Use Azure Policy to control which services users can provision at the subscription/management group level.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", - "waf": "Security" + "severity": "Medium", + "text": "Be aware of Microsoft-initiated failovers. These are exercised by Microsoft in rare situations to fail over all the IoT hubs from an affected region to the corresponding geo-paired region.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "be7d7e48-4327-46d8-adc0-55bcf619e8a1", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "Policy", + "guid": "4ed3e490-dc06-4a1e-b467-5d0239d85540", + "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#cross-region-dr", + "service": "IoT", "services": [ - "AzurePolicy", "WAF" ], "severity": "High", - "text": "Use built-in policies where possible to minimize operational overhead.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", - "waf": "Security" + "text": "Consider a Cross-Region DR strategy for critical workloads", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "description": "Assigning the Resource Policy Contributor role to specific scopes allows you to delegate policy management to relevant teams. For instance, a central IT team may oversee management group-level policies, while application teams handle policies for their subscriptions, enabling distributed governance with adherence to organizational standards.", - "guid": "3f988795-25d6-4268-a6d7-0ba6c97be995", - "link": "https://learn.microsoft.com/azure/governance/policy/overview#azure-rbac-permissions-in-azure-policy", - "service": "Policy", + "guid": "a11ecab0-db47-46f7-9aa7-17764e7e45a1", + "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#microsoft-initiated-failover", + "service": "IoT", "services": [ - "Entra", - "AzurePolicy", - "RBAC", - "Subscriptions", "WAF" ], - "severity": "Medium", - "text": "Assign the built-in Resource Policy Contributor role at a particular scope to enable application-level governance.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", - "waf": "Security" + "severity": "High", + "text": "Learn how to trigger a manual failover.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "19048384-5c98-46cb-8913-156a12476e49", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "Policy", + "guid": "f9db8dfb-1194-460b-aedd-34dd6a69db22", + "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#failback", + "service": "IoT", "services": [ - "AzurePolicy", - "Subscriptions", "WAF" ], - "severity": "Medium", - "text": "Limit the number of Azure Policy assignments made at the root management group scope to avoid managing through exclusions at inherited scopes.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", - "waf": "Security" + "severity": "High", + "text": "Learn how to fail back after a failover.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Search/searchServices", "checklist": "WAF checklist", - "guid": "5a917e1f-348e-4f25-9c27-d42e8bbac757", - "link": "https://learn.microsoft.com/industry/release-plan/2023wave2/cloud-sovereignty/enable-data-sovereignty-policy-baseline", - "service": "Policy", + "guid": "41faa1ed-b7f0-447d-8cba-4a4905e5bb83", + "link": "https://learn.microsoft.com/azure/search/search-reliability#high-availability", + "service": "Cognitive Search", "services": [ - "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "If any data sovereignty requirements exist, Azure Policies should be deployed to enforce them.", - "training": "https://learn.microsoft.com/learn/paths/secure-your-cloud-data/", - "waf": "Security" + "severity": "High", + "text": "Enable 2 replicas to have 99.9% availability for read operations", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Search/searchServices", "checklist": "WAF checklist", - "guid": "78b22132-b41c-460b-a4d3-df8f73a67dc2", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/sovereign-landing-zone", - "service": "Policy", + "guid": "7d956fd9-788a-4845-9b9f-c0340972d810", + "link": "https://learn.microsoft.com/azure/search/search-reliability#high-availability", + "service": "Cognitive Search", "services": [ - "AzurePolicy", - "Subscriptions", "WAF" ], "severity": "Medium", - "text": "For Sovereign Landing Zone, deploy sovereignty policy baseline and assign at correct management group level.", - "waf": "Security" + "text": "Enable 3 replicas to have 99.9% availability for read/write operations", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Search/searchServices", "checklist": "WAF checklist", - "guid": "caeea0e9-1024-41df-a52e-d99c3f22a6f4", - "link": "https://learn.microsoft.com/industry/sovereignty/policy-portfolio-baseline", - "service": "Policy", + "guid": "44dc5f2b-a032-4d03-aae8-90c3f2c0a4c3", + "link": "https://learn.microsoft.com/azure/search/search-reliability#availability-zone-support", + "service": "Cognitive Search", "services": [ - "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "For Sovereign Landing Zone, document Sovereign Control objectives to policy mapping.", - "waf": "Security" + "severity": "High", + "text": "Leverage Availability Zones by enabling read and/or write replicas", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Authorization/policyDefinitions", + "arm-service": "Microsoft.Search/searchServices", "checklist": "WAF checklist", - "guid": "9b461617-db7b-4399-8ac6-d4eb7153893a", - "link": "https://learn.microsoft.com/industry/sovereignty/policy-portfolio-baseline#sovereignty-baseline-policy-initiatives", - "service": "Policy", + "guid": "cd0730f0-0ff1-4b77-9a2b-2a1f7dd5e291", + "link": "https://learn.microsoft.com/azure/search/search-reliability#multiple-services-in-separate-geographic-regions", + "service": "Cognitive Search", "services": [ - "AzurePolicy", + "ACR", "WAF" ], "severity": "Medium", - "text": "For Sovereign Landing Zone, ensure process is in place for management of 'Sovereign Control objectives to policy mapping'.", - "waf": "Security" + "text": "For regional redudancy, Manually create services in 2 or more regions for Search as it doesn't provide an automated method of replicating search indexes across geographic regions", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "Microsoft.Search/searchServices", "checklist": "WAF checklist", - "guid": "67e7a8ed-4b30-4e38-a3f2-9812b2363cef", - "link": "https://learn.microsoft.com/en-us/azure/azure-monitor/logs/workspace-design#azure-regions", - "service": "Monitor", + "guid": "3c964882-aec9-4d44-9f68-4b5f2efbbdb6", + "link": "https://learn.microsoft.com/azure/search/search-reliability#synchronize-data-across-multiple-services", + "service": "Cognitive Search", "services": [ - "Entra", - "Monitor", - "AzurePolicy", - "RBAC", + "ACR", "WAF" ], "severity": "Medium", - "text": "Use a single monitor logs workspace to manage platforms centrally except where Azure role-based access control (Azure RBAC), data sovereignty requirements, or data retention policies mandate separate workspaces.", - "training": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", - "waf": "Operations" + "text": "To synchronize data across multiple services either Use indexers for updating content on multiple services or Use REST APIs for pushing content updates on multiple services", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "Microsoft.Search/searchServices", "checklist": "WAF checklist", - "guid": "7418ada9-4199-4c28-8286-d15e9433e8f3", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", - "service": "Monitor", + "guid": "85ee93c9-f53c-4803-be51-e6e4aa37ff4e", + "link": "https://learn.microsoft.com/azure/search/search-reliability#use-azure-traffic-manager-to-coordinate-requests", + "service": "Cognitive Search", "services": [ - "WAF", - "Monitor" + "TrafficManager", + "WAF" ], "severity": "Medium", - "text": "Decide whether to use a single Azure Monitor Logs workspace for all regions or to create multiple workspaces to cover various geographical regions. Each approach has advantages and disadvantages, including potential cross-region networking charges", - "training": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", + "text": "Use Azure Traffic Manager to coordinate requests", "waf": "Reliability" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "Microsoft.Search/searchServices", "checklist": "WAF checklist", - "guid": "5e6c4cfd-3e50-4454-9c24-47ec66138a72", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/data-retention-archive?tabs=portal-1%2Cportal-2#how-retention-and-archiving-work", - "service": "Monitor", + "guid": "7be10278-57c1-4a61-8ee3-895aebfec5aa", + "link": "https://learn.microsoft.com/azure/search/search-reliability#back-up-and-restore-alternatives", + "service": "Cognitive Search", "services": [ - "AzurePolicy", "Storage", - "WAF", - "ARS" + "Backup", + "WAF" ], "severity": "High", - "text": "Export logs to Azure Storage if your log retention requirements exceed twelve years. Use immutable storage with a write-once, read-many policy to make data non-erasable and non-modifiable for a user-specified interval.", - "training": "https://learn.microsoft.com/learn/paths/architect-infrastructure-operations/", - "waf": "Operations" + "text": "Backup and Restore an Azure Cognitive Search Index. Use this sample code to back up index definition and snapshot to a series of Json files", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.BotService/botServices", "checklist": "WAF checklist", - "guid": "e7d7e484-3276-4d8b-bc05-5bcf619e8a13", - "link": "https://learn.microsoft.com/azure/governance/machine-configuration/overview", - "service": "VM", + "guid": "6ad48408-ee72-4734-a476-ba28fdcf590c", + "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-bot", + "service": "Bot service", "services": [ - "AzurePolicy", - "VM", - "WAF", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Monitor OS level virtual machine (VM) configuration drift using Azure Policy. Enabling Azure Automanage Machine Configuration audit capabilities through policy helps application team workloads to immediately consume feature capabilities with little effort.", - "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", - "waf": "Operations" + "text": "Follow reliability support recommendations in Azure Bot Service", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.BotService/botServices", "checklist": "WAF checklist", - "guid": "f9887952-5d62-4688-9d70-ba6c97be9951", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#update-management-considerations", - "service": "VM", + "guid": "e65de8e1-3f9c-4cbd-9682-66abca264f9a", + "link": "https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-concept-regionalization", + "service": "Bot service", "services": [ - "VM", "WAF" ], "severity": "Medium", - "text": "Use Azure Update Manager as a patching mechanism for Windows and Linux VMs in Azure.", - "training": "https://learn.microsoft.com/azure/update-manager/overview?tabs=azure-vms", - "waf": "Operations" + "text": "Deploying bots with local data residency and regional compliance", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.BotService/botServices", "checklist": "WAF checklist", - "guid": "c806c048-26b7-4ddf-b4c2-b4f0c476925d", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#update-management-considerations ", - "service": "VM", + "guid": "19bfe9d5-5d04-4c3c-9919-ca1b2d1215ae", + "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-bot#cross-region-disaster-recovery-in-multi-region-geography", + "service": "Bot service", "services": [ - "VM", "WAF" ], "severity": "Medium", - "text": "Use Azure Update Manager as a patching mechanism for Windows and Linux VMs outside of Azure using Azure Arc.", - "training": "https://learn.microsoft.com/azure/update-manager/overview?tabs=azure-vms", - "waf": "Operations" + "text": "Azure Bot Service runs in active-active mode for both global and regional services. When an outage occurs, you don't need to detect errors or manage the service. Azure Bot Service automatically performs auto failover and auto recovery in a multi-region geographical architecture. For the EU bot regional service, Azure Bot Service provides two full regions inside Europe with active/active replication to ensure redundancy. For the global bot service, all available regions/geographies can be served as the global footprint.", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/networkWatchers", + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "guid": "90483845-c986-4cb2-a131-56a12476e49f", - "link": "https://learn.microsoft.com/azure/network-watcher/network-watcher-monitoring-overview", - "service": "Network Watcher", + "guid": "a95b86ad-8840-48e3-9273-4b875ba18f20", + "link": "https://learn.microsoft.com/azure/architecture/guide/multitenant/considerations/tenancy-models", + "service": "Azure Monitor", "services": [ - "NetworkWatcher", - "WAF", - "Monitor" + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Use Network Watcher to proactively monitor traffic flows.", - "training": "https://learn.microsoft.com/learn/modules/configure-network-watcher/", - "waf": "Operations" + "text": "Data collection rules in Azure Monitor -https://learn.microsoft.com/azure/azure-monitor/essentials/data-collection-rule-overview", + "training": "https://azure.microsoft.com/pricing/reservations/", + "waf": "Cost" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "6944008b-e7d7-4e48-9327-6d8bdc055bcf", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-setup-guide/monitoring-reporting?tabs=AzureMonitor", - "service": "Monitor", + "guid": "45901365-d38e-443f-abcb-d868266abca2", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/automation", + "service": "Azure Backup", "services": [ - "WAF", - "Monitor" + "Backup", + "WAF" ], "severity": "Medium", - "text": "Use Azure Monitor Logs for insights and reporting.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-monitor/", - "waf": "Operations" + "text": "check backup instances with the underlying datasource not found", + "waf": "Cost" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "97be9951-9048-4384-9c98-6cb2913156a1", - "link": "https://learn.microsoft.com/azure/azure-monitor/alerts/alerts-overview", - "service": "Monitor", + "guid": "64f9a19a-f29c-495d-94c6-c7919ca0f6c5", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/lighthouse", + "service": "VM", "services": [ - "WAF", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Use Azure Monitor alerts for the generation of operational alerts.", - "training": "https://learn.microsoft.com/training/modules/incident-response-with-alerting-on-azure/", - "waf": "Operations" + "text": "Delete or archive unassociated services (disks, nics, ip addresses etc)", + "waf": "Cost" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "fed3c55f-a67e-4875-aadd-3aba3f9fde31", - "link": "https://learn.microsoft.com/azure/automation/how-to/region-mappings", - "service": "Monitor", + "guid": "69bad37a-ad53-4cc7-ae1d-76667357c449", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", + "service": "Azure Backup", "services": [ - "WAF", - "Monitor" + "Storage", + "Backup", + "ASR", + "WAF" ], "severity": "Medium", - "text": "When using Change and Inventory Tracking via Azure Automation Accounts, ensure that you have selected supported regions for linking your Log Analytics workspace and automation accounts together.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-automation-devops/", - "waf": "Operations" + "text": "Consider a good balance between site recovery storage and backup for non mission critical applications", + "waf": "Cost" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "guid": "eba8cf22-45c6-4dc1-9b57-2cceb3b97ce5", - "link": "https://learn.microsoft.com/azure/storage/common/storage-redundancy", - "service": "Backup", + "guid": "674b5ed8-5a85-49c7-933b-e2a1a27b765a", + "link": "https://learn.microsoft.com/azure/cost-management-billing/manage/direct-ea-administration#manage-notification-contacts", + "service": "Azure Monitor", "services": [ - "WAF", - "Backup" + "Monitor", + "WAF" ], - "severity": "Low", - "text": "When using Azure Backup, use the correct backup types (GRS, ZRS & LRS) for your backup, as the default setting is GRS.", - "training": "https://learn.microsoft.com/training/modules/design-solution-for-backup-disaster-recovery/", - "waf": "Reliability" + "severity": "Medium", + "text": "Check spending and savings opportunities among the 40 different log analytics workspaces- use different retention and data collection for nonprod workspaces-create daily cap for awareness and tier sizing - If you do set a daily cap, in addition to creating an alert when the cap is reached,ensure that you also create an alert rule to be notified when some percentage has been reached (90% for example). - consider workspace transformation if possible - https://learn.microsoft.com/azure/azure-monitor/essentials/data-collection-transformations#workspace-transformation-dcr ", + "training": "https://learn.microsoft.com/azure/cost-management-billing/costs/understand-work-scopes", + "waf": "Cost" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "guid": "f541acdc-e979-4377-acdb-3751ab2ab13a", - "link": "https://learn.microsoft.com/azure/governance/policy/concepts/guest-configuration", - "service": "VM", + "guid": "91be1f38-8ef3-494c-8bd4-63cbbac75819", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", + "service": "Azure Monitor", "services": [ + "Storage", "AzurePolicy", - "VM", "WAF" ], "severity": "Medium", - "text": "Use Azure guest policies to automatically deploy software configurations through VM extensions and enforce a compliant baseline VM configuration.", - "waf": "Security" + "text": "Enforce a purging log policy and automation (if needed, logs can be moved to cold storage)", + "training": "https://www.youtube.com/watch?v=nHQYcYGKuyw", + "waf": "Cost" }, { "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "description": "Use Azure Policy's guest configuration features to audit and remediate machine settings (e.g., OS, application, environment) to ensure resources align with expected configurations, and Update Management can enforce patch management for VMs.", - "guid": "da6e55d7-d8a2-4adb-817d-6326af625ca4", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#monitoring-for-configuration-drift", + "guid": "6aae01e6-a84d-4e5d-b36d-1d92881a1bd5", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", "service": "VM", "services": [ + "Storage", + "Backup", + "WAF" + ], + "severity": "Medium", + "text": "Check that the disks are really needed, if not: delete. If they are needed, find lower storage tiers or use backup -", + "training": "https://learn.microsoft.com/azure/cost-management-billing/costs/manage-automation", + "waf": "Cost" + }, + { + "arm-service": "Microsoft.Storage/storageAccounts", + "checklist": "WAF checklist", + "guid": "d1e44a19-659d-4395-afd7-7289b835556d", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", + "service": "Storage", + "services": [ + "Storage", "AzurePolicy", - "VM", - "WAF", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Monitor VM security configuration drift via Azure Policy.", - "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/", - "waf": "Security" + "text": "Consider moving unused storage to lower tier, with customized rule - https://learn.microsoft.com/azure/storage/blobs/lifecycle-management-policy-configure ", + "training": "https://learn.microsoft.com/azure/cost-management-billing/costs/enable-tag-inheritance", + "waf": "Cost" }, { "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "2476e49f-541a-4cdc-b979-377bcdb3751a", - "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", + "guid": "d0102cac-6aae-401e-9a84-de5de36d1d92", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", "service": "VM", "services": [ "VM", - "ASR", - "WAF", - "ACR" + "WAF" ], "severity": "Medium", - "text": "Use Azure Site Recovery for Azure-to-Azure Virtual Machines disaster recovery scenarios. This enables you to replicate workloads across regions.", - "training": "https://learn.microsoft.com/training/modules/protect-infrastructure-with-site-recovery/", - "waf": "Operations" + "text": "Make sure advisor is configured for VM right sizing ", + "waf": "Cost" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "f625ca44-e569-45f2-823a-ce8cb12308ca", - "link": "https://learn.microsoft.com/azure/backup/backup-center-overview", - "service": "Backup", + "description": "check by searching the Meter Category Licenses in the Cost analysys", + "guid": "59ae568b-a38d-4498-9e22-13dbd7bb012f", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/manage/centralize-operations", + "service": "VM", "services": [ - "WAF", - "Backup" + "Cost", + "VM", + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Use Azure-native backup capabilities, or an Azure-compatible, 3rd-party backup solution.", - "training": "https://learn.microsoft.com/training/modules/design-solution-for-backup-disaster-recovery/", - "waf": "Operations" + "text": "run the script on all windows VMs https://learn.microsoft.com/azure/virtual-machines/windows/hybrid-use-benefit-licensing?ref=andrewmatveychuk.com#convert-an-existing-vm-using-azure-hybrid-benefit-for-windows-server- consider implementing a policy if windows VMs are created frequently", + "waf": "Cost" }, { - "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "89cc5e11-aa4d-4c3b-893d-feb99215266a", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-diagnostic-settings-to-save-your-wafs-logs", - "service": "WAF", + "guid": "7b95e06e-158e-42ea-9992-c2de6e2065b3", + "link": "https://learn.microsoft.com/azure/active-directory/privileged-identity-management/pim-configure", + "service": "VM", "services": [ - "AppGW", - "WAF", - "FrontDoor" + "LoadBalancer", + "WAF" ], - "severity": "High", - "text": "Add diagnostic settings to save WAF logs from application delivery services like Azure Front Door and Azure Application Gateway. Regularly review the logs to check for attacks and for false positive detections.", - "training": "https://learn.microsoft.com/training/modules/capture-application-logs-app-service/", - "waf": "Operations" + "severity": "Medium", + "text": " this can be also put under AHUB if you already have licenses https://learn.microsoft.com/azure/virtual-machines/linux/azure-hybrid-benefit-linux?tabs=rhelpayg%2Crhelbyos%2CrhelEnablebyos%2Crhelcompliance", + "waf": "Cost" }, { - "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "7f408960-c626-44cb-a018-347c8d790cdf", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", - "service": "WAF", + "guid": "75c1e945-b459-4837-bf7a-e7c6d3b475a5", + "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-groups-create-azure-portal", + "service": "VM", "services": [ - "AppGW", - "Sentinel", - "WAF", - "FrontDoor" + "VM", + "WAF" ], "severity": "Medium", - "text": "Send WAF logs from your application delivery services like Azure Front Door and Azure Application Gateway to Microsoft Sentinel. Detect attacks and integrate WAF telemetry into your overall Azure environment.", - "training": "https://learn.microsoft.com/training/paths/sc-200-connect-logs-to-azure-sentinel/", - "waf": "Operations" + "text": "Consolidate reserved VM families with flexibility option (no more than 4-5 families)", + "training": "https://learn.microsoft.com/azure/automation/automation-solution-vm-management", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "5017f154-e3ab-4369-9829-e7e316183687", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview", - "service": "Key Vault", + "guid": "c7acbe49-bbe6-44dd-a9f2-e87778468d55", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access#prerequisites-for-a-landing-zone---design-recommendations", + "service": "VM", "services": [ - "AKV", + "Cost", + "VM", + "ARS", "WAF" ], - "severity": "High", - "text": "Use Azure Key Vault to store your secrets and credentials.", - "training": "https://learn.microsoft.com/training/modules/implement-azure-key-vault/", - "waf": "Security" + "severity": "Medium", + "text": "Utilize Azure Reserved Instances: This feature allows you to reserve VMs for a period of 1 or 3 years, providing significant cost savings compared to PAYG prices.", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "ResourceContainers | where type=='microsoft.resources/subscriptions'| parse id with '/subscriptions/' SubscriptionID| project subscriptionId, SubscriptionName = name| join kind=leftouter (Resources| where type == 'microsoft.keyvault/vaults'| project id, name, subscriptionId) on subscriptionId| join kind= leftouter (Resources| where type == 'microsoft.keyvault/vaults'| summarize ResourceCount = count() by subscriptionId) on subscriptionId| extend RCount = iff(isnull(ResourceCount), 0, ResourceCount)| project-away ResourceCount| extend compliant = (RCount <> 1)", - "guid": "a0477a20-9945-4bda-9333-4f2491163418", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview-throttling", - "service": "Key Vault", + "guid": "a6bcca2b-4fea-41db-b3dd-95d48c7c891d", + "link": "https://learn.microsoft.com/azure/active-directory-domain-services/overview", + "service": "VM", "services": [ - "AKV", "WAF" ], "severity": "Medium", - "text": "Use different Azure Key Vaults for different applications and regions to avoid transaction scale limits and restrict access to secrets.", - "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/", - "waf": "Security" + "text": "Only larger disks can be reserved => 1 TiB -", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "2ba52752-6944-4008-ae7d-7e4843276d8b", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "cb1f7d57-59ae-4568-aa38-d4985e2213db", + "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/identity/adds-extend-domain", + "service": "VM", "services": [ - "AKV", - "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Provision Azure Key Vault with the soft delete and purge policies enabled to allow retention protection for deleted objects.", - "training": "https://learn.microsoft.com/training/modules/implement-azure-key-vault/", - "waf": "Security" + "text": "After the right-sizing optimization", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Sql/servers", "checklist": "WAF checklist", - "guid": "dc055bcf-619e-48a1-9f98-879525d62688", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "d7bb012f-7b95-4e06-b158-e2ea3992c2de", + "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy", + "service": "Azure SQL", "services": [ - "AKV", - "RBAC", - "WAF", - "Entra" + "Cost", + "SQL", + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Follow a least privilege model by limiting authorization to permanently delete keys, secrets, and certificates to specialized custom Microsoft Entra ID roles.", - "training": "https://learn.microsoft.com/training/modules/implement-azure-key-vault/", - "waf": "Security" + "text": "Check if applicable and enforce policy/change https://learn.microsoft.com/azure/azure-sql/azure-hybrid-benefit?view=azuresql&tabs=azure-portalhttps://learn.microsoft.com/azure/cost-management-billing/scope-level/create-sql-license-assignments?source=recommendations", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "6d70ba6c-97be-4995-8904-83845c986cb2", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "6e2065b3-a76a-4f4a-991e-8839ada46667", + "link": "https://learn.microsoft.com/azure/active-directory/roles/best-practices", + "service": "VM", "services": [ + "VM", "WAF" ], "severity": "Medium", - "text": "Automate the certificate management and renewal process with public certificate authorities to ease administration.", - "training": "https://learn.microsoft.com/en-us/training/modules/configure-and-manage-azure-key-vault/", - "waf": "Security" + "text": "The VM + license part discount (ahub + 3YRI) is around 70% discount", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "913156a1-2476-4e49-b541-acdce979377b", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "ccbd9792-a6bc-4ca2-a4fe-a1dbf3dd95d4", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", + "service": "VM", "services": [ + "VM", "WAF" ], "severity": "Medium", - "text": "Establish an automated process for key and certificate rotation.", - "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/", - "waf": "Security" + "text": "Consider using a VMSS to match demand rather than flat sizing", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "cdb3751a-b2ab-413a-ba6e-55d7d8a2adb1", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "c1b1cd52-1e54-4a29-a9de-39ac0e7c28dc", + "link": "https://learn.microsoft.com/azure/reliability/cross-region-replication-azure", + "service": "AKS", "services": [ - "AKV", - "PrivateLink", - "VNet", + "AKS", "WAF" ], "severity": "Medium", - "text": "Enable firewall and virtual network service endpoint or private endpoint on the vault to control access to the key vault.", - "training": "https://learn.microsoft.com/training/modules/design-implement-private-access-to-azure-services/", - "waf": "Security" + "text": "Use AKS autoscaler to match your clusters usage (make sure the pods requirements match the scaler)", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "17d6326a-f625-4ca4-9e56-95f2223ace8c", - "link": "https://learn.microsoft.com/azure/key-vault/general/monitor-key-vault", - "service": "Key Vault", + "guid": "44be3b1a-27f8-4b9e-a1be-1f38df03a822", + "link": "https://learn.microsoft.com/azure/azure-monitor/logs/data-retention-archive?tabs=portal-1%2Cportal-2#how-retention-and-archiving-work", + "service": "Azure Backup", "services": [ - "AKV", - "Entra", - "WAF", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Use the platform-central Azure Monitor Log Analytics workspace to audit key, certificate, and secret usage within each instance of Key Vault.", - "training": "https://learn.microsoft.com/training/modules/analyze-infrastructure-with-azure-monitor-logs/", - "waf": "Security" + "text": "Move recovery points to vault-archive where applicable (Validate)", + "training": "https://azure.microsoft.com/pricing/reservations/", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "b12308ca-5017-4f15-9e3a-b3693829e7e3", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "cd463cbb-bc8a-4c29-aebc-91a43da1dae2", + "link": "https://learn.microsoft.com/azure/databricks/clusters/cluster-config-best-practices#automatic-termination", + "service": "Databricks", "services": [ - "AKV", - "AzurePolicy", + "VM", + "LoadBalancer", "WAF" ], "severity": "Medium", - "text": "Delegate Key Vault instantiation and privileged access and use Azure Policy to enforce a consistent compliant configuration.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-key-vault-networking-settings/", - "waf": "Security" + "text": "Consider using Spot VMs with fallback where possible. Consider autotermination of clusters.", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "91163418-2ba5-4275-8694-4008be7d7e48", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "cc881470-607c-41cc-a0e6-14658dd458e9", + "link": "https://learn.microsoft.com/azure/governance/policy/how-to/guest-configuration-create", + "service": "Azure Functions", "services": [ - "AKV", "WAF" ], "severity": "Medium", - "text": "Use an Azure Key Vault per application per environment per region.", - "training": "https://learn.microsoft.com/training/modules/implement-azure-key-vault/", - "waf": "Security" + "text": "Functions - Reuse connections", + "training": "https://learn.microsoft.com/azure/cost-management-billing/reservations/reservation-apis?toc=%2Fazure%2Fcost-management-billing%2Ftoc.json", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "25d62688-6d70-4ba6-a97b-e99519048384", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "27139b82-1102-4dbd-9eaf-11e6f843e52f", + "link": "https://learn.microsoft.com/azure/automation/update-management/overview", + "service": "Azure Functions", "services": [ - "AKV", - "ASR", - "WAF", - "ACR" + "WAF" ], "severity": "Medium", - "text": "If you want to bring your own keys, this might not be supported across all considered services. Implement relevant mitigation so that inconsistencies don't hinder desired outcomes. Choose appropriate region pairs and disaster recovery regions that minimize latency.", - "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/", - "waf": "Security" + "text": "Functions - Cache data locally", + "training": "https://learn.microsoft.com/learn/paths/azure-administrator-manage-compute-resources/", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "4ac6b67c-b3a4-4ff9-8e87-b07a7ce7bbdb", - "link": "https://learn.microsoft.com/industry/sovereignty/key-management", - "service": "Key Vault", + "guid": "4722d928-c1b1-4cd5-81e5-4a29b9de39ac", + "link": "https://learn.microsoft.com/azure/network-watcher/network-watcher-monitoring-overview", + "service": "Azure Functions", "services": [ - "AKV", + "Storage", "WAF" ], "severity": "Medium", - "text": "For Sovereign Landing Zone, use Azure Key Vault managed HSM to store your secrets and credentials.", - "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/", - "waf": "Security" + "text": "Functions - Cold starts-Use the 'Run from package' functionality. This way, the code is downloaded as a single zip file. This can, for example, result in significant improvements with Javascript functions, which have a lot of node modules.Use language specific tools to reduce the package size, for example, tree shaking Javascript applications.", + "training": "https://learn.microsoft.com/learn/modules/configure-network-watcher/", + "waf": "Cost" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "4e5695f2-223a-4ce8-ab12-308ca5017f15", - "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-reports", - "service": "Entra", + "guid": "0e7c28dc-9366-4572-82bf-f4564b0d934a", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", + "service": "Azure Functions", "services": [ - "WAF", - "Entra" + "WAF" ], "severity": "Medium", - "text": "Use Microsoft Entra ID reporting capabilities to generate access control audit reports.", - "training": "https://learn.microsoft.com/training/modules/monitor-report-aad-security-events/", - "waf": "Security" + "text": "Functions - Keep your functions warm", + "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", + "waf": "Cost" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "09945bda-4333-44f2-9911-634182ba5275", - "link": "https://learn.microsoft.com/azure/defender-for-cloud/concept-cloud-security-posture-management", - "service": "Defender", + "guid": "359c363e-7dd6-4162-9a36-4a907ebae38e", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "service": "Azure Functions", "services": [ - "Subscriptions", - "WAF", - "Defender" + "WAF" ], - "severity": "High", - "text": "Enable Defender Cloud Security Posture Management for all subscriptions.", - "training": "https://learn.microsoft.com/training/modules/microsoft-defender-cloud-security-posture/", - "waf": "Security" + "severity": "Medium", + "text": "When using autoscale with different functions, there might be one driving all the autoscale for all the resources - consider moving it to a separate consumption plan (and consider higher plan for CPU)", + "waf": "Cost" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "36a72a48-fffe-4c40-9747-0ab5064355ba", - "link": "https://learn.microsoft.com/azure/defender-for-cloud/plan-defender-for-servers-select-plan", - "service": "Defender", + "guid": "ad53cc7d-e2e8-4aaa-a357-1549ab9153d8", + "link": "https://learn.microsoft.com/azure/service-health/alerts-activity-log-service-notifications-portal", + "service": "Azure Functions", "services": [ - "Subscriptions", - "WAF", - "Defender" + "WAF" ], - "severity": "High", - "text": "Enable a Defender Cloud Workload Protection Plan for Servers on all subscriptions.", - "training": "https://learn.microsoft.com/training/modules/understand-azure-defender-cloud-workload-protection/", - "waf": "Security" + "severity": "Medium", + "text": "Function apps in a given plan are all scaled together, so any issues with scaling can affect all apps in the plan.", + "waf": "Cost" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "77425f48-ecba-43a0-aeac-a3ac733ccc6a", - "link": "https://learn.microsoft.com/azure/defender-for-cloud/connect-azure-subscription", - "service": "Defender", + "guid": "9f89dc7b-44be-43b1-a27f-8b9e91be1f38", + "link": "https://learn.microsoft.com/azure/azure-monitor/alerts/action-groups", + "service": "Azure Functions", "services": [ - "Subscriptions", - "WAF", - "Defender" + "WAF" ], - "severity": "High", - "text": "Enable Defender Cloud Workload Protection Plans for Azure Resources on all subscriptions.", - "training": "https://learn.microsoft.com/training/modules/understand-azure-defender-cloud-workload-protection/", - "waf": "Security" + "severity": "Medium", + "text": "Am I billed for 'await time'? This question is typically asked in the context of a C# function that does an async operation and waits for the result, e.g. await Task.Delay(1000) or await client.GetAsync('http://google.com'). The answer is yes - the GB second calculation is based on the start and end time of the function and the memory usage over that period. What actually happens over that time in terms of CPU activity is not factored into the calculation.One exception to this rule is if you are using durable functions. You are not billed for time spent at awaits in orchestrator functions.apply demand shaping techinques where possible (dev environments?) https://github.com/Azure-Samples/functions-csharp-premium-scaler", + "waf": "Cost" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "24d96b30-61ee-4436-a1cc-d6ef08bc574b", - "link": "https://learn.microsoft.com/mem/configmgr/protect/deploy-use/endpoint-protection", - "service": "VM", + "guid": "3da1dae2-cc88-4147-8607-c1cca0e61465", + "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", + "service": "Front Door", "services": [ + "EventHubs", + "FrontDoor", "WAF" ], - "severity": "High", - "text": "Enable Endpoint Protection on IaaS Servers.", - "training": "https://learn.microsoft.com/training/modules/design-solutions-securing-server-client-endpoints/", - "waf": "Security" + "severity": "Medium", + "text": "Frontdoor - Turn off the default homepageIn the application settings of your App, set AzureWebJobsDisableHomepage to true. This will return a 204 (No Content) to the PoP so only header data is returned.", + "waf": "Cost" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "15833ee7-ad6c-46d3-9331-65c7acbe44ab", - "link": "https://learn.microsoft.com/azure/security-center/", - "service": "VM", + "guid": "8dd458e9-2713-49b8-8110-2dbd6eaf11e6", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-setup-guide/monitoring-reporting?tabs=AzureMonitor", + "service": "Front Door", "services": [ - "Defender", - "WAF", - "Monitor" + "AppSvc", + "FrontDoor", + "WAF" ], "severity": "Medium", - "text": "Monitor base operating system patching drift via Azure Monitor Logs and Defender for Cloud.", - "training": "https://learn.microsoft.com/training/modules/create-log-analytics-workspace-microsoft-defender-cloud/", - "waf": "Security" + "text": "Frontdoor - Route to something that returns nothing. Either set up a Function, Function Proxy, or add a route in your WebApp that returns 200 (OK) and sends no or minimal content. The advantage of this is you will be able to log out when it is called.", + "waf": "Cost" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "e5f8d79f-2e87-4768-924c-516775c6ea95", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", - "service": "Monitor", + "guid": "7e31c67d-68cf-46a6-8a11-94956d697dc3", + "link": "https://learn.microsoft.com/azure/architecture/best-practices/monitoring", + "service": "Storage", "services": [ - "Entra", - "WAF", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Connect default resource configurations to a centralized Azure Monitor Log Analytics workspace.", - "training": "https://learn.microsoft.com/training/modules/analyze-infrastructure-with-azure-monitor-logs/", - "waf": "Security" + "text": "Consider archiving tiers for less used data", + "waf": "Cost" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "graph": "resources| where type == 'microsoft.operationalinsights/workspaces'| extend wsid = properties.customerId| project workspaceResourceId = tolower(id), name, wsid| join (resources| where type == 'microsoft.operationsmanagement/solutions'| where name has 'SecurityInsights'| extend workspaceResourceId = tostring(tolower(properties.workspaceResourceId))| project workspaceResourceId | summarize ResourceCount = count() by workspaceResourceId) on workspaceResourceId| extend RCount = iff(isnull(ResourceCount), 0, ResourceCount)| project-away ResourceCount| extend compliant = (RCount <> 0)", - "guid": "a56888b2-7e83-4404-bd31-b886528502d1", - "link": "https://learn.microsoft.com/en-us/azure/well-architected/security/monitor-threats#centralized-threat-detection-with-correlated-logs", - "service": "Entra", + "guid": "a2ed27b2-d186-4f1a-8252-bddde68a487c", + "link": "https://learn.microsoft.com/azure/automation/how-to/region-mappings", + "service": "VM", "services": [ - "WAF", - "ACR", - "Entra" + "WAF" ], - "severity": "High", - "text": "Centralized threat detection with correlated logs - consolidate security data in a central location where it can be correlated across various services via SIEM (security information and event management)", - "waf": "Security" + "severity": "Medium", + "text": "Check disk sizes where the size does not match the tier (i.e. A 513 GiB disk will pay a P30 (1TiB) and consider resizing", + "waf": "Cost" }, { + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "1761e147-f65e-4d09-bbc2-f464f23e2eba", - "link": "https://learn.microsoft.com/industry/sovereignty/transparency-logs", - "service": "Entra", + "guid": "dec4861b-c3bc-410a-b77e-26e4d5a3bec2", + "link": "https://learn.microsoft.com/azure/governance/policy/concepts/guest-configuration", + "service": "Storage", "services": [ - "WAF", - "Entra" + "WAF" ], "severity": "Medium", - "text": "For Sovereign Landing Zone, enable transparancy logs on the Entra ID tenant.", - "waf": "Security" + "text": "Consider using standard SSD rather than Premium or Ultra where possible", + "waf": "Cost" }, { + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "d21a922d-5ca7-427a-82a6-35f7b21f1bfc", - "link": "https://learn.microsoft.com/azure/security/fundamentals/customer-lockbox-overview", - "service": "Entra", + "guid": "c4e2436b-1336-4db5-9f17-960eee0bdf5c", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#monitoring-for-configuration-drift", + "service": "Storage", "services": [ - "WAF", - "Entra" + "Storage", + "WAF" ], "severity": "Medium", - "text": "For Sovereign Landing Zone, enable customer Lockbox on the Entra ID tenant.", - "waf": "Security" + "text": "For storage accounts, make sure that the chosen tier is not adding up transaction charges (it might be cheaper to move to the next tier)", + "waf": "Cost" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "b03ed428-4617-4067-a787-85468b9ccf3f", - "link": "https://learn.microsoft.com/azure/storage/common/storage-require-secure-transfer", - "service": "Storage", + "guid": "c2efc5d7-61d4-41d2-900b-b47a393a040f", + "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", + "service": "Site Recovery", "services": [ - "Storage", + "ASR", "WAF" ], - "severity": "High", - "text": "Enable secure transfer to storage accounts.", - "training": "https://learn.microsoft.com/training/modules/secure-azure-storage-account/", - "waf": "Security" + "severity": "Medium", + "text": "For ASR, consider using Standard SSD disks if the RPO/RTO and replication throughput allow it", + "waf": "Cost" }, { "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "159aac9f-863f-4f48-82cf-00c28fa97a0e", - "link": "https://learn.microsoft.com/azure/storage/blobs/data-protection-overview#recommendations-for-basic-data-protection", + "guid": "d3294798-b118-48b2-a5a4-6ceb544451e1", + "link": "https://learn.microsoft.com/azure/architecture/framework/resiliency/backup-and-recovery", "service": "Storage", "services": [ "Storage", "WAF" ], - "severity": "High", - "text": "Enable container soft delete for the storage account to recover a deleted container and its contents.", - "waf": "Security" + "severity": "Medium", + "text": "Storage accounts: check hot tier and/or GRS necessary", + "waf": "Cost" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "108d5099-a11d-4445-bd8b-e12a5e95412e", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/considerations/development-strategy-development-lifecycle#automated-builds", - "service": "Key Vault", + "guid": "92d34429-3c76-4286-97a5-51c5b04e4f18", + "link": "https://learn.microsoft.com/azure/backup/backup-center-overview", + "service": "VM", "services": [ - "AKV", - "VM", "WAF" ], - "severity": "High", - "text": "Use Key Vault secrets to avoid hard-coding sensitive information such as credentials (virtual machines user passwords), certificates or keys.", - "training": "https://learn.microsoft.com/en-us/training/modules/implement-azure-key-vault/", - "waf": "Operations" + "severity": "Medium", + "text": "Disks - validate use of Premium SSD disks everywhere: for example, non-prod could swap to Standard SSD or on-demand Premium SSD ", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "a85b86ad-884f-48e3-9273-4b875ba18f10", - "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/system-message#define-additional-safety-and-behavioral-guardrails", - "service": "Azure OpenAI", + "guid": "54387e5c-ed12-46cd-832a-f5b2fc6998a5", + "link": "https://learn.microsoft.com/azure/reliability/availability-zones-overview", + "service": "Synapse", "services": [ + "Cost", + "EventHubs", + "Monitor", "WAF" ], - "severity": "High", - "text": "Follow Metaprompting guardrails for resonsible AI", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Create budgets to manage costs and create alerts that automatically notify stakeholders of spending anomalies and overspending risks.", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "d4391898-cd28-48be-b6b1-7cb8245451e1", - "link": "https://github.com/Azure-Samples/AI-Gateway", - "service": "Azure OpenAI", + "guid": "35e33789-7e31-4c67-b68c-f6a62a119495", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "service": "Synapse", "services": [ - "Entra", - "WAF", - "APIM" + "Cost", + "Storage", + "WAF" ], - "severity": "High", - "text": "Consider Gateway patterns with APIM or solutions like AI central for better rate limiting, load balancing, authentication and logging", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Export cost data to a storage account for additional data analysis.", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "aed3453a-ec72-4392-97a1-52d6cc5e4029", - "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/azure-openai-insights-monitoring-ai-with-confidence/ba-p/4026850", - "service": "Azure OpenAI", - "services": [ - "WAF", - "Monitor" - ], - "severity": "High", - "text": "Enable monitoring for your AOAI instances", - "waf": "Operational Excellence" - }, - { - "arm-service": "Microsoft.CognitiveServices/accounts", - "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.insights/metricalerts' | extend compliant = (properties.targetResourceType =~ 'Microsoft.CognitiveServices/accounts') | project id, compliant", - "guid": "697cb391-ed16-4b2d-886f-0a0241addde6", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitoring#set-up-alerts", - "service": "Azure OpenAI", + "guid": "6d697dc3-a2ed-427b-8d18-6f1a1252bddd", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", + "service": "Synapse", "services": [ - "AKV", - "Subscriptions", - "WAF", - "Monitor" + "Cost", + "SQL", + "WAF" ], - "severity": "High", - "text": "Create alerts to notify teams of events such as an entry in the activity log created by an action performed on the resource, such as regenerating its subscription keys or a metric threshold such as the number of errors exceeding 10 in an hour", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Control costs for a dedicated SQL pool by pausing the resource when it is not in use.", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "8a477cde-b486-41bc-9bc1-0ae66e25d4d5", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitoring", - "service": "Azure OpenAI", + "guid": "e68a487c-dec4-4861-ac3b-c10ae77e26e4", + "link": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/overview", + "service": "Synapse", "services": [ - "WAF", - "Monitor" + "WAF" ], - "severity": "High", - "text": "Monitor token usage to prevent service disruptions due to capacity", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Enable the serverless Apache Spark automatic pause feature and set your timeout value accordingly.", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "a3aec2c4-e243-46b0-936c-b45e17960eee", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitoring", - "service": "Azure OpenAI", + "guid": "d5a3bec2-c4e2-4436-a133-6db55f17960e", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-latest-version-for-customer-managed-certificates", + "service": "Synapse", "services": [ - "WAF", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "observe metrics like processed inference tokens, generated completion tokens monitor for rate limit", - "waf": "Operational Excellence" + "text": "Create multiple Apache Spark pool definitions of various sizes.", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "fbdf4cc2-eec4-4d76-8c31-d25ffbb46a39", - "link": "https://techcommunity.microsoft.com/t5/apps-on-azure-blog/build-an-enterprise-ready-azure-openai-solution-with-azure-api/ba-p/3907562", - "service": "Azure OpenAI", + "guid": "ee0bdf5c-c2ef-4c5d-961d-41d2500bb47a", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups#management-groups-in-the-azure-landing-zone-accelerator", + "service": "Synapse", "services": [ - "WAF", - "APIM" + "Cost", + "WAF" ], - "severity": "Low", - "text": "Enable and configure Diagnostics for the Azure OpenAI Service. If not sufficient, consider using a gateway such as Azure API Managements in front of Azure OpenAI to log both incoming prompts and outgoing responses, where permitted", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Purchase Azure Synapse commit units (SCU) for one year with a pre-purchase plan to save on your Azure Synapse Analytics costs.", + "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "3af30ed3-2947-498b-8178-a2c5a46ceb54", - "link": "https://github.com/Azure-Samples/openai-enterprise-iac", - "service": "Azure OpenAI", + "guid": "393a040f-d329-4479-ab11-88b2c5a46ceb", + "link": "https://learn.microsoft.com/azure/application-gateway/overview-v2", + "service": "VM", "services": [ + "Cost", + "VM", "WAF" ], - "severity": "High", - "text": "Use Infrastructure as code to deploy the Azure OpenAI Service, model deployments, and all related resources", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Use Spot VMs for interruptible jobs: These are VMs that can be bid on and purchased at a discounted price, providing a cost-effective solution for non-critical workloads.", + "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "4350d092-d234-4292-a752-8537a551c5bf", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/managed-identity", - "service": "Azure OpenAI", + "guid": "544451e1-92d3-4442-a3c7-628637a551c5", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", + "service": "VM", "services": [ - "WAF", - "Entra" + "VM", + "WAF" ], - "severity": "High", - "text": "Use Microsoft Entra Authentication with Managed Identity instead of API Key", - "waf": "Security" + "severity": "Medium", + "text": "Right-sizing all VMs", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "4e4f1854-287d-45cd-a126-cc031af5b1fc", - "link": "https://learn.microsoft.com/azure/machine-learning/prompt-flow/how-to-bulk-test-evaluate-flow?view=azureml-api-2", - "service": "Azure OpenAI", + "guid": "b04e4f18-5438-47e5-aed1-26cd032af5b2", + "link": "https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet", + "service": "VM", "services": [ + "VM", "WAF" ], - "severity": "High", - "text": "Evaluate the performance/accuracy of the system with a known golden dataset which has the inputs and the correct answers. Leverage capabilities in PromptFlow for Evaluation.", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Swap VM sized with normalized and most recent sizes", + "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "68889535-e327-4897-b31b-67d67be5962a", - "link": "https://learn.microsoft.com/azure/architecture/ai-ml/architecture/baseline-openai-e2e-chat#azure-openai---performance-efficiency", - "service": "Azure OpenAI", + "guid": "fc6998a5-35e3-4378-a7e3-1c67d68cf6a6", + "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", + "service": "VM", "services": [ + "VM", + "Monitor", "WAF" ], - "severity": "High", - "text": "Evaluate usage of Provisioned throughput model ", - "waf": "Performance" + "severity": "Medium", + "text": "right-sizing VMs - start with monitoring usage below 5% and then work up to 40%", + "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "cd288bed-6b17-4cb8-8454-51e1aed3453a", - "link": "https://learn.microsoft.com/azure/ai-services/content-safety/overview", - "service": "Azure OpenAI", + "guid": "2a119495-6d69-47dc-9a2e-d27b2d186f1a", + "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", + "service": "VM", "services": [ + "VM", "WAF" ], - "severity": "High", - "text": "Review and implement Azure AI content safety", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Containerizing an application can improve VM density and save money on scaling it", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.cache/redis", "checklist": "WAF checklist", - "guid": "1193846d-697c-4b39-8ed1-6b2d186f0a02", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#system-level-throughput", - "service": "Azure OpenAI", + "guid": "65285269-440b-44be-9d3e-0844276d4bdc", + "link": "https://learn.microsoft.com/azure/azure-cache-for-redis/cache-how-to-zone-redundancy", + "service": "Redis", "services": [ + "ACR", "WAF" ], "severity": "High", - "text": "Define and evaluate the throughput of the system based on tokens & response per minute and align with requirements", - "waf": "Performance" + "text": "Enable zone redundancy for Azure Cache for Redis. Azure Cache for Redis supports zone redundant configurations in the Premium and Enterprise tiers. A zone redundant cache can place its nodes across different Azure Availability Zones in the same region. It eliminates data center or AZ outage as a single point of failure and increases the overall availability of your cache.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.cache/redis", "checklist": "WAF checklist", - "guid": "41addde6-8a47-47cd-bb48-61bc3bc10ae6", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#improve-performance", - "service": "Azure OpenAI", + "guid": "bc178bdc-5a06-4ca7-8443-51e19dd34429", + "link": "https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-high-availability#persistence", + "service": "Redis", "services": [ + "Storage", "WAF" ], "severity": "Medium", - "text": "Improve latency of the system by limiting token sizes, streaming options for applications like chatbots or conversational interfaces. Streaming can enhance the perceived performance of Azure OpenAI applications by delivering responses to users in an incremental manner", - "waf": "Performance" + "text": "Configure data persistence for an Azure Cache for Redis instance. Because your cache data is stored in memory, a rare and unplanned failure of multiple nodes can cause all the data to be dropped. To avoid losing data completely, Redis persistence allows you to take periodic snapshots of in-memory data, and store it to your storage account.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.cache/redis", "checklist": "WAF checklist", - "guid": "6e25d4d5-a3ae-4c2c-9e24-36b0336cb45e", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#batching", - "service": "Azure OpenAI", + "guid": "eb722823-7a15-41c5-ab4e-4f1814387e5c", + "link": "https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-high-availability#storage-account-for-persistence", + "service": "Redis", "services": [ - "ServiceBus", "Storage", "WAF" ], "severity": "Medium", - "text": "Estimate elasticity demands to determine synchronous and batch request segregation based on priority. For high priority, use synchronous approach and for low priority, asynchronous batch processing with queue is preferred", - "waf": "Performance" + "text": "Use Geo-redundant storage account to persist Azure Cache for Redis data, or zonally redundant where geo-redundancy is not available", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.cache/redis", "checklist": "WAF checklist", - "guid": "5bda4332-4f24-4811-9331-82ba51752694", - "link": "https://github.com/Azure/azure-openai-benchmark/", - "service": "Azure OpenAI", + "guid": "a8c26c9b-32ab-45bd-bc69-98a135e33789", + "link": "https://learn.microsoft.com/azure/azure-cache-for-redis/cache-how-to-geo-replication", + "service": "Redis", "services": [ + "ASR", "WAF" ], - "severity": "High", - "text": "Benchmark token consumption requirements based on estimated demands from consumers. Consider using the Azure OpenAI benchmarking tool to help you validate the throughput if you are using Provisioned Throughput Unit deployments", - "waf": "Performance" + "severity": "Medium", + "text": "Configure passive geo-replication for Premium Azure Cache for Redis instances. Geo-replication is a mechanism for linking two or more Azure Cache for Redis instances, typically spanning two Azure regions. Geo-replication is designed mainly for cross-region disaster recovery. Two Premium tier cache instances are connected through geo-replication in a way that provides reads and writes to your primary cache, and that data is replicated to the secondary cache.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "4008ae7d-7e47-4432-96d8-bdcf55bce619", - "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/optimizing-azure-openai-a-guide-to-limits-quotas-and-best/ba-p/4076268", - "service": "Azure OpenAI", + "graph": "cdnresources | where type =~ 'microsoft.Cdn/profiles/secrets' | extend frontDoorId = substring(id, 0, indexof(id, '/secrets')) | where properties.parameters.type =~ 'CustomerCertificate' | extend compliant = properties.parameters.useLatestVersion == true | project compliant, id=frontDoorId, certificateName = name | distinct id, certificateName, compliant", + "guid": "f00a69de-7076-4734-a734-6e4552cad9e1", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-latest-version-for-customer-managed-certificates", + "service": "Front Door", "services": [ + "AKV", + "FrontDoor", "WAF" ], "severity": "Medium", - "text": "If you are using Provisioned Throughput Units (PTUs), consider deploying a token-per-minute (TPM) deployment for overflow requests. Use a gateway to route requests to the TPM deployment when the PTU limits are reached.", - "waf": "Performance" + "text": "If you use customer-managed TLS certificates with Azure Front Door, use the 'Latest' certificate version. Reduce the risk of outages caused by manual certificate renewal.", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "e8a13f98-8794-424d-9267-86d60b96c97b", - "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/models", - "service": "Azure OpenAI", + "graph": "resources | where type =~ 'microsoft.cdn/profiles' and sku has 'AzureFrontDoor' | project name, cdnprofileid=tolower(id), tostring(tags), resourceGroup, subscriptionId,skuname=tostring(sku.name) | join kind= fullouter ( cdnresources | where type == 'microsoft.cdn/profiles/securitypolicies' | extend wafpolicyid=tostring(properties['parameters']['wafPolicy']['id']) | extend splitid=split(id, '/') | extend cdnprofileid=tolower(strcat_array(array_slice(splitid, 0, 8), '/')) | project secpolname=name, cdnprofileid, wafpolicyid ) on cdnprofileid | project name, cdnprofileid, secpolname, wafpolicyid,skuname | join kind = fullouter ( resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | extend managedrulesenabled=iff(tostring(properties.managedRules.managedRuleSets) != '[]', true, false), enabledState = tostring(properties.policySettings.enabledState) | project afdwafname=name, managedrulesenabled, wafpolicyid=id, enabledState, tostring(tags) ) on wafpolicyid | where name != '' | summarize associatedsecuritypolicies=countif(secpolname != ''), wafswithmanagedrules=countif(managedrulesenabled == 1) by name, id=cdnprofileid, tags,skuname | extend compliant = (associatedsecuritypolicies > 0 and wafswithmanagedrules > 0) | project id, compliant", + "guid": "e79d17b7-3b22-4a5a-97e7-a8ed4b30e38c", + "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", + "service": "Front Door", "services": [ + "FrontDoor", + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Choose the right model for the right task. Pick models with right tradeoff between speed, quality of response and output complexity", - "waf": "Performance" + "severity": "Medium", + "text": "Use Azure Front Door with WAF policies to deliver and help protect global HTTP/S apps that span multiple Azure regions.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "e9951904-8384-45c9-a6cb-2912156a1147", - "link": "https://github.com/Azure/azure-openai-benchmark/", - "service": "Azure OpenAI", + "guid": "3f29812b-2363-4cef-b179-b599de0d5973", + "link": "https://learn.microsoft.com/azure/frontdoor/origin-security?tabs=application-gateway&pivots=front-door-standard-premium#example-configuration", + "service": "Front Door", "services": [ + "AppGW", + "FrontDoor", + "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Have a baseline for performance without fine-tuning for knowing whether or not fine-tuning has improved model performance", - "waf": "Performance" + "text": "When using Front Door and Application Gateway to help protect HTTP/S apps, use WAF policies in Front Door. Lock down Application Gateway to receive traffic only from Front Door.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "5e39f541-accc-4d97-a376-bcdb3750ab2a", - "link": "https://learn.microsoft.com/azure/architecture/ai-ml/architecture/baseline-openai-e2e-chat#azure-openai---reliability", - "service": "Azure OpenAI", + "graph": "resources | where type == 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=='Enabled') and (mode=='Prevention')), enabledState, mode", + "guid": "ae248989-b306-4591-9186-de482e3f0f0e", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings", + "service": "Front Door", "services": [ - "WAF", - "ACR" + "FrontDoor", + "AzurePolicy", + "WAF" ], - "severity": "Low", - "text": "Deploy multiple OAI instances across regions", - "waf": "Reliability" + "severity": "High", + "text": "Deploy your WAF policy for Front Door in 'Prevention' mode' so that Web Application Firewall takes appropriate action to allow or deny traffic.", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "b039da6d-55d7-4c89-8adb-107d5325af62", - "link": "https://learn.microsoft.com/azure/architecture/ai-ml/architecture/baseline-openai-e2e-chat#azure-openai---reliability", - "service": "Azure OpenAI", + "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/origins' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups')) | extend compliant = properties['hostName'] !endswith '.trafficmanager.net' | project compliant, id=frontDoorId", + "guid": "062d5839-4d36-402f-bfa4-02811eb936e9", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#avoid-combining-traffic-manager-and-front-door", + "service": "Front Door", "services": [ - "Entra", - "WAF", - "APIM" + "EventHubs", + "FrontDoor", + "TrafficManager", + "WAF" ], "severity": "High", - "text": "Implement retry & healthchecks with Gateway pattern like APIM", - "waf": "Reliability" + "text": "Avoid placing Traffic Manager behind Front Door.", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "5ca44e46-85e2-4223-ace8-bb12308ca5f1", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/quota?tabs=rest#introduction-to-quota", - "service": "Azure OpenAI", + "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/origins' | extend frontDoorId = substring(id, 0, indexof(id, '/origins')) | extend compliant = isempty(properties.originHostHeader) or (tostring(properties.hostName) =~ tostring(properties.originHostHeader)) | project id=frontDoorId, originName = name, compliant", + "guid": "5efeb96a-003f-4b18-8fcd-b4d84459c2b2", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-the-same-domain-name-on-front-door-and-your-origin", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], - "severity": "Medium", - "text": "Ensure having adequate quotas of TPM & RPM for the workload", - "waf": "Reliability" + "severity": "High", + "text": "Use the same domain name on Azure Front Door and your origin. Mismatched host names can cause subtle bugs.", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "ec723923-7a15-42d6-ac5e-402925387e5c", - "link": "https://www.microsoft.com/research/project/guidelines-for-human-ai-interaction/", - "service": "Azure OpenAI", + "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/origins' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups')) | extend originGroupId = substring(id, 0, indexof(id, '/origins')) | join kind=inner (cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups' | extend originGroupName = name | extend hasHealthProbe = isnotnull(properties.healthProbeSettings)) on $left.originGroupId == $right.id | summarize numberOrigins = count() by originGroupId, subscriptionId, frontDoorId, hasHealthProbe, originGroupName | extend compliant = not(numberOrigins == 1 and hasHealthProbe) | project id = frontDoorId, compliant", + "guid": "0b5a380c-4bfb-47bc-b1d7-dcfef363a61b", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], - "severity": "Medium", - "text": "Review the considerations in HAI toolkit guidance and apply those interaction practices for the slution", - "waf": "Operational Excellence" + "severity": "Low", + "text": "Disable health probes when there is only one origin in an Azure Front Door origin group.", + "waf": "Performance" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "7f154e3a-a369-4282-ae7e-316183687a04", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/business-continuity-disaster-recovery", - "service": "Azure OpenAI", + "guid": "5567048e-e5d7-4206-9c55-b5ed45d2cc0c", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#select-good-health-probe-endpoints", + "service": "Front Door", "services": [ - "WAF", - "ACR" + "FrontDoor", + "WAF" ], "severity": "Medium", - "text": "Deploy separate fine tuned models across regions if finetuning is employed", + "text": "Select good health probe endpoints for Azure Front Door. Consider building health endpoints that check all of your application's dependencies.", "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "77a1f893-5bda-4433-84f2-4811633182ba", - "link": "https://learn.microsoft.com/azure/backup/backup-overview", - "service": "Azure OpenAI", + "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups/')) | extend compliant = (isnull(properties['healthProbeSettings']['probeRequestType']) or toupper(properties['healthProbeSettings']['probeRequestType']) == 'HEAD') | project compliant, id=frontDoorId", + "guid": "a13f72f3-8f5c-4864-95e5-75bf37fbbeb1", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes", + "service": "Front Door", "services": [ - "ASR", - "WAF", - "Backup" + "FrontDoor", + "WAF" ], - "severity": "Medium", - "text": "Regularly backup and replicate critical data to ensure data availability and recoverability in case of data loss or system failures. Leverage Azure's backup and disaster recovery services to protect your data.", - "waf": "Reliability" + "severity": "Low", + "text": "Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application.", + "waf": "Performance" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.search/searchservices' | extend compliant = (sku.name != 'free' and properties.replicaCount >= 3) | project id, compliant", - "guid": "95b96ad8-844c-4e3b-8b38-b876ba2cf204", - "link": "https://learn.microsoft.com/azure/search/search-reliability", - "service": "Azure OpenAI", + "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/customdomains' | extend frontDoorId = substring(id, 0, indexof(id, '/customdomains')) | extend compliant = (isnull(properties['tlsSettings']['certificateType']) or tolower(properties['tlsSettings']['certificateType']) =~ 'customercertificate') | project compliant, id = frontDoorId", + "guid": "af95c92d-d723-4f4a-98d7-8722324efd4d", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates", + "service": "Front Door", "services": [ + "Cost", + "AKV", + "FrontDoor", "WAF" ], "severity": "High", - "text": "Azure AI search service tiers should be choosen to have a SLA ", - "waf": "Reliability" + "text": "Use managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals.", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "99013a5d-3ce4-474d-acbd-8682a6abca2a", - "link": "https://learn.microsoft.com/purview/purview", - "service": "Azure OpenAI", + "guid": "189ea962-3969-4863-8f5a-5ad808c2cf4b", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#define-your-waf-configuration-as-code", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], - "severity": "Low", - "text": "Classify data and sensitivity, labeling with Microsoft Purview before generating the embeddings and make sure to treat the embeddings generated with same sensitivity and classification", - "waf": "Security" + "severity": "Medium", + "text": "Define your Azure Front Door WAF configuration as code. By using code, you can more easily adopt new rule set version and gain additional protection.", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "4fda1dbf-3dd9-45d4-ac7c-891dca1f6d56", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/use-your-data-securely", - "service": "Azure OpenAI", + "graph": "cdnresources | where type == 'microsoft.cdn/profiles/afdendpoints/routes' | extend frontDoorId = substring(id, 0, indexof(id, '/afdendpoints')) | extend forwardingProtocol=tostring(properties.forwardingProtocol),supportedProtocols=properties.supportedProtocols,httpsRedirect=properties.httpsRedirect | extend compliant = forwardingProtocol =~ 'httpsonly' and (supportedProtocols has 'https' or httpsRedirect =~ 'enabled') | project id = frontDoorId, compliant", + "guid": "2e30abab-5478-417c-81bf-bf1ad4ed1ed4", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-end-to-end-tls", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], "severity": "High", - "text": "Encrypt data used for RAG with SSE/Disk encryption with optional BYOK", + "text": "Use end-to-end TLS with Azure Front Door. Use TLS for connections from your clients to Front Door, and from Front Door to your origin.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "59ae558b-937d-4498-9e11-12dbd7ba012f", - "link": "https://learn.microsoft.com/azure/search/search-security-overview", - "service": "Azure OpenAI", + "graph": "cdnresources | where type == 'microsoft.cdn/profiles/afdendpoints/routes' | extend frontDoorId = substring(id, 0, indexof(id, '/afdendpoints')) | extend forwardingProtocol=tostring(properties.forwardingProtocol),supportedProtocols=properties.supportedProtocols,httpsRedirect=properties.httpsRedirect | extend compliant = httpsRedirect =~ 'enabled' | project id = frontDoorId, compliant", + "guid": "10aa45af-166f-44c4-9f36-b6d592dac2ca", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-http-to-https-redirection", + "service": "Front Door", "services": [ - "WAF", - "ACR" + "FrontDoor", + "WAF" ], - "severity": "High", - "text": "Ensure TLS is enforced for data in transit across data sources, AI search used for Retrieval-Augmented Generation (RAG) and LLM communication", + "severity": "Medium", + "text": "Use HTTP to HTTPS redirection with Azure Front Door. Support older clients by redirecting them to an HTTPS request automatically.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "7b94ef6e-047d-42ea-8992-b1cd6e2054b2", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/role-based-access-control", - "service": "Azure OpenAI", + "graph": "resources | where type =~ 'microsoft.network/frontdoorwebapplicationfirewallpolicies' | project policyName=name, policyId=id,policySku=sku.name, links=properties.securityPolicyLinks, enabledState=properties.policySettings.enabledState, mode=properties.policySettings.mode | mvexpand links | extend securityPolicy=links.id | extend securityPolicyParts=split(securityPolicy, '/') | extend profileId=strcat_array(array_slice(securityPolicyParts, 0, -3), '/') | project id=profileId, compliant=((enabledState=~'Enabled') and (mode=~'Prevention')), enabledState, mode", + "guid": "28b9ee82-b2c7-45aa-bc98-6de6f59a095d", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#enable-the-waf", + "service": "Front Door", "services": [ - "RBAC", + "FrontDoor", "WAF" ], "severity": "High", - "text": "Use RBAC to manage access to Azure OpenAI services. Assign appropriate permissions to users and restrict access based on their roles and responsibilities", + "text": "Enable the Azure Front Door WAF. Protect your application from a range of attacks.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "9769e4a6-91e8-4838-ac93-6667e13c0056", - "link": "https://learn.microsoft.com/azure/security/fundamentals/data-encryption-best-practices", - "service": "Azure OpenAI", + "guid": "2902d8cc-1b0c-4495-afad-624ab70f7bd6", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#tune-your-waf", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], - "severity": "Medium", - "text": "Implement data encryption, masking or redaction techniques to hide sensitive data or replace it with obfuscated values in non-production environments or when sharing data for testing or troubleshooting purposes", + "severity": "High", + "text": "Tune the Azure Front Door WAF for your workload by configuring the WAF in Detection mode to reduce and fix false positive detections.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "74b1e945-b459-4837-be7a-d6c6d3b375a5", - "link": "https://learn.microsoft.com/azure/defender-for-cloud/ai-onboarding", - "service": "Azure OpenAI", + "guid": "17ba124b-127d-42b6-9322-388d5b2bbcfc", + "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection", + "service": "Front Door", "services": [ - "Sentinel", - "Defender", - "WAF", - "Monitor" + "FrontDoor", + "AzurePolicy", + "WAF" ], "severity": "High", - "text": "Utilize Azure Defender to detect and respond to security threats and set up monitoring and alerting mechanisms to identify suspicious activities or breaches. Leverage Azure Sentinel for advanced threat detection and response", + "text": "Enable request body inspection feature enabled in Azure Front Door WAF policy.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "c7acbe48-abe5-44cd-99f2-e87768468c55", - "link": "https://techcommunity.microsoft.com/t5/azure-storage-blog/managing-long-term-log-retention-or-any-business-data/ba-p/2494791", - "service": "Azure OpenAI", + "guid": "49a98f2b-ec22-4a87-9415-6a10b00d6555", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#enable-default-rule-sets", + "service": "Front Door", "services": [ - "AzurePolicy", + "FrontDoor", "WAF" ], - "severity": "Medium", - "text": "Establish data retention and disposal policies to adhere to compliance regulations. Implement secure deletion methods for data that is no longer required and maintain an audit trail of data retention and disposal activities", + "severity": "High", + "text": "Enable the Azure Front Door WAF default rule sets. The default rule sets detect and block common attacks.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "a9c27d9c-42bb-46bd-8c69-99a246f3389a", - "link": "https://learn.microsoft.com/azure/ai-services/content-safety/concepts/jailbreak-detection", - "service": "Azure OpenAI", + "guid": "147a13d4-2a2f-4824-a524-f5855b52b946", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#enable-bot-management-rules", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], "severity": "High", - "text": "Implement Prompt shields and groundedness detection using Content Safety ", - "waf": "Operational Excellence" + "text": "Enable the Azure Front Door WAF bot protection rule set. The bot rules detect good and bad bots.", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "a775c6ee-95b9-46ad-a844-ce3b2b38b876", - "link": "https://learn.microsoft.com/azure/compliance/", - "service": "Azure OpenAI", + "guid": "d7dcdcb9-0d99-44b9-baab-ac7570ede79a", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#use-the-latest-ruleset-versions", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], - "severity": "High", - "text": "Ensure compliance with relevant data protection regulations, such as GDPR or HIPAA, by implementing privacy controls and obtaining necessary consents or permissions for data processing activities.", + "severity": "Medium", + "text": "Use the latest Azure Front Door WAF rule set version. Rule set updates are regularly updated to take account of the current threat landscape.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "ba2cf204-9901-43a5-b3ce-474dccbd8682", - "service": "Azure OpenAI", + "guid": "b9620385-1cde-418f-914b-a84a06982ffc", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-rate-limiting", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], "severity": "Medium", - "text": "Educate your employees about data security best practices, the importance of handling data securely, and potential risks associated with data breaches. Encourage them to follow data security protocols diligently.", + "text": "Add rate limiting to the Azure Front Door WAF. Rate limiting blocks clients accidentally or intentionally sending large amounts of traffic in a short period of time.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "eae01e6e-842e-452f-9721-d928c1b1cd52", - "service": "Azure OpenAI", + "guid": "6dc36c52-0124-4ffe-9eaf-23ec1282dedb", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#use-a-high-threshold-for-rate-limits", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], - "severity": "High", - "text": "Keep production data separate from development and testing data. Only use real sensitive data in production and utilize anonymized or synthetic data in development and test environments.", + "severity": "Medium", + "text": "Use a high threshold for Azure Front Door WAF rate limits. High rate limit thresholds avoid blocking legitimate traffic, while still providing protection against extremely high numbers of requests that might overwhelm your infrastructure.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "1e54a29a-9de3-499c-bd7b-28dc93555620", - "service": "Azure OpenAI", + "guid": "388a3d0e-0a43-4367-90b2-3dd2aeece5ee", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#geo-filter-traffic", + "service": "Front Door", "services": [ "WAF" ], - "severity": "Medium", - "text": "If you have varying levels of data sensitivity, consider creating separate indexes for each level. For instance, you could have one index for general data and another for sensitive data, each governed by different access protocols", + "severity": "Low", + "text": "If you are not expecting traffic from all geographical regions, use geo-filters to block traffic from non-expected countries.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "2bfe4564-b0d8-434a-948b-263e6dd60512", - "service": "Azure OpenAI", + "guid": "00acd8a9-6975-414f-8491-2be6309893b8", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#specify-the-unknown-zz-location", + "service": "Front Door", "services": [ - "AzurePolicy", - "RBAC", + "FrontDoor", "WAF" ], "severity": "Medium", - "text": "Take segregation a step further by placing sensitive datasets in different instances of the service. Each instance can be controlled with its own specific set of RBAC policies", + "text": "Specify the unknown (ZZ) location when geo-filtering traffic with the Azure Front Door WAF. Avoid accidentally blocking legitimate requests when IP addresses can't be geo-matched.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "a36498f6-dbad-438e-ad53-cc7ce1d7aaab", - "service": "Azure OpenAI", + "guid": "4cea4050-7946-4a7c-89e6-b021b73c352d", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-diagnostic-settings-to-save-your-wafs-logs", + "service": "Front Door", "services": [ + "Monitor", "WAF" ], - "severity": "High", - "text": "Recognize that embeddings and vectors generated from sensitive information are themselves sensitive. This data should be afforded the same protective measures as the source material", - "waf": "Security" + "severity": "Medium", + "text": "Capture logs and metrics by turning on Diagnostic Settings. Include resource activity logs, access logs, health probe logs, and WAF logs. Set up alerts.", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "3571449a-b805-43d8-af89-dc7b33be2a1a", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/role-based-access-control", - "service": "Azure OpenAI", + "guid": "845f5f91-9c21-4674-a725-5ce890850e20", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", + "service": "Front Door", "services": [ - "RBAC", + "Sentinel", + "FrontDoor", "WAF" ], - "severity": "High", - "text": "Apply RBAC to th data stores having embeddings and vectors and scope access based on role's access requirements", - "waf": "Security" + "severity": "Medium", + "text": "Send Azure Front Door WAF logs to Microsoft Sentinel.", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.CognitiveServices/accounts' or type == 'microsoft.search/searchservices' | project id, compliant = (properties.privateEndpointConnections != '[]' and properties.publicNetworkAccess !~ 'enabled')", - "guid": "27f7b9e9-1be1-4f38-aef3-9812bd463cbb", - "link": "https://techcommunity.microsoft.com/t5/azure-architecture-blog/azure-openai-private-endpoints-connecting-across-vnet-s/ba-p/3913325", - "service": "Azure OpenAI", + "guid": "3bb0a854-ea3d-4212-bd8e-3f0cb7792b02", + "link": "https://learn.microsoft.com/azure/frontdoor/routing-methods", + "service": "Front Door", "services": [ - "PrivateLink", + "Backup", "WAF" ], - "severity": "High", - "text": "Configure private endpoint for AI services to restrict service access within your network", - "waf": "Security" + "severity": "Medium", + "text": "Choose a routing method that supports your deployment strategy. The weighted method, which distributes traffic based on the configured weight coefficient, supports active-active models. A priority-based value that configures the primary region to receive all traffic and send traffic to the secondary region as a backup supports active-passive models. Combine the preceding methods with latency so that the origin with the lowest latency receives traffic.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "ac8ac199-ebb9-41a3-9d90-cae2cc881370", - "service": "Azure OpenAI", + "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups')) | extend healthprobe=tostring(properties.healthProbeSettings) | project origingroupname=name, id, tags, resourceGroup, subscriptionId, healthprobe, frontDoorId | join ( cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/Origins' | extend origingroupname = tostring(properties.originGroupName) ) on origingroupname | summarize origincount=count(), enabledhealthprobecount=countif(healthprobe != '') by origingroupname, id, tostring(tags), resourceGroup, subscriptionId, frontDoorId | extend compliant = origincount > 1 | project id = frontDoorId, compliant", + "guid": "c3a769e4-cc78-40a9-b36a-f9bcab19ec2d", + "link": "https://learn.microsoft.com/azure/frontdoor/quickstart-create-front-door", + "service": "Front Door", "services": [ - "Firewall", - "VNet", "WAF" ], "severity": "High", - "text": "Enforce strict inbound and outbound traffic control with Azure Firewall and UDRs and limit the external integration points", - "waf": "Security" + "text": "Support redundancy by having multiple origins in one or more back-end pools. Always have redundant instances of your application and make sure each instance exposes an endpoint or origin. You can place those origins in one or more back-end pools.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "6f7c0cba-fe51-4464-add4-57e927138b82", - "service": "Azure OpenAI", + "guid": "999852be-2137-4179-8fc3-30d1df6fed1d", + "link": "https://learn.microsoft.com/azure/frontdoor/troubleshoot-issues#troubleshooting-steps", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], - "severity": "High", - "text": "Implement network segmentation and access controls to restrict access to the LLM application only to authorized users and systems and prevent lateral movement", - "waf": "Security" + "severity": "Medium", + "text": "Set a timeout on forwarding requests to the back end. Adjust the timeout setting according to your endpoints' needs. If you don't, Azure Front Door might close the connection before the origin sends the response. You can also lower the default timeout for Azure Front Door if all of your origins have a shorter timeout.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "7f42c78e-78cb-46a2-8ad1-90916e6a8d8f", - "link": "https://www.microsoft.com/research/blog/llmlingua-innovating-llm-efficiency-with-prompt-compression/", - "service": "Azure OpenAI", + "guid": "17bf6351-3e5e-41f1-87bb-d5ad0b4e3de6", + "link": "https://learn.microsoft.com/azure/frontdoor/routing-methods#23session-affinity", + "service": "Front Door", "services": [ "WAF" ], "severity": "Medium", - "text": "Use prompt compression tools like LLMLingua or gprtrim", - "waf": "Cost Optimization" + "text": "Decide if your application requires session affinity. If you have high reliability requirements, we recommend that you disable session affinity.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.CognitiveServices/accounts' or type == 'microsoft.search/searchservices' | project id, compliant = (isnotnull(identity))", - "guid": "1102cac6-eae0-41e6-b842-e52f4721d928", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/managed-identity", - "service": "Azure OpenAI", + "guid": "425bfb31-94c4-4007-b9ae-46da9fe57cc7", + "link": "https://learn.microsoft.com/azure/frontdoor/origin?pivots=front-door-standard-premium#origin-host-header", + "service": "Front Door", "services": [ - "AKV", - "WAF", - "Entra" + "WAF" ], - "severity": "High", - "text": "Ensure that APIs and endpoints used by the LLM application are properly secured with authentication and authorization mechanisms, such as Managed identities, API keys or OAuth, to prevent unauthorized access.", + "severity": "Medium", + "text": "Send the host header to the back end. The back-end services should be aware of the host name so that they can create rules to accept traffic only from that host.", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "c1b1cd52-1e54-4a29-a9de-399cfd7b28dc", - "link": "https://techcommunity.microsoft.com/t5/azure-architecture-blog/security-best-practices-for-genai-applications-openai-in-azure/ba-p/4027885", - "service": "Azure OpenAI", + "guid": "81a5398a-2414-450f-9fc3-e048bc65784c", + "link": "https://learn.microsoft.com/azure/frontdoor/front-door-caching", + "service": "Front Door", "services": [ "WAF" ], "severity": "Medium", - "text": "Enforce strong end user authentication mechanisms, such as multi-factor authentication, to prevent unauthorized access to the LLM application and associated network resources", - "waf": "Security" + "text": "Use caching for endpoints that support it.", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "93555620-2bfe-4456-9b0d-834a348b263e", - "service": "Azure OpenAI", + "graph": "cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups' | extend frontDoorId = substring(id, 0, indexof(id, '/origingroups')) | extend healthprobe=tostring(properties.healthProbeSettings) | project origingroupname=name, id, tags, resourceGroup, subscriptionId, healthprobe, frontDoorId | join ( cdnresources | where type =~ 'microsoft.cdn/profiles/origingroups/Origins' | extend origingroupname = tostring(properties.originGroupName) ) on origingroupname | summarize origincount=count(), enabledhealthprobecount=countif(healthprobe != '') by origingroupname, id, tostring(tags), resourceGroup, subscriptionId, frontDoorId | extend compliant = origincount > 1 or (origincount == 1 and enabledhealthprobecount == 0) | project id = frontDoorId, compliant", + "guid": "34069d73-e4de-46c5-a36f-625f87575a56", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group", + "service": "Front Door", "services": [ - "WAF", - "Monitor" + "FrontDoor", + "WAF" ], - "severity": "Medium", - "text": "Implement network monitoring tools to detect and analyze network traffic for any suspicious or malicious activities. Enable logging to capture network events and facilitate forensic analysis in case of security incidents", - "waf": "Security" + "severity": "Low", + "text": "Disable health checks in single back-end pools. If you have only one origin configured in your Azure Front Door origin group, these calls are unnecessary. This is only recommended if you can't have multiple origins in your endpoint.", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "6dd60512-a364-498f-9dba-d38ead53cc7c", - "service": "Azure OpenAI", + "guid": "c92d6786-cdd1-444d-9cad-934a192a276a", + "link": "https://learn.microsoft.com/azure/frontdoor/standard-premium/how-to-reports", + "service": "Front Door", "services": [ + "Storage", + "FrontDoor", "WAF" ], "severity": "Medium", - "text": "Conduct security audits and penetration testing to identify and address any network security weaknesses or vulnerabilities in the LLM application's network infrastructure", - "waf": "Security" + "text": "We recommend using the Premium Tier for leveraging the Security reports while the Standard Azure Front Door Profile provides only traffic reports under built-in analytics/reports.", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.cognitiveservices/accounts' or type == 'microsoft.search/searchservices' | project id, compliant = (tags != '{}')", - "guid": "e1d7aaab-3571-4449-ab80-53d89f89dc7b", - "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/tag-resources?tabs=json", - "service": "Azure OpenAI", + "guid": "440cf7de-30a1-4550-ab50-c9f6eac140cd", + "link": "https://learn.microsoft.com/azure/frontdoor/front-door-wildcard-domain", + "service": "Front Door", "services": [ + "AKV", "WAF" ], - "severity": "Low", - "text": "Azure AI Services are properly tagged for better management", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Use wildcard TLS certificates when possible.", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "77036e5e-6b4b-4ed3-b503-547c1347dc56", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations", - "service": "Azure OpenAI", + "guid": "556e2733-6ca9-4edd-9cc7-26de66d46c2e", + "link": "https://learn.microsoft.com/azure/frontdoor/front-door-caching", + "service": "Front Door", "services": [ + "FrontDoor", "WAF" ], - "severity": "Low", - "text": "Azure AI Service accounts follows organizational naming conventions", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Optimize your application query string for caching. For purely static content, ignore query strings to maximize your use of the cache. If your application uses query strings, consider including them in the cache key. Including the query strings in the cache key allows Azure Front Door to serve cached responses or other responses, based on your configuration.", + "waf": "Performance" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "028a71ff-e1ce-415d-b3f0-d5e772d41e36", - "link": "https://learn.microsoft.com/azure/ai-services/diagnostic-logging", - "service": "Azure OpenAI", + "guid": "c0b7e55e-fcab-4e66-bdae-bd0290f6aece", + "link": "https://learn.microsoft.com/azure/frontdoor/standard-premium/how-to-compression", + "service": "Front Door", "services": [ + "Storage", "WAF" ], - "severity": "High", - "text": "Diagnostic logs in Azure AI services resources should be enabled", - "waf": "Operational Excellence" + "severity": "Medium", + "text": "Use file compression when you're accessing downloadable content.", + "waf": "Performance" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.CognitiveServices/accounts' or type == 'microsoft.search/searchservices' | project id, compliant = (properties.disableLocalAuth == true)", - "guid": "11cc57b4-a4b1-4410-b439-58a8c2289b3d", - "link": "https://learn.microsoft.com/azure/ai-services/authentication", - "service": "Azure OpenAI", + "graph": "resources | where type =~ 'microsoft.network/frontdoors' and properties['resourceState'] !~ 'migrated' | extend compliant = false | project id, compliant", + "guid": "cb8eb8c0-aa73-4a26-a495-6eba8dc4a243", + "link": "https://learn.microsoft.com/azure/cdn/tier-migration", + "service": "Front Door", "services": [ - "WAF", - "Entra" + "FrontDoor", + "WAF" ], "severity": "High", - "text": "Key access (local authentication) is recommended to be disabled for security. After disabling key based access, Microsoft Entra ID becomes the only access method, which allows maintaining minimum privilege principle and granular control. ", - "waf": "Security" + "text": "Consider migrating to Standard or Premium SKU if you are using Classic Azure Front Door currently as Classic Azure Front Door will be deprecated by March 2027.", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "6b57cfc6-5546-41e1-a3e3-453a3c863964", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Azure OpenAI", + "guid": "67c33697-15b1-4752-aeee-0b9b588defc4", + "link": "https://learn.microsoft.com/azure/architecture/guide/networking/global-web-applications/mission-critical-content-delivery", + "service": "Front Door", "services": [ - "AKV", - "WAF", - "Entra" + "Storage", + "FrontDoor", + "TrafficManager", + "WAF" ], - "severity": "High", - "text": "Store and manage keys securely using Azure Key Vault. Avoid hard-coding or embedding sensitive keys within your LLM application's code and retrieve them securely from Azure Key Vault using managed identities", - "waf": "Security" + "severity": "Medium", + "text": "Consider using Traffic Manager load balancing Azure Front Door and a third party CDN provider CDN profile for mission critical high availability scenario. ", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.network/frontdoors", "checklist": "WAF checklist", - "guid": "8b652d6c-15f5-4129-9539-8e6ded227dd1", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Azure OpenAI", + "guid": "972cd4cd-25b0-4b70-96e9-eab4bfd32907", + "link": "https://learn.microsoft.com/azure/app-service/app-service-ip-restrictions?tabs=azurecli#restrict-access-to-a-specific-azure-front-door-instance", + "service": "Front Door", "services": [ - "AKV", + "AppSvc", + "FrontDoor", "WAF" ], "severity": "High", - "text": "Regularly rotate and expire keys stored in Azure Key Vault to minimize the risk of unauthorized access.", + "text": "When using Front Door with origin as App services, consider locking down the traffic to app services only through Azure Front Door using access restrictions. ", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "adfe27be-e297-401a-a352-baaab79b088d", - "link": "https://github.com/openai/tiktoken", - "service": "Azure OpenAI", + "guid": "ab5351f6-383a-45ed-9c5e-b143b16db40a", + "link": "https://learn.microsoft.com/azure/aks/use-windows-hpc", + "service": "AKS", "services": [ + "AKS", "WAF" ], - "severity": "High", - "text": "Use tiktoken to understand token sizes for token optimizations in conversational mode", - "waf": "Cost Optimization" + "severity": "Low", + "text": "If required for AKS Windows workloads HostProcess containers can be used", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "42b06c21-d799-49a6-96f4-389a7f42c78e", - "link": "https://learn.microsoft.com/azure/security/develop/secure-dev-overview", - "service": "Azure OpenAI", + "guid": "a280dcf5-90ce-465d-b8e1-3f9ccbd46926", + "link": "https://learn.microsoft.com/azure/azure-functions/functions-kubernetes-keda", + "service": "AKS", "services": [ "WAF" ], - "severity": "High", - "text": "Follow secure coding practices to prevent common vulnerabilities such as injection attacks, cross-site scripting (XSS), or security misconfigurations", - "waf": "Security" + "severity": "Low", + "text": "Use KEDA if running event-driven workloads", + "waf": "Performance" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "78c06a73-a22a-4495-9e6a-8dc4a20e27c3", - "link": "https://learn.microsoft.com/azure/devops/repos/security/github-advanced-security-dependency-scanning?view=azure-devops", - "service": "Azure OpenAI", + "guid": "26886d20-b66c-457b-a591-19bf8e8f5c58", + "link": "https://dapr.io/", + "service": "AKS", "services": [ "WAF" ], - "severity": "High", - "text": "Setup a process to regularly update and patch the LLM libraries and other system components", - "waf": "Security" + "severity": "Low", + "text": "Use Dapr to ease microservice development", + "waf": "Operations" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "e29711b1-352b-4eee-879b-588defc4972c", - "link": "https://learn.microsoft.com/legal/cognitive-services/openai/code-of-conduct", - "service": "Azure OpenAI", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (sku.tier=='Paid') | distinct id,compliant", + "guid": "71d41e36-10cc-457b-9a4b-1410d4395898", + "link": "https://learn.microsoft.com/azure/aks/uptime-sla", + "service": "AKS", "services": [ - "AzurePolicy", + "AKS", "WAF" ], "severity": "High", - "text": "Adhere to Azure OpenAI or other LLMs terms of use, policies and guidance and allowed use cases", - "waf": "Operational Excellence" + "text": "Use the SLA-backed AKS offering", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "d3cd21bf-7703-46e5-b6b4-bed3d503547c", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs#base-series-and-codex-series-fine-tuned-models", - "service": "Azure OpenAI", + "guid": "c1288b3c-6a57-4cfc-9444-51e1a3d3453a", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-scheduler", + "service": "AKS", "services": [ - "WAF", - "Cost" + "Cost", + "WAF" ], - "severity": "Medium", - "text": "Understand difference in cost of base models and fine tuned models and token step sizes", - "waf": "Cost Optimization" + "severity": "Low", + "text": "Use Disruption Budgets in your pod and deployment definitions", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "1347dc56-028a-471f-be1c-e15dd3f0d5e7", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#batching", - "service": "Azure OpenAI", + "guid": "3c763963-7a55-42d5-a15e-401955387e5c", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-geo-replication", + "service": "ACR", "services": [ - "WAF", - "Cost" + "ACR", + "WAF" ], "severity": "High", - "text": "Batch requests, where possible, to minimize the per-call overhead which can reduce overall costs. Ensure you optimize batch size", - "waf": "Cost Optimization" + "text": "If using a private registry, configure region replication to store images in multiple regions", + "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "72d41e36-11cc-457b-9a4b-1410d43958a8", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", - "service": "Azure OpenAI", + "guid": "f82cb8eb-8c0a-4a63-a25a-4956eaa8dc4a", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/aks/eslz-cost-governance-with-kubecost", + "service": "AKS", "services": [ - "WAF", "Cost", - "Monitor" + "WAF" ], - "severity": "Medium", - "text": "Set up a cost tracking system that monitors model usage and use that information to help inform model choices and prompt sizes", - "waf": "Cost Optimization" + "severity": "Low", + "text": "Use an external application such as kubecost to allocate costs to different users", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "166cd072-af9b-4141-a898-a535e737897e", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/quota?tabs=rest#understanding-rate-limits", - "service": "Azure OpenAI", + "guid": "4d3dfbab-9924-4831-a68d-fdf0d72f462c", + "link": "https://learn.microsoft.com/azure/aks/scale-down-mode", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Set a maximum limit on the number of tokens per model response (max_tokens and the number of completions to generate). Optimize the size to ensure it is large enough for a valid response", - "waf": "Cost Optimization" + "severity": "Low", + "text": "Use scale down mode to delete/deallocate nodes", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "3266b225-86f4-4a16-92bd-ddea8a487cde", - "link": "https://learn.microsoft.com/azure/search/vector-search-index-size?tabs=portal-vector-quota", - "service": "Azure OpenAI", + "guid": "87e651ea-bc4a-4a87-a6df-c06a4b570ebc", + "link": "https://learn.microsoft.com/azure/aks/gpu-multi-instance", + "service": "AKS", "services": [ - "Storage", + "AKS", "WAF" ], "severity": "Medium", - "text": "Plan and manage AI Search Vector storage", - "waf": "Operational Excellence" + "text": "When required use multi-instance partitioning GPU on AKS Clusters", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "b4861bc3-bc14-4aeb-9e66-e8d9a3aec218", - "link": "https://learn.microsoft.com/azure/machine-learning/prompt-flow/how-to-end-to-end-llmops-with-prompt-flow?view=azureml-api-2", - "service": "Azure OpenAI", + "guid": "2b72a08b-0410-4cd6-9093-e068a5cf27e8", + "link": "https://learn.microsoft.com/azure/aks/start-stop-nodepools", + "service": "AKS", "services": [ - "WAF", - "ACR" + "WAF" ], - "severity": "Medium", - "text": "Ensure deployment of Azure OpenAI instances across your various environments, such as development, test, and production supporting lrarning & experimentation. Apply LLMOps practices to automate the lifecycle management of your GenAI applications", - "waf": "Operational Excellence" + "severity": "Low", + "text": "If running a Dev/Test cluster use NodePool Start/Stop", + "waf": "Cost" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "aa80932c-8ec9-4d1b-a770-26e5e6beba9e", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/provisioned-throughput-onboarding#understanding-the-provisioned-throughput-purchase-model", - "service": "Azure OpenAI", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.addonProfiles.azurepolicy) and properties.addonProfiles.azurepolicy.enabled==true) | distinct id,compliant", + "guid": "9ca48e4a-85e2-4223-bce8-bb12307ca5f1", + "link": "https://learn.microsoft.com/azure/governance/policy/concepts/policy-for-kubernetes", + "service": "AKS", "services": [ - "Storage", + "AKS", + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Evaluate usage of billing models - PAYG vs PTU. Start with PAYG and consider PTU when the usage is predictable in production since it offers dedicated memory and compute, reserved capacity, and consistent maximum latency for the specified model version", - "waf": "Cost Optimization" + "severity": "Medium", + "text": "Use Azure Policy for Kubernetes to ensure cluster compliance", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "e6436b07-36db-455f-9796-03334bdf9cc2", - "link": "https://techcommunity.microsoft.com/t5/ai-azure-ai-services-blog/how-to-control-azure-openai-models/ba-p/4146793", - "service": "Azure OpenAI", + "graph": "where type=='microsoft.containerservice/managedclusters' | project id,resourceGroup,name,pools=properties.agentPoolProfiles | project id,name,resourceGroup,poolcount=array_length(pools) | extend compliant = (poolcount > 1)", + "guid": "6f158e3e-a3a9-42c2-be7e-2165c3a87af4", + "link": "https://learn.microsoft.com/azure/aks/use-system-pools", + "service": "AKS", "services": [ "WAF" ], "severity": "Medium", - "text": "Evaluate the quality of prompts and applications when switching between model versions", - "waf": "Operational Excellence" + "text": "Separate applications from the control plane with user/system node pools", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "3418db61-2712-4650-9bb4-7a393a080327", - "link": "https://learn.microsoft.com/azure/machine-learning/prompt-flow/concept-model-monitoring-generative-ai-evaluation-metrics?view=azureml-api-2", - "service": "Azure OpenAI", + "guid": "a7a1f893-9bda-4477-98f2-4c116775c2ea", + "link": "https://learn.microsoft.com/azure/aks/use-system-pools", + "service": "AKS", "services": [ - "WAF", - "Monitor" + "WAF" ], - "severity": "Medium", - "text": "Evaluate, monitor and refine your GenAI apps for features like groundedness, relevance, accuracy, coherence and fluency", - "waf": "Operational Excellence" + "severity": "Low", + "text": "Add taint to your system nodepool to make it dedicated", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "294798b1-578b-4219-a46c-eb5443513592", - "service": "Azure OpenAI", + "guid": "55b46a94-8008-4ae7-b7e4-b475b6c8bdbf", + "link": "https://learn.microsoft.com/azure/container-registry/", + "service": "AKS", "services": [ + "ACR", "WAF" ], "severity": "Medium", - "text": "Evaluate your Azure AI Search results based on different search parameters", - "waf": "Operational Excellence" - }, - { - "arm-service": "Microsoft.CognitiveServices/accounts", - "checklist": "WAF checklist", - "guid": "2744293b-b628-4537-a551-19b08e8f5854", - "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/fine-tuning-considerations", - "service": "Azure OpenAI", - "services": [ - "WAF" - ], - "severity": "Medium", - "text": "Look at fine tuning models as way of increasing accuracy only when you have tried other basic approaches like prompt engineering and RAG with your data", - "waf": "Operational Excellence" + "text": "Use a private registry for your images, such as ACR", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "287d9cec-166c-4d07-8af9-b141a898a535", - "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/advanced-prompt-engineering?pivots=programming-language-chat-completions", - "service": "Azure OpenAI", + "guid": "59bce65d-e8a0-43f9-9879-468d66a786d6", + "link": "https://learn.microsoft.com/azure/security-center/container-security", + "service": "ACR", "services": [ "WAF" ], "severity": "Medium", - "text": "Use prompt engineering techniques to improve the accuracy of LLM responses", - "waf": "Operational Excellence" + "text": "Scan your images for vulnerabilities", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "e737897e-71ca-47da-acfa-962a1594946d", - "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/red-teaming", - "service": "Azure OpenAI", + "guid": "d167dd18-2b0a-4c24-8b99-9a646f8389a7", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-cluster-isolation", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Red team your GenAI applications", + "severity": "High", + "text": "Define app separation requirements (namespace/nodepool/cluster)", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "edb117e6-76aa-4f66-aca4-8e5a95f2223e", - "link": "https://www.microsoft.com/haxtoolkit/guideline/encourage-granular-feedback/", - "service": "Azure OpenAI", + "guid": "5e3df584-eccc-4d97-a3b6-bcda3b50eb2e", + "link": "https://github.com/Azure/secrets-store-csi-driver-provider-azure", + "service": "AKS", "services": [ + "AKV", "WAF" ], "severity": "Medium", - "text": "Provide end users with scoring options for LLM responses and track these scores. ", - "waf": "Operational Excellence" + "text": "Store your secrets in Azure Key Vault with the CSI Secrets Store driver", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "d5f3547c-c346-4d81-9028-a71ffe1b9b5d", - "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/optimizing-azure-openai-a-guide-to-limits-quotas-and-best/ba-p/4076268", - "service": "Azure OpenAI", + "guid": "b03dda6d-58d7-4c89-8ddb-107d5769ae66", + "link": "https://learn.microsoft.com/azure/aks/update-credentials", + "service": "AKS", "services": [ "WAF" ], "severity": "High", - "text": "Consider Quota management practices. Use dynamic quota for certain use cases when your application can use extra capacity opportunistically or the application itself is driving the rate at which the Azure OpenAI API is called", - "waf": "Cost Optimization" + "text": "If using Service Principals for the cluster, refresh credentials periodically (like quarterly)", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc410", - "link": "https://github.com/Azure/aoai-apim/blob/main/README.md", - "service": "Azure OpenAI", + "guid": "e7ba73a3-0508-4f80-806f-527db30cee96", + "link": "https://learn.microsoft.com/azure/aks/use-kms-etcd-encryption", + "service": "AKS", "services": [ - "APIM", - "ACR", - "Entra", - "LoadBalancer", "WAF" ], "severity": "Medium", - "text": "Use Load balancer solutions like APIM based gateway for balancing load and capacity across services and regions", - "waf": "Operational Excellence" + "text": "If required add Key Management Service etcd encryption", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc411", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/fine-tuning?tabs=turbo%2Cpython-new&pivots=programming-language-studio#import-training-data-from-azure-blob-store", - "service": "Azure OpenAI", + "guid": "ec8e4e42-0344-41b0-b865-9123e8956d31", + "link": "https://learn.microsoft.com/azure/confidential-computing/confidential-nodes-aks-overview", + "service": "AKS", "services": [ - "Storage", + "AKS", "WAF" ], - "severity": "Medium", - "text": "Follow the guidance for fine-tuning with large data files and import the data from an Azure blob store. Large files, 100 MB or larger, can become unstable when uploaded through multipart forms because the requests are atomic and can't be retried or resumed", - "waf": "Reliability" + "severity": "Low", + "text": "If required consider using Confidential Compute for AKS", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc412", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/quota?tabs=rest", - "service": "Azure OpenAI", + "guid": "c9e95ffe-6dd1-4a17-8c5f-110389ca9b21", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-containers-enable", + "service": "AKS", "services": [ - "WAF", - "Monitor" + "Defender", + "WAF" ], "severity": "Medium", - "text": "Manage rate limits for your model deployments and monitor usage of tokens per minute (TPM) and requests per minute (RPM) for pay-as-you-go deployments", - "waf": "Reliability" + "text": "Consider using Defender for Containers", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc413", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitor-openai", - "service": "Azure OpenAI", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.servicePrincipalProfile.clientId=='msi') | distinct id,compliant", + "guid": "ed127dd1-42b0-46b2-8c69-99a646f3389a", + "link": "https://learn.microsoft.com/azure/aks/use-managed-identity", + "service": "AKS", "services": [ - "WAF", - "Monitor" + "Entra", + "WAF" ], - "severity": "Medium", - "text": "Monitor provision-managed utilization if you're using the provisioned throughput payment model", - "waf": "Reliability" + "severity": "High", + "text": "Use managed identities instead of Service Principals", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc414", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/content-filters", - "service": "Azure OpenAI", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = isnotnull(properties.aadProfile) | distinct id,compliant", + "guid": "7e42c78e-78c0-46a6-8a21-94956e698dc4", + "link": "https://learn.microsoft.com/azure/aks/managed-aad", + "service": "AKS", "services": [ + "Entra", "WAF" ], "severity": "Medium", - "text": "Tune content filters to minimize false positives from overly aggressive filters", - "waf": "Reliability" + "text": "Integrate authentication with AAD (using the managed integration)", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc415", - "link": "https://learn.microsoft.com/azure/ai-services/openai/encrypt-data-at-rest", - "service": "Azure OpenAI", + "guid": "a2fe27b2-e287-401a-8352-beedf79b488d", + "link": "https://learn.microsoft.com/azure/aks/control-kubeconfig-access", + "service": "AKS", "services": [ - "AKV", "WAF" ], "severity": "Medium", - "text": "Use customer-managed keys for fine-tuned models and training data that's uploaded to Azure OpenAI", + "text": "Limit access to admin kubeconfig (get-credentials --admin)", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "graph": "resources | where type == 'microsoft.cognitiveservices/accounts' and kind =~ 'contentsafety' | project id, compliant = 1", - "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc416", - "link": "https://learn.microsoft.com/azure/ai-services/content-safety/concepts/jailbreak-detection", - "service": "Azure OpenAI", + "guid": "eec4962c-c3bd-421b-b77f-26e5e6b3bec3", + "link": "https://learn.microsoft.com/azure/aks/manage-azure-rbac", + "service": "AKS", "services": [ - "LoadBalancer", + "RBAC", + "Entra", "WAF" ], "severity": "Medium", - "text": "Implement jailbreak risk detection to safeguard your language model deployments against prompt injection attacks", + "text": "Integrate authorization with AAD RBAC", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc417", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitor-openai", - "service": "Azure OpenAI", + "guid": "d4f3537c-1346-4dc5-9027-a71ffe1bd05d", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-identity", + "service": "AKS", "services": [ + "RBAC", + "AKS", "WAF" ], - "severity": "Medium", - "text": "Use security controls like throttling, service isolation and gateway pattern to prevent attacks that might exhaust model usage quotas", + "severity": "High", + "text": "Use namespaces for restricting RBAC privilege in Kubernetes", "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "72d41e36-11cc-457b-9a4b-1410d43958a9", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", - "service": "Azure OpenAI", + "guid": "d2e0d5d7-71d4-41e3-910c-c57b4a4b1410", + "link": "https://learn.microsoft.com/azure/aks/workload-identity-migration-sidecar", + "service": "AKS", "services": [ - "WAF", - "Cost" + "Entra", + "WAF" ], "severity": "Medium", - "text": "Develop your cost model, considering prompt sizes. Understanding prompt input and response sizes and how text translates into tokens helps you create a viable cost model", - "waf": "Cost Optimization" + "text": "For Pod Identity Access Management use Azure AD Workload Identity (preview)", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "72d41e36-11cc-457b-9a4b-1410d43958a1", - "link": "https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/", - "service": "Azure OpenAI", + "guid": "f4dcf690-1b30-407d-abab-6f8aa780d3a3", + "link": "https://learn.microsoft.com/azure/aks/managed-aad#non-interactive-sign-in-with-kubelogin", + "service": "AKS", "services": [ - "WAF", - "Cost" + "AKS", + "WAF" ], "severity": "Medium", - "text": "Consider model pricing and capabilities when you choose models. Start with less-costly models for less-complex tasks like text generation or completion tasks and for complex tasks like language translation or content understanding, consider using more advanced models. Optimize costs while still achieving the desired application performance", - "waf": "Cost Optimization" + "text": "For AKS non-interactive logins use kubelogin (preview)", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "72d41e36-11cc-457b-9a4b-1410d43958a2", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", - "service": "Azure OpenAI", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.disableLocalAccounts==true) | distinct id,compliant", + "guid": "b085b1f2-3119-4771-8c9a-bbf4411810ec", + "link": "https://learn.microsoft.com/azure/aks/managed-aad#disable-local-accounts", + "service": "AKS", "services": [ - "WAF", - "Cost" + "AKS", + "WAF" ], "severity": "Medium", - "text": "Maximize Azure OpenAI price breakpoints like fine-tuning and model breakpoints like image generation to your advantage. Fine-tuning is charged per hour, use as much time as you have available per hour to improve results without slipping into the next billing period. The cost for generating 100 images is the same as the cost for 1 image", - "waf": "Cost Optimization" + "text": "Disable AKS local accounts", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "72d41e36-11cc-457b-9a4b-1410d43958a3", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", - "service": "Azure OpenAI", + "guid": "36abb0db-c118-4f4c-9880-3f30f9a2deb6", + "link": "https://learn.microsoft.com/azure/aks/managed-aad#configure-just-in-time-cluster-access-with-azure-ad-and-aks", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Remove unused fine-tuned models when they're no longer being consumed to avoid incurring an ongoing hosting fee", - "waf": "Cost Optimization" + "severity": "Low", + "text": "Configure if required Just-in-time cluster access", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "7f42c78e-78cb-46a2-8ad1-90916e6a8d8g", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", - "service": "Azure OpenAI", + "guid": "c4d7f4c6-79bf-45d0-aa05-ce8fc717e150", + "link": "https://learn.microsoft.com/azure/aks/managed-aad#use-conditional-access-with-azure-ad-and-aks", + "service": "AKS", "services": [ + "AKS", + "Entra", "WAF" ], - "severity": "Medium", - "text": "Create concise prompts that provide enough context for the model to generate a useful response. Also ensure that you optimize the limit of the response length.", - "waf": "Cost Optimization" + "severity": "Low", + "text": "Configure if required AAD conditional access for AKS", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "b4861bc3-bc14-4aeb-9e66-e8d9a3aec219", - "link": "https://learn.microsoft.com/azure/ai-services/create-account-bicep", - "service": "Azure OpenAI", + "guid": "e1123a7c-a333-4eb4-a120-4ee3f293c9f3", + "link": "https://learn.microsoft.com/azure/aks/use-group-managed-service-accounts", + "service": "AKS", "services": [ + "AKS", "WAF" ], - "severity": "Medium", - "text": "Use infrastructure as code (IaC) to deploy Azure OpenAI, model deployments, and other infrastructure required for fine-tuning models", - "waf": "Operational Excellence" + "severity": "Low", + "text": "If required for Windows AKS workloads configure gMSA ", + "waf": "Security" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "2744293b-b628-4537-a551-19b08e8f5855", - "link": "https://learn.microsoft.com/azure/architecture/guide/multitenant/service/openai", - "service": "Azure OpenAI", + "guid": "1f711a74-3672-470b-b8b8-a2148d640d79", + "link": "https://learn.microsoft.com/azure/aks/use-managed-identity#use-a-pre-created-kubelet-managed-identity", + "service": "AKS", "services": [ + "Entra", "WAF" ], "severity": "Medium", - "text": "Consider using dedicated model deployments per consumer group to provide per-model usage isolation that can help prevent noisy neighbors between your consumer groups", - "waf": "Operational Excellence" + "text": "For finer control consider using a managed Kubelet Identity", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "d7941d4a-7b6f-458f-8714-2f8f8c059ad4", - "link": "https://learn.microsoft.com/azure/api-management/api-management-error-handling-policies", - "service": "APIM", + "guid": "cbd8ac2a-aebc-4a2a-94da-1dbf3dc99248", + "link": "https://azure.github.io/application-gateway-kubernetes-ingress/setup/install-existing/", + "service": "AKS", "services": [ - "AzurePolicy", + "ACR", + "AppGW", "WAF" ], "severity": "Medium", - "text": "Implement an error handling policy at the global level", - "waf": "Operations" + "text": "If using AGIC, do not share an AppGW across clusters", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "0b0c0765-ff37-4369-90bd-3eb23ce71b08", - "link": "https://learn.microsoft.com/azure/api-management/set-edit-policies?tabs=form#use-base-element-to-set-policy-evaluation-order", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnull(properties.addonProfiles.httpApplicationRouting) or properties.addonProfiles.httpApplicationRouting.enabled==false) | distinct id,compliant", + "guid": "8008ae7d-7e4b-4475-a6c8-bdbf59bce65d", + "link": "https://learn.microsoft.com/azure/aks/http-application-routing", + "service": "AKS", "services": [ - "AzurePolicy", + "AKS", "WAF" ], - "severity": "Medium", - "text": "Ensure all APIs policies include a element.", - "waf": "Operations" + "severity": "High", + "text": "Do not use AKS HTTP Routing Add-On, use instead the managed NGINX ingress with the application routing add-on.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "a5c45b03-93b6-42fe-b16b-8fccb6a79902", - "link": "https://learn.microsoft.com/azure/api-management/policy-fragments", - "service": "APIM", + "guid": "7bacd7b9-c025-4a9d-a5d2-25d6bc5439d9", + "link": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview", + "service": "AKS", "services": [ - "AzurePolicy", - "WAF", - "ACR" + "WAF" ], "severity": "Medium", - "text": "Use Policy Fragments to avoid repeating same policies definitions across multiple APIs", - "waf": "Operations" + "text": "For Windows workloads use Accelerated Networking", + "waf": "Performance" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c3818a95-6ff3-4474-88dc-e809b46dad6a", - "link": "https://learn.microsoft.com/azure/api-management/monetization-support", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (tolower(properties.networkProfile.loadBalancerSku)=='standard') | distinct id,compliant", + "guid": "ba7da7be-9952-4914-a384-5d997cb39132", + "link": "https://learn.microsoft.com/azure/aks/load-balancer-standard", + "service": "AKS", "services": [ + "LoadBalancer", "WAF" ], - "severity": "Medium", - "text": "If you are planning to monetize your APIs, review the 'monetization support' article for best practices", - "waf": "Operations" + "severity": "High", + "text": "Use the standard ALB (as opposed to the basic one)", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "a7d0840a-c8c4-4e83-adec-5ca578eb4049", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-use-azure-monitor#resource-logs", - "service": "APIM", + "guid": "22fbe8d6-9b40-47ef-9011-25bb1a555a6b", + "link": "https://learn.microsoft.com/azure/aks/use-multiple-node-pools#add-a-node-pool-with-a-unique-subnet", + "service": "AKS", "services": [ - "WAF", - "Monitor" + "VNet", + "WAF" ], - "severity": "High", - "text": "Enable Diagnostics Settings to export logs to Azure Monitor", - "waf": "Operations" + "severity": "Medium", + "text": "If using Azure CNI, consider using different Subnets for NodePools", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "8691fa38-45ed-4299-a247-fecd98d35deb", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-app-insights", - "service": "APIM", + "guid": "c3c39c98-6bb2-4c12-859a-114b5e3df584", + "link": "https://learn.microsoft.com/azure/private-link/private-link-overview", + "service": "AKS", "services": [ + "VNet", + "PrivateLink", "WAF" ], "severity": "Medium", - "text": "Enable Application Insights for more detailed telemetry", - "waf": "Operations" + "text": "Use Private Endpoints (preferred) or Virtual Network Service Endpoints to access PaaS services from the cluster", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "55fd27bb-76ac-4a91-bc37-049e885be6b7", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-use-azure-monitor", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.networkProfile.networkPlugin=='azure') | distinct id,compliant", + "guid": "a0f61565-9de5-458f-a372-49c831112dbd", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-network", + "service": "AKS", "services": [ - "WAF", - "Monitor" + "WAF" ], "severity": "High", - "text": "Configure alerts on the most critical metrics", - "waf": "Operations" + "text": "Choose the best CNI network plugin for your requirements (Azure CNI recommended)", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "39460bdb-156f-4dc2-a87f-1e8c11ab0998", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#certificate-management-in-azure-key-vault", - "service": "APIM", + "guid": "7faf12e7-0943-4f63-8472-2da29c2b1cd6", + "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", + "service": "AKS", "services": [ - "AKV", + "VNet", "WAF" ], "severity": "High", - "text": "Ensure that custom SSL certificates are stored an Azure Key Vault so they can be securely accessed and updated", - "waf": "Security" + "text": "If using Azure CNI, size your subnet accordingly considering the maximum number of pods per node", + "waf": "Performance" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "e9217997-5f6c-479d-8576-8f2adf706ec8", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#azure-ad-authentication-required-for-data-plane-access", - "service": "APIM", + "guid": "22f54b29-bade-43aa-b1e8-c38ec9366673", + "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", + "service": "AKS", "services": [ - "WAF", - "Entra" + "WAF" ], "severity": "High", - "text": "Protect incoming requests to APIs (data plane) with Azure AD", - "waf": "Security" + "text": "If using Azure CNI, check the maximum pods/node (default 30)", + "waf": "Performance" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "5e5f64ba-c90e-480e-8888-398d96cf0bfb", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-aad", - "service": "APIM", + "description": "For internal apps organizations often open the whole AKS subnet in their firewalls. This opens network access to the nodes too, and potentially to the pods as well (if using Azure CNI). If LoadBalancer IPs are in a different subnet, only this one needs to be available to the app clients. Another reason is that if the IP addresses in the AKS subnet are a scarce resource, consuming its IP addresses for services will reduce the maximum scalability of the cluster .", + "guid": "13c00567-4b1e-4945-a459-c373e7ed6162", + "link": "https://learn.microsoft.com/azure/aks/internal-lb", + "service": "AKS", "services": [ - "WAF", - "Entra" + "VNet", + "AKS", + "WAF" ], - "severity": "Medium", - "text": "Use Microsoft Entra ID to authenticate users in the Developer Portal", + "severity": "Low", + "text": "If using private-IP LoadBalancer services, use a dedicated subnet (not the AKS subnet)", "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "f8e574ce-280f-49c8-b2ef-68279b081cf3", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-create-groups", - "service": "APIM", + "guid": "43f63047-22d9-429c-8b1c-d622f54b29ba", + "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Create appropriate groups to control the visibility of the products", - "waf": "Security" + "severity": "High", + "text": "Size the service IP address range accordingly (it is going to limit the cluster scalability)", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "06862505-2d9a-4874-9491-2837b00a3475", - "link": "https://learn.microsoft.com/azure/api-management/backends", - "service": "APIM", + "guid": "57bf217f-6dc8-481c-81e2-785773e9c00f", + "link": "https://learn.microsoft.com/azure/aks/use-byo-cni", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Use Backends feature to eliminate redundant API backend configurations", - "waf": "Operations" + "severity": "Low", + "text": "If required add your own CNI plugin", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "03b125d5-b69b-4739-b7fd-84b86da4933e", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-properties?tabs=azure-portal", - "service": "APIM", + "guid": "4b3bb365-9458-44d9-9ed1-5c8f52890364", + "link": "https://learn.microsoft.com/azure/aks/use-multiple-node-pools#assign-a-public-ip-per-node-for-your-node-pools", + "service": "AKS", "services": [ - "AzurePolicy", + "AKS", "WAF" ], - "severity": "Medium", - "text": "Use Named Values to store common values that can be used in policies", - "waf": "Operations" + "severity": "Low", + "text": "If required configure Public IP per node in AKS", + "waf": "Performance" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "beae759e-4ddb-4326-bf26-47f87d3454b6", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region", - "service": "APIM", + "guid": "b3808b9f-a1cf-4204-ad01-3a923ce474db", + "link": "https://learn.microsoft.com/azure/aks/concepts-network", + "service": "AKS", "services": [ - "WAF", - "ACR" + "WAF" ], "severity": "Medium", - "text": "For DR, leverage the premium tier with deployments scaled across two or more regions for 99.99% SLA", + "text": "Use an ingress controller to expose web-based apps instead of exposing them with LoadBalancer-type services", "waf": "Reliability" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "9c8d1664-dd9a-49d4-bd83-950af0af4044", - "link": "https://learn.microsoft.com/azure/api-management/high-availability", - "service": "APIM", - "services": [ - "WAF" - ], - "severity": "Medium", - "text": "Deploy at least one unit in two or more availability zones for an increased SLA of 99.99%", - "waf": "Reliability" - }, - { - "arm-service": "Microsoft.ApiManagement/service", - "checklist": "WAF checklist", - "guid": "8d2db6e8-85c6-4118-a52c-ae76a4f27934", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#service-native-backup-capability", - "service": "APIM", + "guid": "ccb534e7-416e-4a1d-8e93-533b53199085", + "link": "https://learn.microsoft.com/azure/aks/nat-gateway", + "service": "AKS", "services": [ - "WAF", - "Backup" + "WAF" ], - "severity": "High", - "text": "Ensure there is an automated backup routine", + "severity": "Low", + "text": "Use Azure NAT Gateway as outboundType for scaling egress traffic", "waf": "Reliability" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "43e60b94-7bca-43a2-aadf-efb04d63a485", - "link": "https://learn.microsoft.com/azure/api-management/retry-policy", - "service": "APIM", + "guid": "8ee9a69a-1b58-4b1e-9c61-476e110a160b", + "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni#dynamic-allocation-of-ips-and-enhanced-subnet-support", + "service": "AKS", "services": [ - "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Use Policies to add a fail-over backend URL and caching to reduce failing calls.", + "text": "Use Dynamic allocations of IPs in order to avoid Azure CNI IP exhaustion", "waf": "Reliability" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "8210699f-8d43-45c2-8f19-57e54134bd8f", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-log-event-hubs", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.networkProfile.outboundType=='userDefinedRouting') | distinct id,compliant", + "guid": "3b365a91-7ecb-4e48-bbe5-4cd7df2e8bba", + "link": "https://learn.microsoft.com/azure/aks/limit-egress-traffic", + "service": "AKS", "services": [ - "AzurePolicy", - "EventHubs", + "NVA", "WAF" ], - "severity": "Low", - "text": "If you need to log at high performance levels, consider Event Hubs policy", - "waf": "Operations" + "severity": "High", + "text": "Filter egress traffic with AzFW/NVA if your security requirements mandate it", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "121bfc39-fa7b-4096-b93b-ab56c1bc0bed", - "link": "https://learn.microsoft.com/azure/api-management/api-management-sample-flexible-throttling", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = ((isnull(properties.apiServerAccessProfile.enablePrivateCluster) or properties.apiServerAccessProfile.enablePrivateCluster==false) and isnotnull(properties.apiServerAccessProfile.authorizedIPRanges)) | distinct id,compliant", + "guid": "c4581559-bb91-463e-a908-aed8c44ce3b2", + "link": "https://learn.microsoft.com/azure/aks/api-server-authorized-ip-ranges", + "service": "AKS", "services": [ - "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Apply throttling policies to control the number of requests per second", - "training": "https://learn.microsoft.com/training/modules/protect-apis-on-api-management/", - "waf": "Performance" + "text": "If using a public API endpoint, restrict the IP addresses that can access it", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "bb5f356b-3daf-47a2-a9ee-867a8100bbd5", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-autoscale", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | where isnotnull(properties.apiServerAccessProfile.enablePrivateCluster) | extend compliant = (properties.apiServerAccessProfile.enablePrivateCluster==true) | distinct id, compliant", + "guid": "ecccd979-3b6b-4cda-9b50-eb2eb03dda6d", + "link": "https://learn.microsoft.com/azure/aks/private-clusters", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Configure autoscaling to scale out the number of instances when the load increases", - "waf": "Performance" + "severity": "High", + "text": "Use private clusters if your requirements mandate it", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "84b94abb-59b6-4b9d-8587-3413669468e8", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-provision-self-hosted-gateway", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | where isnotnull(properties.apiServerAccessProfile.enablePrivateCluster) | extend compliant = (properties.apiServerAccessProfile.enablePrivateCluster==true) | distinct id, compliant", + "guid": "ce7f2a7c-297c-47c6-adea-a6ff838db665", + "link": "https://learn.microsoft.com/azure/aks/use-network-policies", + "service": "AKS", "services": [ + "AKS", + "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Deploy self-hosted gateways where Azure doesn't have a region close to the backend APIs.", - "waf": "Performance" + "text": "For Windows 2019 and 2022 AKS nodes Calico Network Policies can be used ", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "1fe8db45-a017-4888-8c4d-4422583cfae0", - "link": "https://learn.microsoft.com/azure/api-management/upgrade-and-scale#upgrade-and-scale", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = isnotnull(properties.networkProfile.networkPolicy) | distinct id,compliant", + "guid": "58d7c892-ddb1-407d-9769-ae669ca48e4a", + "link": "https://learn.microsoft.com/azure/aks/use-network-policies", + "service": "AKS", "services": [ + "AKS", + "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "Use the premium tier for production workloads.", - "waf": "Reliability" + "severity": "High", + "text": "Enable a Kubernetes Network Policy option (Calico/Azure)", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "1b8d68a4-66cd-44d5-ba94-3ee94440e8d6", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region#-route-api-calls-to-regional-backend-services", - "service": "APIM", + "guid": "85e2223e-ce8b-4b12-907c-a5f16f158e3e", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-network", + "service": "AKS", "services": [ + "AKS", "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "In multi-region model, use Policies to route the requests to regional backends based on availability or latency.", - "waf": "Reliability" - }, - { - "arm-service": "Microsoft.ApiManagement/service", - "checklist": "WAF checklist", - "guid": "46f07d33-ef9a-44e8-8f98-67c097c5d8cd", - "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits#api-management-limits", - "service": "APIM", - "services": [ - "Entra", - "WAF", - "APIM" - ], "severity": "High", - "text": "Be aware of APIM's limits", - "waf": "Reliability" + "text": "Use Kubernetes network policies to increase intra-cluster security", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "10f58602-f0f9-4d77-972a-956f6e0f2600", - "link": "https://learn.microsoft.com/en-us/azure/api-management/self-hosted-gateway-overview", - "service": "APIM", + "guid": "a3a92c2d-e7e2-4165-a3a8-7af4a7a1f893", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-network", + "service": "AKS", "services": [ "WAF" ], "severity": "High", - "text": "Ensure that the self-hosted gateway deployments are resilient.", - "waf": "Reliability" - }, - { - "arm-service": "Microsoft.ApiManagement/service", - "checklist": "WAF checklist", - "guid": "7519e385-a88b-4d34-966b-6269d686e890", - "link": "https://learn.microsoft.com/azure/api-management/front-door-api-management", - "service": "APIM", - "services": [ - "Entra", - "WAF", - "FrontDoor", - "APIM" - ], - "severity": "Medium", - "text": "Use Azure Front Door in front of APIM for multi-region deployment", - "waf": "Performance" + "text": "Use a WAF for web workloads (UIs or APIs)", + "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "cd45c90e-7690-4753-930b-bf290c69c074", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#virtual-network-integration", - "service": "APIM", + "graph": "Resources | where type=~'microsoft.containerservice/managedclusters' | project resourceGroup,name,pools=properties.agentPoolProfiles | mv-expand pools | project subnetId=tostring(pools.vnetSubnetID) | where isnotempty(subnetId) | join (Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,enableDdosProtection=tostring(properties.enableDdosProtection),subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,enableDdosProtection,subnetId=tostring(subnets.id)) on subnetId | distinct id,resourceGroup,name,enableDdosProtection | extend compliant = (enableDdosProtection == 'true')", + "guid": "9bda4776-8f24-4c11-9775-c2ea55b46a94", + "link": "https://learn.microsoft.com/azure/virtual-network/ddos-protection-overview", + "service": "AKS", "services": [ "VNet", + "DDoS", + "AKS", "WAF" ], "severity": "Medium", - "text": "Deploy the service within a Virtual Network (VNet)", + "text": "Use DDoS Standard in the AKS Virtual Network", "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "02661582-b3d1-48d1-9d7b-c6a918a0ca33", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#network-security-group-support", - "service": "APIM", + "graph": "Resources | where type=~'microsoft.containerservice/managedclusters' | project resourceGroup,name,pools=properties.agentPoolProfiles | mv-expand pools | project subnetId=tostring(pools.vnetSubnetID) | where isnotempty(subnetId) | join (Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,enableDdosProtection=tostring(properties.enableDdosProtection),subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,enableDdosProtection,subnetId=tostring(subnets.id)) on subnetId | distinct id,resourceGroup,name,enableDdosProtection | extend compliant = (enableDdosProtection == 'true')", + "guid": "6c46b91a-1107-4485-ad66-3183e2a8c266", + "link": "https://learn.microsoft.com/azure/aks/http-proxy", + "service": "AKS", "services": [ - "Entra", - "APIM", - "VNet", - "WAF", - "Monitor" + "WAF" ], - "severity": "Medium", - "text": "Deploy network security groups (NSG) to your subnets to restrict or monitor traffic to/from APIM.", + "severity": "Low", + "text": "If required add company HTTP Proxy", "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "67437a28-2721-4a2c-becd-caa54c8237a5", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#azure-private-link", - "service": "APIM", + "guid": "e9855d04-c3c3-49c9-a6bb-2c12159a114b", + "link": "https://learn.microsoft.com/azure/aks/servicemesh-about", + "service": "AKS", "services": [ - "Entra", - "APIM", - "PrivateLink", - "VNet", "WAF" ], "severity": "Medium", - "text": "Deploy Private Endpoints to filter incoming traffic when APIM is not deployed to a VNet.", + "text": "Consider using a service mesh for advanced microservice communication management", "waf": "Security" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "d698adbd-3288-44cb-b10a-9b572da395ae", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#disable-public-network-access", - "service": "APIM", + "guid": "67f7a9ed-5b31-4f38-a3f3-9812b2463cff", + "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-metric-alerts", + "service": "AKS", "services": [ + "Monitor", "WAF" ], "severity": "High", - "text": "Disable Public Network Access", - "waf": "Security" + "text": "Configure alerts on the most critical metrics (see Container Insights for recommendations)", + "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "0674d750-0c6f-4ac0-8717-ceec04d0bdbd", - "link": "https://learn.microsoft.com/azure/api-management/automation-manage-api-management", - "service": "APIM", + "guid": "337453a3-cc63-4963-9a65-22ac19e80696", + "link": "https://learn.microsoft.com/azure/advisor/advisor-get-started", + "service": "AKS", "services": [ + "Entra", "WAF" ], - "severity": "Medium", - "text": "Simplify management with PowerShell automation scripts", + "severity": "Low", + "text": "Check regularly Azure Advisor for recommendations on your cluster", "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c385bfcd-49fd-4786-81ba-cedbb4c57345", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/app-platform/api-management/platform-automation-and-devops#design-recommendations", - "service": "APIM", + "guid": "3aa70560-e7e7-4968-be3d-628af35b2ced", + "link": "https://learn.microsoft.com/azure/aks/certificate-rotation", + "service": "AKS", "services": [ - "Entra", - "WAF", - "APIM" + "AKS", + "WAF" ], - "severity": "Medium", - "text": "Configure APIM via Infrastructure-as-code. Review DevOps best practices from the Cloud Adaption Framework APIM Landing Zone Accelerator", + "severity": "Low", + "text": "Enable AKS auto-certificate rotation", "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "6c3a27c0-197f-426c-9ffa-86fed51d9ab6", - "link": "https://learn.microsoft.com/azure/api-management/visual-studio-code-tutorial", - "service": "APIM", + "guid": "e189c599-df0d-45a7-9dd4-ce32c1881370", + "link": "https://learn.microsoft.com/azure/aks/supported-kubernetes-versions", + "service": "AKS", "services": [ - "Entra", - "WAF", - "APIM" + "AKS", + "WAF" ], - "severity": "Medium", - "text": "Promote usage of Visual Studio Code APIM extension for faster API development", + "severity": "High", + "text": "Have a regular process to upgrade your kubernetes version periodically (quarterly, for example), or use the AKS autoupgrade feature", "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "354f1c03-8112-4965-85ad-c0074bddf231", - "link": "https://learn.microsoft.com/azure/api-management/devops-api-development-templates", - "service": "APIM", + "guid": "6f7c4c0d-4e51-4464-ad24-57ed67138b82", + "link": "https://learn.microsoft.com/azure/aks/node-updates-kured", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Implement DevOps and CI/CD in your workflow", + "severity": "High", + "text": "Use kured for Linux node upgrades in case you are not using node-image upgrade", "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "b6439493-426a-45f3-9697-cf65baee208d", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-mutual-certificates-for-clients", - "service": "APIM", + "guid": "139c9580-ade3-426a-ba09-cf157d9f6477", + "link": "https://learn.microsoft.com/azure/aks/node-image-upgrade", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Secure APIs using client certificate authentication", - "waf": "Security" + "severity": "High", + "text": "Have a regular process to upgrade the cluster node images periodically (weekly, for example)", + "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "2a67d143-1033-4c0a-8732-680896478f08", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-mutual-certificates", - "service": "APIM", + "guid": "0102ce16-ee30-41e6-b882-e52e4621dd68", + "link": "https://learn.microsoft.com/azure/architecture/example-scenario/bedrock/bedrock-automated-deployments", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Secure backend services using client certificate authentication", - "waf": "Security" + "severity": "Low", + "text": "Consider gitops to deploy applications or cluster configuration to multiple clusters", + "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "074435f5-4a46-41ac-b521-d6114cb5d845", - "link": "https://learn.microsoft.com/azure/api-management/mitigate-owasp-api-threats", - "service": "APIM", + "guid": "d7672c26-7602-4482-85a4-14527fbe855c", + "link": "https://learn.microsoft.com/azure/aks/command-invoke", + "service": "AKS", "services": [ + "AKS", "WAF" ], - "severity": "Medium", - "text": "Review 'Recommendations to mitigate OWASP API Security Top 10 threats' article and check what is applicable to your APIs", - "waf": "Security" + "severity": "Low", + "text": "Consider using AKS command invoke on private clusters", + "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "5507c4b8-a7f8-41d6-9661-418c987100c9", - "link": "https://learn.microsoft.com/azure/api-management/authorizations-overview", - "service": "APIM", + "guid": "31d7aaab-7571-4449-ab80-53d89e89d17b", + "link": "https://learn.microsoft.com/azure/aks/node-auto-repair#node-autodrain", + "service": "AKS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Use Authorizations feature to simplify management of OAuth 2.0 token for your backend APIs", - "waf": "Security" + "severity": "Low", + "text": "For planned events consider using Node Auto Drain", + "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "2deee033-b906-4bc2-9f26-c8d3699fe091", - "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-manage-protocols-ciphers", - "service": "APIM", + "guid": "ed0fda7f-211b-47c7-8b6e-c18873fb473c", + "link": "https://learn.microsoft.com/azure/aks/faq", + "service": "AKS", "services": [ "WAF" ], "severity": "High", - "text": "Use the latest TLS version when encrypting information in transit. Disable outdated and unnecessary protocols and ciphers when possible.", - "waf": "Security" + "text": "Develop own governance practices to make sure no changes are performed by operators in the node RG (aka 'infra RG')", + "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "f8af3d94-1d2b-4070-846f-849197524258", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#im-8-restrict-the-exposure-of-credential-and-secrets", - "service": "APIM", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (properties.nodeResourceGroup !startswith 'MC_') | distinct id,compliant", + "guid": "73b32a5a-67f7-4a9e-b5b3-1f38c3f39812", + "link": "https://learn.microsoft.com/azure/aks/cluster-configuration", + "service": "AKS", "services": [ - "AKV", "WAF" ], - "severity": "High", - "text": "Ensure that secrets (Named values) are stored an Azure Key Vault so they can be securely accessed and updated", - "waf": "Security" + "severity": "Low", + "text": "Use custom Node RG (aka 'Infra RG') name", + "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "791abd8b-7706-4e31-9569-afefde724be3", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#managed-identities", - "service": "APIM", + "guid": "b2463cff-e189-4c59-adf0-d5a73dd4ce32", + "link": "https://kubernetes.io/docs/setup/release/notes/", + "service": "AKS", "services": [ - "WAF", - "Entra" + "AKS", + "WAF" ], "severity": "Medium", - "text": "Use managed identities to authenticate to other Azure resources whenever possible", - "waf": "Security" + "text": "Do not use deprecated Kubernetes APIs in your YAML manifests", + "waf": "Operations" }, { - "arm-service": "Microsoft.ApiManagement/service", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "220c4ca6-6688-476b-b2b5-425a78e6fb87", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#ns-6-deploy-web-application-firewall", - "service": "APIM", + "guid": "c1881370-6f7c-44c0-b4e5-14648d2457ed", + "link": "https://learn.microsoft.com/azure-stack/aks-hci/adapt-apps-mixed-os-clusters", + "service": "AKS", "services": [ - "AppGW", - "Entra", - "WAF", - "APIM" + "WAF" ], - "severity": "High", - "text": "Use web application firewall (WAF) by deploying Application Gateway in front of APIM", - "waf": "Security" + "severity": "Low", + "text": "Taint Windows nodes", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Leverage zone-redundancy to ensure high availability in the event of zone-level failures. Use Premium V2/V3 or Isolated v2 tiers, which provide support for zone-redundant deployments and ensure minimal downtime during disasters.", - "guid": "b32e1aa1-4813-4602-88fe-27ca2891f421", - "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/app-service-web-app/zone-redundant?source=recommendations", - "service": "App Services", + "guid": "67138b82-0102-4ce1-9ee3-01e6e882e52e", + "link": "https://learn.microsoft.com/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-20H2%2Cwindows-10-20H2", + "service": "AKS", "services": [ - "AppSvc", "WAF" ], "severity": "Low", - "text": "Implement a baseline highly available zone-redundant web application architecture. Ensure your Azure App Service is on Premium V2/V3 or Isolated v2 tiers for zone-redundant support.", - "waf": "Reliability" + "text": "Keep windows containers patch level in sync with host patch level", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Leverage staging slots for zero-downtime deployments and automated backups to ensure disaster recovery. Choose the appropriate tier (Standard or Premium) based on the number of slots and disaster recovery requirements.", - "graph": "resources | where type =~ 'microsoft.web/serverfarms' | extend compliant = (sku.tier == 'Premium' or sku.tier == 'Standard') | distinct id,compliant", - "guid": "e4b31c6a-2e3f-4df1-8e8b-9c3aa5a27820", - "link": "https://learn.microsoft.com/azure/app-service/overview-hosting-plans", - "service": "App Services", + "description": "Via Diagnostic Settings at the cluster level", + "guid": "5b56ad48-408f-4e72-934c-476ba280dcf5", + "link": "https://learn.microsoft.com/azure/aks/monitor-aks", + "service": "AKS", "services": [ - "ASR", - "WAF", - "Backup" + "Monitor", + "WAF" ], - "severity": "Medium", - "text": "Use Premium and Standard tiers for staging slots and automated backups. Align your backup retention period with disaster recovery needs.", - "waf": "Reliability" + "severity": "Low", + "text": "Send master logs (aka API logs) to Azure Monitor or your preferred log management solution", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Availability Zones provide physical isolation across datacenters in a region, reducing downtime during outages. Verify your region supports Availability Zones and use Premium V2/V3 tiers for zone-redundant deployments.", - "guid": "a7e2e6c2-491f-4fa4-a82b-521d0bc3b202", - "link": "https://learn.microsoft.com/azure/reliability/migrate-app-service", - "service": "App Services", + "guid": "64d1a846-e28a-4b6b-9a33-22a635c15a21", + "link": "https://learn.microsoft.com/azure/aks/node-pool-snapshot", + "service": "AKS", "services": [ - "WAF", - "ACR" + "WAF" ], - "severity": "High", - "text": "Leverage Availability Zones where regionally applicable (Premium V2/V3 tier required). Check region support for Availability Zones.", - "waf": "Reliability" + "severity": "Low", + "text": "If required use nodePool snapshots", + "waf": "Cost" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Enable health checks to detect unhealthy instances in real-time and automatically replace them to maintain high availability and application reliability.", - "graph": "appserviceresources | where type =~ 'microsoft.web/sites/config' | extend compliant = (properties.HealthCheckPath != '') | distinct id,compliant", - "guid": "1275e4a9-7b6a-43c3-a9cd-5ee18d8995ad", - "link": "https://learn.microsoft.com/azure/app-service/monitor-instances-health-check", - "service": "App Services", + "guid": "c5a5b252-1e44-4a59-a9d2-399c4d7b68d0", + "link": "https://learn.microsoft.com/azure/aks/spot-node-pool", + "service": "AKS", "services": [ - "AppSvc", - "WAF", - "Monitor" + "WAF" ], - "severity": "Medium", - "text": "Implement health checks to monitor and detect issues with App Service instances. Health checks enable automatic instance replacement on failure.", - "waf": "Reliability" + "severity": "Low", + "text": "Consider spot node pools for non time-sensitive workloads", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Follow best practices for configuring backups and restores in Azure App Service and ASE to guarantee data availability and ensure recovery during disaster scenarios.", - "guid": "35a91c5d-4ad6-4d9b-8e0f-c47db9e6d1e7", - "link": "https://learn.microsoft.com/azure/app-service/manage-backup", - "service": "App Services", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.addonProfiles.aciConnectorLinux) and properties.addonProfiles.aciConnectorLinux.enabled==true) | distinct id,compliant", + "guid": "c755562f-2b4e-4456-9b4d-874a748b662e", + "link": "https://learn.microsoft.com/azure/aks/concepts-scale", + "service": "AKS", "services": [ - "AppSvc", - "WAF", - "Backup" + "AKS", + "WAF" ], - "severity": "High", - "text": "Refer to backup and restore best practices for Azure App Service and App Service Environments (ASE) to ensure data availability and recovery.", - "waf": "Reliability" + "severity": "Low", + "text": "Consider AKS virtual node for quick bursting", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Ensure high availability by incorporating scaling, fault tolerance, monitoring, and zone redundancy into your App Service architecture. Leverage health checks and availability zones to maintain uptime.", - "guid": "e68cd0ec-afc6-4bd8-a27f-7860ad9a0db2", - "link": "https://learn.microsoft.com/azure/architecture/framework/services/compute/azure-app-service/reliability", - "service": "App Services", + "guid": "6f8389a7-f82c-4b8e-a8c0-aa63a25a4956", + "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-overview", + "service": "AKS", "services": [ - "AppSvc", - "WAF", - "Monitor" + "Monitor", + "WAF" ], "severity": "High", - "text": "Implement Azure App Service reliability best practices, including auto-scaling, fault tolerance, health checks, and zone redundancy.", - "waf": "Reliability" + "text": "Monitor your cluster metrics with Container Insights (or other tools like Prometheus)", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Prepare for disaster recovery by implementing region failover strategies. Utilize active-active and active-passive configurations, automated failover, and Infrastructure as Code (IaC) for seamless failover during outages.", - "guid": "bd2a865c-0835-4418-bb58-4df91a5a9b3f", - "link": "https://learn.microsoft.com/azure/app-service/manage-disaster-recovery#recover-app-content-only", - "service": "App Services", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.addonProfiles.omsagent) and properties.addonProfiles.omsagent.enabled==true) | distinct id,compliant", + "guid": "eaa8dc4a-2436-47b3-9697-15b1752beee0", + "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-overview", + "service": "AKS", "services": [ - "AppSvc", - "ASR", "WAF" ], - "severity": "Low", - "text": "Familiarize with App Service region failover, including active-active and active-passive configurations, automated failover, and IaC deployment.", - "waf": "Reliability" + "severity": "High", + "text": "Store and analyze your cluster logs with Container Insights (or other tools like Telegraf/ElasticSearch)", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Azure App Service offers built-in reliability features, including scaling, fault tolerance, and service-level agreements (SLAs). Leverage these features to maintain consistent performance during outages.", - "guid": "f3d2f1e4-e6d4-4b7a-a5a5-e2a9b2c6f293", - "link": "https://learn.microsoft.com/azure/reliability/reliability-app-service", - "service": "App Services", + "guid": "4621dd68-c5a5-4be2-bdb1-1726769ef669", + "link": "https://learn.microsoft.com/azure/azure-monitor/containers/container-insights-analyze", + "service": "AKS", "services": [ - "AppSvc", + "Monitor", "WAF" ], - "severity": "High", - "text": "Familiarize with reliability support in Azure App Service, including scaling options, SLAs, and automated recovery mechanisms.", - "waf": "Reliability" + "severity": "Medium", + "text": "Monitor CPU and memory utilization of the nodes", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Enabling 'Always On' for Function Apps ensures that the app does not go idle, maintaining its availability and responsiveness at all times.", - "guid": "c7b5f3d1-0569-4fd2-9f32-c0b64e9c0c5e", - "link": "https://learn.microsoft.com/azure/azure-functions/dedicated-plan#always-on", - "service": "App Services", + "guid": "1a4835ac-9422-423e-ae80-b123081a5417", + "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", + "service": "AKS", "services": [ - "AppSvc", + "Monitor", "WAF" ], "severity": "Medium", - "text": "Ensure 'Always On' is enabled for Function Apps running on App Service plans to prevent idling and ensure continuous availability.", - "waf": "Reliability" + "text": "If using Azure CNI, monitor % of pod IPs consumed per node", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Health checks monitor the health of App Service instances, enabling automatic replacement of unhealthy instances to maintain high availability.", - "guid": "a3b4d5f6-758c-4f9d-9e1a-d7c6b7e8f9ab", - "link": "https://learn.microsoft.com/azure/app-service/monitor-instances-health-check", - "service": "App Services", + "description": "I/O in the OS disk is a critical resource. If the OS in the nodes gets throttled on I/O, this could lead to unpredictable behavior, typically ending up in node being declared NotReady", + "guid": "415833ea-3ad3-4c2d-b733-165c3acbe04b", + "link": "https://learn.microsoft.com/azure/virtual-machines/premium-storage-performance", + "service": "AKS", "services": [ - "AppSvc", + "Monitor", + "EventHubs", + "Storage", "WAF", - "Monitor" + "ServiceBus" ], "severity": "Medium", - "text": "Monitor App Service instances using Health checks to detect unhealthy instances and automatically replace them.", - "waf": "Reliability" + "text": "Monitor OS disk queue depth in nodes", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c7d3e5f9-a19c-4833-8ca6-1dcb0128e129", - "link": "https://learn.microsoft.com/azure/azure-monitor/app/availability-overview", - "service": "App Services", + "guid": "be209d39-fda4-4777-a424-d116785c2fa5", + "link": "https://learn.microsoft.com/azure/aks/load-balancer-standard", + "service": "AKS", "services": [ - "WAF", - "Monitor" + "NVA", + "LoadBalancer", + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Monitor availability and responsiveness of web app or website using Application Insights availability tests, ensuring proactive detection of performance issues and downtime.", - "waf": "Reliability" + "text": "If not using egress filtering with AzFW/NVA, monitor standard ALB allocated SNAT ports", + "waf": "Operations" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "b4e3f2d5-a5c6-4d7e-8b2f-c5d9e7a8f0ea", - "link": "https://learn.microsoft.com/azure/azure-monitor/app/availability-standard-tests", - "service": "App Services", + "guid": "74c2ee76-569b-4a79-a57e-dedf91b022c9", + "link": "https://learn.microsoft.com/azure/aks/aks-resource-health", + "service": "AKS", "services": [ - "WAF", - "Monitor" + "AKS", + "WAF" + ], + "severity": "Medium", + "text": "Subscribe to resource health notifications for your AKS cluster", + "waf": "Operations" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "guid": "b54eb2eb-03dd-4aa3-9927-18e2edb11726", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-scheduler", + "service": "AKS", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Configure requests and limits in your pod specs", + "waf": "Operations" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "guid": "769ef669-1a48-435a-a942-223ece80b123", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-scheduler", + "service": "AKS", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Enforce resource quotas for namespaces", + "waf": "Operations" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "guid": "081a5417-4158-433e-a3ad-3c2de733165c", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits", + "service": "AKS", + "services": [ + "Subscriptions", + "WAF" + ], + "severity": "High", + "text": "Ensure your subscription has enough quota to scale out your nodepools", + "waf": "Operations" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "guid": "f4fd0602-7ab5-46f1-b66a-e9dea9654a65", + "link": "https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/", + "service": "AKS", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Configure Liveness and Readiness probes for all deployments", + "waf": "Operations" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.autoScalerProfile)) | distinct id,compliant", + "guid": "90ce65de-8e13-4f9c-abd4-69266abca264", + "link": "https://learn.microsoft.com/azure/aks/concepts-scale", + "service": "AKS", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Use the Cluster Autoscaler", + "waf": "Performance" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "graph": "where type=='microsoft.containerservice/managedclusters' | extend compliant = (isnotnull(properties.austoscalerProfile)) | distinct id,compliant", + "guid": "831c2872-c693-4b39-a887-a561bada49bc", + "link": "https://learn.microsoft.com/azure/aks/custom-node-configuration", + "service": "AKS", + "services": [ + "AKS", + "WAF" ], "severity": "Low", - "text": "Use Application Insights Standard test to monitor availability and responsiveness of web app or website", - "waf": "Reliability" + "text": "Customize node configuration for AKS node pools", + "waf": "Performance" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Azure Key Vault ensures secrets are encrypted, securely stored, and accessed only by authorized applications. It supports audit logging, and secret versioning, and reduces the risk of accidental exposure of sensitive information.", - "guid": "834ac932-223e-4ce8-8b12-3071a5416415", - "link": "https://learn.microsoft.com/azure/app-service/app-service-key-vault-references", - "service": "App Services", + "guid": "faa19bfe-9d55-4d04-a3c4-919ca1b2d121", + "link": "https://learn.microsoft.com/azure/aks/concepts-scale", + "service": "AKS", "services": [ - "AppSvc", - "WAF", - "AKV" + "WAF" + ], + "severity": "Medium", + "text": "Use the Horizontal Pod Autoscaler when required", + "waf": "Performance" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "description": "Larger nodes will bring higher performance and features such as ephemeral disks and accelerated networking, but they will increase the blast radius and decrease the scaling granularity", + "guid": "5ae124ba-34df-4585-bcdc-e9bd3bb0cdb3", + "link": "https://blog.cloudtrooper.net/2020/10/23/which-vm-size-should-i-choose-as-aks-node/", + "service": "AKS", + "services": [ + "WAF" ], "severity": "High", - "text": "Use Azure Key Vault to store any secrets the application needs. Key Vault provides a secure, managed, and audited environment for storing secrets, and integrates seamlessly with App Service via App Service Key Vault References for enhanced security.", - "waf": "Security" + "text": "Consider an appropriate node size, not too large or too small", + "waf": "Performance" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Managed Identity eliminates the need for hard-coded credentials by allowing App Service to authenticate to Azure Key Vault securely. This reduces the risk of credential exposure and simplifies secret management for enhanced security.", - "guid": "833ea3ad-2c2d-4e73-8165-c3acbef4abe1", - "link": "https://learn.microsoft.com/azure/app-service/app-service-key-vault-references", - "service": "App Services", + "guid": "38800e6a-ae01-40a2-9fbc-ae5a06e5462d", + "link": "https://learn.microsoft.com/azure/aks/quotas-skus-regions#service-quotas-and-limits", + "service": "AKS", "services": [ - "AppSvc", - "WAF", - "AKV", - "Entra" + "AKS", + "WAF" + ], + "severity": "Low", + "text": "If more than 5000 nodes are required for scalability then consider using an additional AKS cluster", + "waf": "Performance" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "guid": "9583c0f6-6083-43f6-aa6b-df7102c901bb", + "link": "https://learn.microsoft.com/azure/event-grid/event-schema-aks", + "service": "AKS", + "services": [ + "AKS", + "WAF" + ], + "severity": "Low", + "text": "Consider subscribing to EventGrid Events for AKS automation", + "waf": "Performance" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "guid": "c5016d8c-c6c9-4165-89ae-673ef0fff19d", + "link": "https://learn.microsoft.com/azure/aks/manage-abort-operations", + "service": "AKS", + "services": [ + "AKS", + "WAF" + ], + "severity": "Low", + "text": "For long running operation on an AKS cluster consider event termination", + "waf": "Performance" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "guid": "c4e37133-f186-4ce1-aed9-9f1b32f6e021", + "link": "https://learn.microsoft.com/azure/aks/use-azure-dedicated-hosts", + "service": "AKS", + "services": [ + "AKS", + "WAF" + ], + "severity": "Low", + "text": "If required consider using Azure Dedicated Hosts for AKS nodes", + "waf": "Performance" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "graph": "where type=='microsoft.containerservice/managedclusters' | project id,resourceGroup,name,pools=properties.agentPoolProfiles | mvexpand pools | extend compliant = (pools.osDiskType=='Ephemeral') | project id,name=strcat(name,'-',pools.name), resourceGroup, compliant", + "guid": "24367b33-6971-45b1-952b-eee0b9b588de", + "link": "https://learn.microsoft.com/azure/aks/cluster-configuration", + "service": "AKS", + "services": [ + "WAF" ], "severity": "High", - "text": "Use Managed Identity to securely connect to Azure Key Vault for accessing secrets, through App Service Key Vault References.", - "waf": "Security" + "text": "Use ephemeral OS disks", + "waf": "Performance" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Storing TLS certificates in Azure Key Vault enhances security by providing centralized, secure management and automated renewal of certificates. This reduces the risk of manual handling errors and certificate expiration.", - "guid": "f8d39fda-4776-4831-9c11-5775c2ea55b4", - "link": "https://learn.microsoft.com/azure/app-service/configure-ssl-certificate", - "service": "App Services", + "guid": "f0ce315f-1120-4166-8206-94f2cf3a4d07", + "link": "https://learn.microsoft.com/azure/virtual-machines/disks-types", + "service": "AKS", "services": [ - "AppSvc", - "WAF", - "AKV", - "Entra" + "AKS", + "WAF" ], "severity": "High", - "text": "Use Azure Key Vault to securely store and manage TLS certificates for App Service.", - "waf": "Security" + "text": "For non-ephemeral disks, use high IOPS and larger OS disks for the nodes when running many pods/node since it requires high performance for running multiple pods and will generate huge logs with default AKS log rotation thresholds", + "waf": "Performance" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "To minimize exposure and improve security, isolate systems processing sensitive data. Leverage separate App Service Plans or App Service Environments for isolation, and use different subscriptions or management groups to enforce stricter boundaries and governance.", - "guid": "6ad48408-ee72-4734-a475-ba18fdbf590c", - "link": "https://learn.microsoft.com/azure/app-service/overview-hosting-plans", - "service": "App Services", + "guid": "39c486ce-d5af-4062-89d5-18bb5fd795db", + "link": "https://learn.microsoft.com/azure/aks/use-ultra-disks", + "service": "AKS", "services": [ - "AppSvc", - "Subscriptions", + "Storage", + "AKS", + "WAF" + ], + "severity": "Low", + "text": "For hyper performance storage option use Ultra Disks on AKS", + "waf": "Performance" + }, + { + "arm-service": "microsoft.containerservice/managedClusters", + "checklist": "WAF checklist", + "guid": "9f7547c1-747d-4c56-868a-714435bd19dd", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-multi-region", + "service": "AKS", + "services": [ + "Storage", + "SQL", "WAF" ], "severity": "Medium", - "text": "Isolate systems that process sensitive information using separate App Service Plans, App Service Environments (ASE), and consider different subscriptions or management groups for enhanced security.", - "waf": "Security" + "text": "Avoid keeping state in the cluster, and store data outside (AzStorage, AzSQL, Cosmos, etc)", + "waf": "Performance" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Local disks on App Service are not encrypted and sensitive data should not be stored on those. (For example: D:\\\\Local and %TMP%).", - "guid": "e65de8e0-3f9b-4cbd-9682-66abca264f9a", - "link": "https://learn.microsoft.com/azure/app-service/operating-system-functionality#file-access", - "service": "App Services", + "guid": "24429eb7-2281-4376-85cc-57b4a4b18142", + "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-storage", + "service": "AKS", "services": [ - "AppSvc", - "TrafficManager", + "Storage", "WAF" ], "severity": "Medium", - "text": "Do not store sensitive data on local disk", - "waf": "Security" + "text": "If using AzFiles Standard, consider AzFiles Premium and/or ANF for performance reasons", + "waf": "Performance" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "description": "Use Microsoft Entra ID or B2C for secure user authentication and Single Sign-On (SSO) across applications. Integrate using the built-in App Service Authentication/Authorization feature for streamlined security and compliance with modern authentication protocols like OpenID Connect.", - "guid": "919ca0b2-c121-459e-814b-933df574eccc", - "link": "https://learn.microsoft.com/azure/app-service/overview-authentication-authorization", - "service": "App Services", + "guid": "83958a8c-2689-4b32-ab57-cfc64546135a", + "link": "https://learn.microsoft.com/azure/aks/availability-zones#azure-disk-availability-zone-support", + "service": "AKS", "services": [ - "AppSvc", - "WAF", - "ACR", - "Entra" + "Storage", + "WAF" ], "severity": "Medium", - "text": "Use Microsoft Entra ID or B2C for secure authentication and Single Sign-On (SSO).", - "waf": "Security" + "text": "If using Azure Disks and AZs, consider having nodepools within a zone for LRS disk with VolumeBindingMode:WaitForFirstConsumer for provisioning storage in right zone or use ZRS disk for nodepools spanning multiple zones", + "waf": "Performance" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Ensure all code deployments to App Service originate from a controlled, secured environment, such as a well-managed DevOps pipeline. This practice mitigates the risk of deploying unauthorized or malicious code by enforcing version control, code verification, and secure hosting.", - "guid": "3f9bcbd4-6826-46ab-aa26-4f9a19aed9c5", - "link": "https://learn.microsoft.com/azure/app-service/deploy-best-practices", - "service": "App Services", + "guid": "a85b86ad-884f-48e3-9273-4b875ba18f10", + "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/system-message#define-additional-safety-and-behavioral-guardrails", + "service": "Azure OpenAI", "services": [ - "AppSvc", "WAF" ], "severity": "High", - "text": "Deploy code to App Service from a trusted and secure environment.", - "waf": "Security" + "text": "Follow Metaprompting guardrails for resonsible AI", + "waf": "Operational Excellence" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Disable basic authentication for FTP/FTPS and WebDeploy/SCM to enhance security by enforcing Microsoft Entra ID secured endpoints for deployment. This ensures that only authenticated users using Microsoft Entra ID credentials can access deployment services, including the SCM site.", - "guid": "5d04c2c3-919c-4a0b-8c12-159e114b933d", - "link": "https://learn.microsoft.com/azure/app-service/deploy-configure-credentials#disable-basic-authentication", - "service": "App Services", + "guid": "d4391898-cd28-48be-b6b1-7cb8245451e1", + "link": "https://github.com/Azure-Samples/AI-Gateway", + "service": "Azure OpenAI", "services": [ - "WAF", - "Entra" + "APIM", + "Entra", + "WAF" ], "severity": "High", - "text": "Disable basic authentication for FTP/FTPS and WebDeploy/SCM.", - "waf": "Security" + "text": "Consider Gateway patterns with APIM or solutions like AI central for better rate limiting, load balancing, authentication and logging", + "waf": "Operational Excellence" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Wherever possible, use Managed Identity to securely connect to Microsoft Entra ID-secured resources without storing credentials. If this is not feasible, store secrets in Azure Key Vault and access them using Managed Identity to maintain security and reduce the risk of credential exposure.", - "guid": "f574eccc-d9bd-43ba-bcda-3b54eb2eb03d", - "link": "https://learn.microsoft.com/azure/app-service/overview-managed-identity?tabs=portal%2Chttp", - "service": "App Services", + "guid": "aed3453a-ec72-4392-97a1-52d6cc5e4029", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/azure-openai-insights-monitoring-ai-with-confidence/ba-p/4026850", + "service": "Azure OpenAI", + "services": [ + "Monitor", + "WAF" + ], + "severity": "High", + "text": "Enable monitoring for your AOAI instances", + "waf": "Operational Excellence" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "graph": "resources | where type == 'microsoft.insights/metricalerts' | extend compliant = (properties.targetResourceType =~ 'Microsoft.CognitiveServices/accounts') | project id, compliant", + "guid": "697cb391-ed16-4b2d-886f-0a0241addde6", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitoring#set-up-alerts", + "service": "Azure OpenAI", "services": [ + "Subscriptions", "AKV", - "WAF", - "Entra" + "Monitor", + "WAF" ], "severity": "High", - "text": "Use Managed Identity to connect to Microsoft Entra ID secured resources.", - "waf": "Security" + "text": "Create alerts to notify teams of events such as an entry in the activity log created by an action performed on the resource, such as regenerating its subscription keys or a metric threshold such as the number of errors exceeding 10 in an hour", + "waf": "Operational Excellence" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "When using images stored in Azure Container Registry, pull these images using a Managed Identity to avoid storing credentials. This ensures secure access to container images and reduces the risk of credential exposure.", - "guid": "d9a25827-18d2-4ddb-8072-5769ee6691a4", - "link": "https://learn.microsoft.com/azure/app-service/configure-custom-container#use-managed-identity-to-pull-image-from-azure-container-registry", - "service": "App Services", + "guid": "8a477cde-b486-41bc-9bc1-0ae66e25d4d5", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitoring", + "service": "Azure OpenAI", "services": [ - "WAF", - "ACR", - "Entra" + "Monitor", + "WAF" ], "severity": "High", - "text": "Pull container images from Azure Container Registry using a Managed Identity.", - "waf": "Security" + "text": "Monitor token usage to prevent service disruptions due to capacity", + "waf": "Operational Excellence" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Configure diagnostic settings to send telemetry and security logs (including HTTP, platform, and audit logs) to Log Analytics. Centralized logging enhances monitoring, threat detection, and compliance reporting.", - "guid": "47768314-c115-4775-a2ea-55b46ad48408", - "link": "https://learn.microsoft.com/azure/app-service/troubleshoot-diagnostic-logs", - "service": "App Services", + "guid": "a3aec2c4-e243-46b0-936c-b45e17960eee", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitoring", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "Entra", - "WAF", - "Monitor" + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Send App Service runtime and security logs to Log Analytics for centralized monitoring and alerting.", + "text": "observe metrics like processed inference tokens, generated completion tokens monitor for rate limit", + "waf": "Operational Excellence" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "fbdf4cc2-eec4-4d76-8c31-d25ffbb46a39", + "link": "https://techcommunity.microsoft.com/t5/apps-on-azure-blog/build-an-enterprise-ready-azure-openai-solution-with-azure-api/ba-p/3907562", + "service": "Azure OpenAI", + "services": [ + "APIM", + "WAF" + ], + "severity": "Low", + "text": "Enable and configure Diagnostics for the Azure OpenAI Service. If not sufficient, consider using a gateway such as Azure API Managements in front of Azure OpenAI to log both incoming prompts and outgoing responses, where permitted", + "waf": "Operational Excellence" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "3af30ed3-2947-498b-8178-a2c5a46ceb54", + "link": "https://github.com/Azure-Samples/openai-enterprise-iac", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Use Infrastructure as code to deploy the Azure OpenAI Service, model deployments, and all related resources", + "waf": "Operational Excellence" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "4350d092-d234-4292-a752-8537a551c5bf", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/managed-identity", + "service": "Azure OpenAI", + "services": [ + "Entra", + "WAF" + ], + "severity": "High", + "text": "Use Microsoft Entra Authentication with Managed Identity instead of API Key", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Set up a diagnostic setting to send the activity log to Log Analytics as the central destination for logging and monitoring. This allows you to monitor control plane activity on the App Service resource itself.", - "guid": "ee72734b-475b-4a18-bdbf-590ce65de8e0", - "link": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log", - "service": "App Services", + "guid": "4e4f1854-287d-45cd-a126-cc031af5b1fc", + "link": "https://learn.microsoft.com/azure/machine-learning/prompt-flow/how-to-bulk-test-evaluate-flow?view=azureml-api-2", + "service": "Azure OpenAI", "services": [ - "AppSvc", + "WAF" + ], + "severity": "High", + "text": "Evaluate the performance/accuracy of the system with a known golden dataset which has the inputs and the correct answers. Leverage capabilities in PromptFlow for Evaluation.", + "waf": "Operational Excellence" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "68889535-e327-4897-b31b-67d67be5962a", + "link": "https://learn.microsoft.com/azure/architecture/ai-ml/architecture/baseline-openai-e2e-chat#azure-openai---performance-efficiency", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Evaluate usage of Provisioned throughput model ", + "waf": "Performance" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "cd288bed-6b17-4cb8-8454-51e1aed3453a", + "link": "https://learn.microsoft.com/azure/ai-services/content-safety/overview", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Review and implement Azure AI content safety", + "waf": "Operational Excellence" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "1193846d-697c-4b39-8ed1-6b2d186f0a02", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#system-level-throughput", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Define and evaluate the throughput of the system based on tokens & response per minute and align with requirements", + "waf": "Performance" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "41addde6-8a47-47cd-bb48-61bc3bc10ae6", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#improve-performance", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Improve latency of the system by limiting token sizes, streaming options for applications like chatbots or conversational interfaces. Streaming can enhance the perceived performance of Azure OpenAI applications by delivering responses to users in an incremental manner", + "waf": "Performance" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "6e25d4d5-a3ae-4c2c-9e24-36b0336cb45e", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#batching", + "service": "Azure OpenAI", + "services": [ + "Storage", + "ServiceBus", + "WAF" + ], + "severity": "Medium", + "text": "Estimate elasticity demands to determine synchronous and batch request segregation based on priority. For high priority, use synchronous approach and for low priority, asynchronous batch processing with queue is preferred", + "waf": "Performance" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "5bda4332-4f24-4811-9331-82ba51752694", + "link": "https://github.com/Azure/azure-openai-benchmark/", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Benchmark token consumption requirements based on estimated demands from consumers. Consider using the Azure OpenAI benchmarking tool to help you validate the throughput if you are using Provisioned Throughput Unit deployments", + "waf": "Performance" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "4008ae7d-7e47-4432-96d8-bdcf55bce619", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/optimizing-azure-openai-a-guide-to-limits-quotas-and-best/ba-p/4076268", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "If you are using Provisioned Throughput Units (PTUs), consider deploying a token-per-minute (TPM) deployment for overflow requests. Use a gateway to route requests to the TPM deployment when the PTU limits are reached.", + "waf": "Performance" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "e8a13f98-8794-424d-9267-86d60b96c97b", + "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/models", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Choose the right model for the right task. Pick models with right tradeoff between speed, quality of response and output complexity", + "waf": "Performance" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "e9951904-8384-45c9-a6cb-2912156a1147", + "link": "https://github.com/Azure/azure-openai-benchmark/", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Have a baseline for performance without fine-tuning for knowing whether or not fine-tuning has improved model performance", + "waf": "Performance" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "5e39f541-accc-4d97-a376-bcdb3750ab2a", + "link": "https://learn.microsoft.com/azure/architecture/ai-ml/architecture/baseline-openai-e2e-chat#azure-openai---reliability", + "service": "Azure OpenAI", + "services": [ + "ACR", + "WAF" + ], + "severity": "Low", + "text": "Deploy multiple OAI instances across regions", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "b039da6d-55d7-4c89-8adb-107d5325af62", + "link": "https://learn.microsoft.com/azure/architecture/ai-ml/architecture/baseline-openai-e2e-chat#azure-openai---reliability", + "service": "Azure OpenAI", + "services": [ + "APIM", "Entra", - "WAF", - "Monitor" + "WAF" + ], + "severity": "High", + "text": "Implement retry & healthchecks with Gateway pattern like APIM", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "5ca44e46-85e2-4223-ace8-bb12308ca5f1", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/quota?tabs=rest#introduction-to-quota", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Ensure having adequate quotas of TPM & RPM for the workload", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "ec723923-7a15-42d6-ac5e-402925387e5c", + "link": "https://www.microsoft.com/research/project/guidelines-for-human-ai-interaction/", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Review the considerations in HAI toolkit guidance and apply those interaction practices for the slution", + "waf": "Operational Excellence" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "7f154e3a-a369-4282-ae7e-316183687a04", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/business-continuity-disaster-recovery", + "service": "Azure OpenAI", + "services": [ + "ACR", + "WAF" + ], + "severity": "Medium", + "text": "Deploy separate fine tuned models across regions if finetuning is employed", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "77a1f893-5bda-4433-84f2-4811633182ba", + "link": "https://learn.microsoft.com/azure/backup/backup-overview", + "service": "Azure OpenAI", + "services": [ + "ASR", + "Backup", + "WAF" + ], + "severity": "Medium", + "text": "Regularly backup and replicate critical data to ensure data availability and recoverability in case of data loss or system failures. Leverage Azure's backup and disaster recovery services to protect your data.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "graph": "resources | where type == 'microsoft.search/searchservices' | extend compliant = (sku.name != 'free' and properties.replicaCount >= 3) | project id, compliant", + "guid": "95b96ad8-844c-4e3b-8b38-b876ba2cf204", + "link": "https://learn.microsoft.com/azure/search/search-reliability", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Azure AI search service tiers should be choosen to have a SLA ", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "99013a5d-3ce4-474d-acbd-8682a6abca2a", + "link": "https://learn.microsoft.com/purview/purview", + "service": "Azure OpenAI", + "services": [ + "WAF" ], - "severity": "Medium", - "text": "Send App Service activity logs to Log Analytics", + "severity": "Low", + "text": "Classify data and sensitivity, labeling with Microsoft Purview before generating the embeddings and make sure to treat the embeddings generated with same sensitivity and classification", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Use regional VNet integration, Network Security Groups (NSGs), and User-Defined Routes (UDRs) to control outbound network access. Route traffic through a Network Virtual Appliance (NVA), such as Azure Firewall, and monitor firewall logs to ensure traffic is properly controlled and secure.", - "guid": "c12159e1-14b9-433d-b574-ecccd9bd3baf", - "link": "https://learn.microsoft.com/azure/app-service/overview-vnet-integration", - "service": "App Services", + "guid": "4fda1dbf-3dd9-45d4-ac7c-891dca1f6d56", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/use-your-data-securely", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "NVA", - "Firewall", - "VNet", - "Monitor", "WAF" ], - "severity": "Medium", - "text": "Control outbound network access for App Service using VNet integration, NSGs, UDRs, and firewalls.", + "severity": "High", + "text": "Encrypt data used for RAG with SSE/Disk encryption with optional BYOK", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Provide a stable outbound IP by using VNet integration with a NAT Gateway or Network Virtual Appliance (NVA) like Azure Firewall. This enables the receiving party to allow-list based on IP, if necessary. For communications with Azure services, use mechanisms like Service Endpoints or private endpoints to avoid relying on static IPs, ensuring secure and efficient connectivity.", - "guid": "cda3b54e-b2eb-403d-b9a2-582718d2ddb1", - "link": "https://learn.microsoft.com/azure/app-service/networking/nat-gateway-integration", - "service": "App Services", + "guid": "59ae558b-937d-4498-9e11-12dbd7ba012f", + "link": "https://learn.microsoft.com/azure/search/search-security-overview", + "service": "Azure OpenAI", "services": [ - "NVA", - "Storage", - "Firewall", - "VNet", - "PrivateLink", + "ACR", "WAF" ], - "severity": "Low", - "text": "Ensure a stable IP for outbound communications by using VNet NAT Gateway or Azure Firewall.", + "severity": "High", + "text": "Ensure TLS is enforced for data in transit across data sources, AI search used for Retrieval-Augmented Generation (RAG) and LLM communication", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Control inbound network access by configuring App Service Access Restrictions, Service Endpoints, or Private Endpoints. Ensure appropriate restrictions are set for both the web app and the SCM (deployment) site to limit unauthorized access and enhance security.", - "guid": "0725769e-e669-41a4-a34a-c932223ece80", - "link": "https://learn.microsoft.com/azure/app-service/networking-features#access-restrictions", - "service": "App Services", + "guid": "7b94ef6e-047d-42ea-8992-b1cd6e2054b2", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/role-based-access-control", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "PrivateLink", + "RBAC", "WAF" ], "severity": "High", - "text": "Control inbound network access using Access Restrictions, Service Endpoints, or Private Endpoints.", + "text": "Use RBAC to manage access to Azure OpenAI services. Assign appropriate permissions to users and restrict access based on their roles and responsibilities", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Protect App Service from malicious inbound traffic by deploying a Web Application Firewall (WAF) using Azure Application Gateway or Azure Front Door. Ensure WAF logs are monitored regularly to detect and respond to security threats.", - "guid": "b123071a-5416-4415-a33e-a3ad2c2de732", - "link": "https://learn.microsoft.com/azure/app-service/networking/app-gateway-with-service-endpoints", - "service": "App Services", + "guid": "9769e4a6-91e8-4838-ac93-6667e13c0056", + "link": "https://learn.microsoft.com/azure/security/fundamentals/data-encryption-best-practices", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "AppGW", - "Monitor", - "WAF", - "FrontDoor" + "WAF" ], - "severity": "High", - "text": "Use a Web Application Firewall (WAF) in front of App Service.", + "severity": "Medium", + "text": "Implement data encryption, masking or redaction techniques to hide sensitive data or replace it with obfuscated values in non-production environments or when sharing data for testing or troubleshooting purposes", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "To prevent the Web Application Firewall (WAF) from being bypassed, lock down access to App Service by using Access Restrictions, Service Endpoints, and Private Endpoints. This ensures that all traffic is routed through the WAF, providing a secure front layer of protection.", - "guid": "165c3acb-ef4a-4be1-b8d3-9fda47768314", - "link": "https://learn.microsoft.com/azure/app-service/networking-features#access-restrictions", - "service": "App Services", + "guid": "74b1e945-b459-4837-be7a-d6c6d3b375a5", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/ai-onboarding", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "PrivateLink", + "Sentinel", + "Monitor", + "Defender", "WAF" ], "severity": "High", - "text": "Ensure the WAF cannot be bypassed by securing access to App Service.", + "text": "Utilize Azure Defender to detect and respond to security threats and set up monitoring and alerting mechanisms to identify suspicious activities or breaches. Leverage Azure Sentinel for advanced threat detection and response", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Ensure that the minimum TLS policy is set to 1.2 or higher, with a preference for TLS 1.3, to enhance security through stronger encryption protocols. TLS 1.3 provides additional security improvements and faster handshake times, reducing vulnerabilities associated with older versions.", - "graph": "appserviceresources | where type =~ 'microsoft.web/sites/config' | extend compliant = (properties.MinTlsVersion>=1.2) | distinct id,compliant", - "guid": "c115775c-2ea5-45b4-9ad4-8408ee72734b", - "link": "https://learn.microsoft.com/azure/app-service/configure-ssl-bindings#enforce-tls-versions", - "service": "App Services", + "guid": "c7acbe48-abe5-44cd-99f2-e87768468c55", + "link": "https://techcommunity.microsoft.com/t5/azure-storage-blog/managing-long-term-log-retention-or-any-business-data/ba-p/2494791", + "service": "Azure OpenAI", "services": [ - "AppSvc", "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Set minimum TLS policy to 1.2 or higher, preferably 1.3, in App Service configuration.", + "text": "Establish data retention and disposal policies to adhere to compliance regulations. Implement secure deletion methods for data that is no longer required and maintain an audit trail of data retention and disposal activities", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Configure App Service to enforce HTTPS-only, automatically redirecting all HTTP traffic to HTTPS. Additionally, implement HTTP Strict Transport Security (HSTS) in your code or via a Web Application Firewall (WAF) to ensure browsers only access the site over HTTPS, enhancing security by preventing downgrade attacks.", - "graph": "where (type=='microsoft.web/sites' and (kind == 'app' or kind == 'app,linux' )) | extend compliant = (properties.httpsOnly==true) | distinct id,compliant", - "guid": "475ba18f-dbf5-490c-b65d-e8e03f9bcbd4", - "link": "https://learn.microsoft.com/azure/app-service/configure-ssl-bindings#enforce-https", - "service": "App Services", + "guid": "a9c27d9c-42bb-46bd-8c69-99a246f3389a", + "link": "https://learn.microsoft.com/azure/ai-services/content-safety/concepts/jailbreak-detection", + "service": "Azure OpenAI", "services": [ - "AppSvc", "WAF" ], "severity": "High", - "text": "Use HTTPS only and consider enabling HTTP Strict Transport Security (HSTS).", - "waf": "Security" + "text": "Implement Prompt shields and groundedness detection using Content Safety ", + "waf": "Operational Excellence" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Do not use wildcards (*) in your CORS configuration, as this permits unrestricted access from any origin, compromising security. Instead, explicitly specify trusted origins that are allowed to access the service, ensuring controlled access.", - "guid": "68266abc-a264-4f9a-89ae-d9c55d04c2c3", - "link": "https://learn.microsoft.com/azure/app-service/app-service-web-tutorial-rest-api", - "service": "App Services", + "guid": "a775c6ee-95b9-46ad-a844-ce3b2b38b876", + "link": "https://learn.microsoft.com/azure/compliance/", + "service": "Azure OpenAI", "services": [ - "Storage", "WAF" ], "severity": "High", - "text": "Avoid using wildcards for CORS; specify allowed origins explicitly.", + "text": "Ensure compliance with relevant data protection regulations, such as GDPR or HIPAA, by implementing privacy controls and obtaining necessary consents or permissions for data processing activities.", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Remote debugging should not be enabled in production as it opens additional ports, increasing the attack surface. Although App Service automatically turns off remote debugging after 48 hours, it is recommended to disable it manually in production to maintain a secure environment.", - "graph": "appserviceresources | where type =~ 'microsoft.web/sites/config' | extend compliant = (properties.RemoteDebuggingEnabled == false) | distinct id,compliant", - "guid": "d9bd3baf-cda3-4b54-bb2e-b03dd9a25827", - "link": "https://learn.microsoft.com/azure/app-service/configure-common#configure-general-settings", - "service": "App Services", + "guid": "ba2cf204-9901-43a5-b3ce-474dccbd8682", + "service": "Azure OpenAI", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Educate your employees about data security best practices, the importance of handling data securely, and potential risks associated with data breaches. Encourage them to follow data security protocols diligently.", + "waf": "Security" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "eae01e6e-842e-452f-9721-d928c1b1cd52", + "service": "Azure OpenAI", "services": [ - "AppSvc", "WAF" ], "severity": "High", - "text": "Turn off remote debugging in production environments.", + "text": "Keep production data separate from development and testing data. Only use real sensitive data in production and utilize anonymized or synthetic data in development and test environments.", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Enable Defender for App Service. This (amongst other threats) detects communications to known malicious IP addresses. Review the recommendations from Defender for App Service as part of your operations.", - "guid": "18d2ddb1-0725-4769-be66-91a4834ac932", - "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-app-service-introduction", - "service": "App Services", + "guid": "1e54a29a-9de3-499c-bd7b-28dc93555620", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "WAF", - "Defender" + "WAF" ], "severity": "Medium", - "text": "Enable Defender for Cloud - Defender for App Service", + "text": "If you have varying levels of data sensitivity, consider creating separate indexes for each level. For instance, you could have one index for general data and another for sensitive data, each governed by different access protocols", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Azure provides DDoS Basic protection on its network, which can be improved with intelligent DDoS Standard capabilities which learns about normal traffic patterns and can detect unusual behavior. DDoS Standard applies to a Virtual Network so it must be configured for the network resource in front of the app, such as Application Gateway or an NVA.", - "guid": "223ece80-b123-4071-a541-6415833ea3ad", - "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", - "service": "App Services", + "guid": "2bfe4564-b0d8-434a-948b-263e6dd60512", + "service": "Azure OpenAI", "services": [ - "AppGW", - "DDoS", - "NVA", - "VNet", - "EventHubs", + "RBAC", + "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Enable DDOS Protection Standard on the WAF VNet", + "text": "Take segregation a step further by placing sensitive datasets in different instances of the service. Each instance can be controlled with its own specific set of RBAC policies", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "When using images stored in Azure Container Registry, ensure they are pulled over a virtual network by using a private endpoint and configuring the app setting 'WEBSITE_PULL_IMAGE_OVER_VNET'. This ensures secure communication between App Service and the registry, preventing exposure to the public internet.", - "guid": "2c2de732-165c-43ac-aef4-abe1f8d39fda", - "link": "https://learn.microsoft.com/azure/app-service/configure-custom-container#use-an-image-from-a-network-protected-registry", - "service": "App Services", + "guid": "a36498f6-dbad-438e-ad53-cc7ce1d7aaab", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "ACR", - "PrivateLink", - "VNet", "WAF" ], - "severity": "Medium", - "text": "Pull container images over a Virtual Network from Azure Container Registry.", + "severity": "High", + "text": "Recognize that embeddings and vectors generated from sensitive information are themselves sensitive. This data should be afforded the same protective measures as the source material", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Perform a penetration test on the web application in accordance with Azure's penetration testing rules of engagement. This helps identify vulnerabilities and security weaknesses that can be addressed before they are exploited.", - "guid": "eb2eb03d-d9a2-4582-918d-2ddb10725769", - "link": "https://learn.microsoft.com/azure/security/fundamentals/pen-testing", - "service": "App Services", + "guid": "3571449a-b805-43d8-af89-dc7b33be2a1a", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/role-based-access-control", + "service": "Azure OpenAI", "services": [ + "RBAC", "WAF" ], - "severity": "Medium", - "text": "Conduct a penetration test on the web application.", + "severity": "High", + "text": "Apply RBAC to th data stores having embeddings and vectors and scope access based on role's access requirements", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Ensure that only trusted code, which has been validated and scanned for vulnerabilities, is deployed to production following DevSecOps practices. This minimizes the risk of introducing security vulnerabilities into the application environment.", - "guid": "19aed9c5-5d04-4c2c-9919-ca0b2c12159e", - "link": "https://learn.microsoft.com/azure/architecture/solution-ideas/articles/devsecops-in-azure", - "service": "App Services", + "graph": "resources | where type =~ 'Microsoft.CognitiveServices/accounts' or type == 'microsoft.search/searchservices' | project id, compliant = (properties.privateEndpointConnections != '[]' and properties.publicNetworkAccess !~ 'enabled')", + "guid": "27f7b9e9-1be1-4f38-aef3-9812bd463cbb", + "link": "https://techcommunity.microsoft.com/t5/azure-architecture-blog/azure-openai-private-endpoints-connecting-across-vnet-s/ba-p/3913325", + "service": "Azure OpenAI", "services": [ + "PrivateLink", "WAF" ], - "severity": "Medium", - "text": "Deploy validated and vulnerability-scanned code.", + "severity": "High", + "text": "Configure private endpoint for AI services to restrict service access within your network", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Ensure that the latest versions of supported platforms, programming languages, protocols, and frameworks are used. Regular updates mitigate the risk of security vulnerabilities and ensure compatibility with security patches.", - "guid": "114b933d-f574-4ecc-ad9b-d3bafcda3b54", - "link": "https://learn.microsoft.com/azure/app-service/overview-patch-os-runtime", - "service": "App Services", + "guid": "ac8ac199-ebb9-41a3-9d90-cae2cc881370", + "service": "Azure OpenAI", "services": [ + "VNet", + "Firewall", "WAF" ], "severity": "High", - "text": "Use up-to-date platforms, languages, protocols and frameworks", + "text": "Enforce strict inbound and outbound traffic control with Azure Firewall and UDRs and limit the external integration points", "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Leverage Auto-Healing in Azure App Service to automatically restart instances or trigger custom actions based on pre-defined failure conditions like memory thresholds, HTTP errors, or specific event logs.", - "guid": "60b3a935-33e5-45c9-87c7-53882e395b46", - "link": "https://learn.microsoft.com/azure/app-service/overview-diagnostics", - "service": "App Services", + "guid": "6f7c0cba-fe51-4464-add4-57e927138b82", + "service": "Azure OpenAI", "services": [ - "AppSvc", "WAF" ], - "severity": "Medium", - "text": "Use Auto-Healing with custom rules to restart App Service instances automatically when failures occur.", - "waf": "Reliability" + "severity": "High", + "text": "Implement network segmentation and access controls to restrict access to the LLM application only to authorized users and systems and prevent lateral movement", + "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Configure Azure Monitor alerts based on Application Insights metrics for response times, failure rates, and overall availability. Alerts help detect issues proactively and reduce mean-time-to-recovery (MTTR).", - "guid": "e52e4514-02a7-4e81-a98e-88ce1b18e557", - "link": "https://learn.microsoft.com/azure/azure-monitor/app/alerts", - "service": "App Services", + "guid": "7f42c78e-78cb-46a2-8ad1-90916e6a8d8f", + "link": "https://www.microsoft.com/research/blog/llmlingua-innovating-llm-efficiency-with-prompt-compression/", + "service": "Azure OpenAI", "services": [ - "WAF", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Set up alerts for critical Application Insights metrics, such as response time and failure rates.", - "waf": "Reliability" + "text": "Use prompt compression tools like LLMLingua or gprtrim", + "waf": "Cost Optimization" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Use Azure Policy to enforce security, compliance, and governance configurations for App Service. Policies can ensure that critical settings such as TLS versions, backup configurations, and network restrictions are enforced across all App Service instances.", - "guid": "361e886f-ca40-4ead-a8e9-1379c642ae9c", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "App Services", + "graph": "resources | where type =~ 'Microsoft.CognitiveServices/accounts' or type == 'microsoft.search/searchservices' | project id, compliant = (isnotnull(identity))", + "guid": "1102cac6-eae0-41e6-b842-e52f4721d928", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/managed-identity", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "ACR", - "Backup", - "AzurePolicy", + "AKV", + "Entra", "WAF" ], "severity": "High", - "text": "Apply Azure Policy to enforce compliance across App Service configurations.", - "waf": "Governance" + "text": "Ensure that APIs and endpoints used by the LLM application are properly secured with authentication and authorization mechanisms, such as Managed identities, API keys or OAuth, to prevent unauthorized access.", + "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "Leverage Azure Cost Management to track and forecast App Service expenses. Set up alerts for budget thresholds to avoid overspending, and optimize costs based on resource utilization trends.", - "guid": "42eb48f0-28ff-497c-b2c0-a8fa1f989832", - "link": "https://learn.microsoft.com/azure/cost-management-billing/", - "service": "App Services", + "guid": "c1b1cd52-1e54-4a29-a9de-399cfd7b28dc", + "link": "https://techcommunity.microsoft.com/t5/azure-architecture-blog/security-best-practices-for-genai-applications-openai-in-azure/ba-p/4027885", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "WAF", - "Cost", - "Monitor" + "WAF" ], - "severity": "Low", - "text": "Monitor App Service costs using Azure Cost Management and create cost alerts.", - "waf": "Cost" + "severity": "Medium", + "text": "Enforce strong end user authentication mechanisms, such as multi-factor authentication, to prevent unauthorized access to the LLM application and associated network resources", + "waf": "Security" }, { - "arm-service": "microsoft.web/sites", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "If you have predictable and steady usage of App Service, purchasing Reserved Instances can significantly reduce long-term costs. Commit to one or three years for lower pricing compared to pay-as-you-go.", - "guid": "e489221b-487e-48a3-aaab-48e3d205ca12", - "link": "https://learn.microsoft.com/azure/cost-management-billing/reservations/", - "service": "App Services", + "guid": "93555620-2bfe-4456-9b0d-834a348b263e", + "service": "Azure OpenAI", "services": [ - "AppSvc", - "ARS", - "Cost", - "Storage", + "Monitor", "WAF" ], "severity": "Medium", - "text": "Purchase reserved instances for App Service plans to optimize long-term costs.", - "waf": "Cost" + "text": "Implement network monitoring tools to detect and analyze network traffic for any suspicious or malicious activities. Enable logging to capture network events and facilitate forensic analysis in case of security incidents", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "32e42e36-11c8-418b-8a0b-c510e43a18a9", - "service": "AVS", + "guid": "6dd60512-a364-498f-9dba-d38ead53cc7c", + "service": "Azure OpenAI", "services": [ - "Subscriptions", - "WAF", - "Entra" + "WAF" ], - "severity": "High", - "text": "Ensure ADDS domain controller(s) are deployed in the identity subscription in native Azure", + "severity": "Medium", + "text": "Conduct security audits and penetration testing to identify and address any network security weaknesses or vulnerabilities in the LLM application's network infrastructure", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "75089c20-990d-4927-b105-885576f76fc2", - "service": "AVS", + "graph": "resources | where type == 'microsoft.cognitiveservices/accounts' or type == 'microsoft.search/searchservices' | project id, compliant = (tags != '{}')", + "guid": "e1d7aaab-3571-4449-ab80-53d89f89dc7b", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/tag-resources?tabs=json", + "service": "Azure OpenAI", "services": [ - "AVS", "WAF" ], - "severity": "Medium", - "text": "Ensure ADDS sites and services is configured to keep authentication requests from Azure-based resources (including Azure VMware Solution) local to Azure", - "waf": "Security" + "severity": "Low", + "text": "Azure AI Services are properly tagged for better management", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "de3aad1e-7c28-4ec9-9666-b7570449aa80", - "service": "AVS", + "guid": "77036e5e-6b4b-4ed3-b503-547c1347dc56", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations", + "service": "Azure OpenAI", "services": [ "WAF" ], - "severity": "High", - "text": "Ensure that vCenter is connected to ADDS to enable authentication based on 'named user accounts'", - "waf": "Security" + "severity": "Low", + "text": "Azure AI Service accounts follows organizational naming conventions", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "cd289ced-6b17-4db8-8554-61e2aee3553a", - "service": "AVS", + "guid": "028a71ff-e1ce-415d-b3f0-d5e772d41e36", + "link": "https://learn.microsoft.com/azure/ai-services/diagnostic-logging", + "service": "Azure OpenAI", "services": [ "WAF" ], - "severity": "Medium", - "text": "Ensure that the connection from vCenter to ADDS is using a secure protocol (LDAPS)", - "waf": "Security" + "severity": "High", + "text": "Diagnostic logs in Azure AI services resources should be enabled", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "b9d37dac-43bc-46cd-8d79-a9b24604489a", - "service": "AVS", + "graph": "resources | where type =~ 'Microsoft.CognitiveServices/accounts' or type == 'microsoft.search/searchservices' | project id, compliant = (properties.disableLocalAuth == true)", + "guid": "11cc57b4-a4b1-4410-b439-58a8c2289b3d", + "link": "https://learn.microsoft.com/azure/ai-services/authentication", + "service": "Azure OpenAI", "services": [ + "Entra", "WAF" ], - "severity": "Medium", - "text": "CloudAdmin account in vCenter IdP is used only as an emergency account (break-glass)", + "severity": "High", + "text": "Key access (local authentication) is recommended to be disabled for security. After disabling key based access, Microsoft Entra ID becomes the only access method, which allows maintaining minimum privilege principle and granular control. ", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "53d88e89-d17b-473b-82a5-a67e7a9ed5b3", - "service": "AVS", + "guid": "6b57cfc6-5546-41e1-a3e3-453a3c863964", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Azure OpenAI", "services": [ - "WAF", - "Entra" + "AKV", + "Entra", + "WAF" ], "severity": "High", - "text": "Ensure that NSX-Manager is integrated with an external Identity provider (LDAPS)", + "text": "Store and manage keys securely using Azure Key Vault. Avoid hard-coding or embedding sensitive keys within your LLM application's code and retrieve them securely from Azure Key Vault using managed identities", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "ae0e37ce-e297-411b-b352-caaab79b198d", - "service": "AVS", + "guid": "8b652d6c-15f5-4129-9539-8e6ded227dd1", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Azure OpenAI", "services": [ - "RBAC", - "AVS", + "AKV", "WAF" ], - "severity": "Medium", - "text": "Has an RBAC model been created for use within VMware vSphere", + "severity": "High", + "text": "Regularly rotate and expire keys stored in Azure Key Vault to minimize the risk of unauthorized access.", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "ab81932c-9fc9-4d1b-a780-36f5e6bfbb9e", - "service": "AVS", + "guid": "adfe27be-e297-401a-a352-baaab79b088d", + "link": "https://github.com/openai/tiktoken", + "service": "Azure OpenAI", "services": [ - "RBAC", "WAF" ], - "severity": "Medium", - "text": "RBAC permissions should be granted on ADDS groups and not on specific users", - "waf": "Security" + "severity": "High", + "text": "Use tiktoken to understand token sizes for token optimizations in conversational mode", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "d503547c-c447-4e82-9128-a71f0f1cac6d", - "service": "AVS", + "guid": "42b06c21-d799-49a6-96f4-389a7f42c78e", + "link": "https://learn.microsoft.com/azure/security/develop/secure-dev-overview", + "service": "Azure OpenAI", "services": [ - "RBAC", - "AVS", "WAF" ], "severity": "High", - "text": "RBAC permissions on the Azure VMware Solution resource in Azure are 'locked down' to a limited set of owners only", + "text": "Follow secure coding practices to prevent common vulnerabilities such as injection attacks, cross-site scripting (XSS), or security misconfigurations", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "fd9f0df4-68dc-4976-b9a9-e6a79f7682c5", - "service": "AVS", + "guid": "78c06a73-a22a-4495-9e6a-8dc4a20e27c3", + "link": "https://learn.microsoft.com/azure/devops/repos/security/github-advanced-security-dependency-scanning?view=azure-devops", + "service": "Azure OpenAI", "services": [ - "RBAC", "WAF" ], "severity": "High", - "text": "Ensure all custom roles are scoped with CloudAdmin permitted authorizations", + "text": "Setup a process to regularly update and patch the LLM libraries and other system components", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "9ef1d5e8-32e4-42e3-911c-818b0a0bc510", - "link": "https://github.com/Azure/AzureCAT-AVS/tree/main/networking", - "service": "AVS", + "guid": "e29711b1-352b-4eee-879b-588defc4972c", + "link": "https://learn.microsoft.com/legal/cognitive-services/openai/code-of-conduct", + "service": "Azure OpenAI", "services": [ - "AVS", + "AzurePolicy", "WAF" ], "severity": "High", - "text": "Is the correct Azure VMware Solution connectivity model selected for the customer use case at hand", - "waf": "Performance" + "text": "Adhere to Azure OpenAI or other LLMs terms of use, policies and guidance and allowed use cases", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "eb710a37-cbc1-4055-8dd5-a936a8bb7cf5", - "service": "AVS", + "guid": "d3cd21bf-7703-46e5-b6b4-bed3d503547c", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs#base-series-and-codex-series-fine-tuned-models", + "service": "Azure OpenAI", "services": [ - "VPN", - "NetworkWatcher", - "ExpressRoute", - "Monitor", + "Cost", + "WAF" + ], + "severity": "Medium", + "text": "Understand difference in cost of base models and fine tuned models and token step sizes", + "waf": "Cost Optimization" + }, + { + "arm-service": "Microsoft.CognitiveServices/accounts", + "checklist": "WAF checklist", + "guid": "1347dc56-028a-471f-be1c-e15dd3f0d5e7", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/latency#batching", + "service": "Azure OpenAI", + "services": [ + "Cost", "WAF" ], "severity": "High", - "text": "Ensure ExpressRoute or VPN connections from on-premises to Azure are monitored using 'connection monitor'", - "waf": "Operations" + "text": "Batch requests, where possible, to minimize the per-call overhead which can reduce overall costs. Ensure you optimize batch size", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "976e24f2-a7f8-426c-9253-2a92a2a7ed99", - "service": "AVS", + "guid": "72d41e36-11cc-457b-9a4b-1410d43958a8", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", + "service": "Azure OpenAI", "services": [ - "VM", - "AVS", - "NetworkWatcher", - "ExpressRoute", + "Cost", "Monitor", "WAF" ], "severity": "Medium", - "text": "Ensure a connection monitor is created from an Azure native resource to an Azure VMware Solution virtual machine to monitor the Azure VMware Solution back-end ExpressRoute connection", - "waf": "Operations" + "text": "Set up a cost tracking system that monitors model usage and use that information to help inform model choices and prompt sizes", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "f41ce6a0-64f3-4805-bc65-3ab50df01265", - "service": "AVS", + "guid": "166cd072-af9b-4141-a898-a535e737897e", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/quota?tabs=rest#understanding-rate-limits", + "service": "Azure OpenAI", "services": [ - "VM", - "AVS", - "NetworkWatcher", - "Monitor", "WAF" ], "severity": "Medium", - "text": "Ensure a connection monitor is created from an on-premises resource to an Azure VMware Solution virtual machine to monitor end-2-end connectivity", - "waf": "Operations" + "text": "Set a maximum limit on the number of tokens per model response (max_tokens and the number of completions to generate). Optimize the size to ensure it is large enough for a valid response", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "563b4dc7-4a74-48b6-933a-d1a0916a6649", - "service": "AVS", + "guid": "3266b225-86f4-4a16-92bd-ddea8a487cde", + "link": "https://learn.microsoft.com/azure/search/vector-search-index-size?tabs=portal-vector-quota", + "service": "Azure OpenAI", "services": [ - "ARS", + "Storage", "WAF" ], - "severity": "High", - "text": "When route server is used, ensure no more then 1000 routes are propagated from route server to ExR gateway to on-premises (ARS limit).", - "waf": "Operations" + "severity": "Medium", + "text": "Plan and manage AI Search Vector storage", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "6128a71f-0f1c-4ac6-b9ef-1d5e832e42e3", - "service": "AVS", + "guid": "b4861bc3-bc14-4aeb-9e66-e8d9a3aec218", + "link": "https://learn.microsoft.com/azure/machine-learning/prompt-flow/how-to-end-to-end-llmops-with-prompt-flow?view=azureml-api-2", + "service": "Azure OpenAI", "services": [ - "RBAC", - "AVS", - "WAF", - "Entra" + "ACR", + "WAF" ], - "severity": "High", - "text": "Is Privileged Identity Management implemented for roles managing the Azure VMware Solution resource in the Azure Portal (no standing permissions allowed)", - "waf": "Security" + "severity": "Medium", + "text": "Ensure deployment of Azure OpenAI instances across your various environments, such as development, test, and production supporting lrarning & experimentation. Apply LLMOps practices to automate the lifecycle management of your GenAI applications", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "c4e2436b-b336-4d71-9f17-960eee0b9b5c", - "service": "AVS", + "guid": "aa80932c-8ec9-4d1b-a770-26e5e6beba9e", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/provisioned-throughput-onboarding#understanding-the-provisioned-throughput-purchase-model", + "service": "Azure OpenAI", "services": [ - "RBAC", - "AVS", - "WAF", - "Entra" + "Storage", + "WAF" ], "severity": "High", - "text": "Privileged Identity Management audit reporting should be implemented for the Azure VMware Solution PIM roles", - "waf": "Security" + "text": "Evaluate usage of billing models - PAYG vs PTU. Start with PAYG and consider PTU when the usage is predictable in production since it offers dedicated memory and compute, reserved capacity, and consistent maximum latency for the specified model version", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "78c447a8-26b2-4863-af0f-1cac599ef1d5", - "service": "AVS", + "guid": "e6436b07-36db-455f-9796-03334bdf9cc2", + "link": "https://techcommunity.microsoft.com/t5/ai-azure-ai-services-blog/how-to-control-azure-openai-models/ba-p/4146793", + "service": "Azure OpenAI", "services": [ - "AVS", - "WAF", - "Entra" + "WAF" ], "severity": "Medium", - "text": "If using Privileged Identity Management is being used, ensure that a valid Entra ID enabled account is created with a valid SMTP record for Azure VMware Solution Automatic Host replacement notifications. (standing permissions required)", - "waf": "Security" + "text": "Evaluate the quality of prompts and applications when switching between model versions", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "8defc4d7-21d3-41d2-90fb-707ae9eab40e", - "service": "AVS", + "guid": "3418db61-2712-4650-9bb4-7a393a080327", + "link": "https://learn.microsoft.com/azure/machine-learning/prompt-flow/concept-model-monitoring-generative-ai-evaluation-metrics?view=azureml-api-2", + "service": "Azure OpenAI", "services": [ + "Monitor", "WAF" ], - "severity": "High", - "text": "Limit use of CloudAdmin account to emergency access only", - "waf": "Security" + "severity": "Medium", + "text": "Evaluate, monitor and refine your GenAI apps for features like groundedness, relevance, accuracy, coherence and fluency", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "d329f798-bc17-48bd-a5a0-6ca7144351d1", - "service": "AVS", + "guid": "294798b1-578b-4219-a46c-eb5443513592", + "service": "Azure OpenAI", "services": [ - "RBAC", "WAF" ], "severity": "Medium", - "text": "Create custom RBAC roles in vCenter to implement a least-privilege model inside vCenter", - "waf": "Security" + "text": "Evaluate your Azure AI Search results based on different search parameters", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "9dd24429-eb72-4281-97a1-51c5bb4e4f18", - "service": "AVS", + "guid": "2744293b-b628-4537-a551-19b08e8f5854", + "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/fine-tuning-considerations", + "service": "Azure OpenAI", "services": [ "WAF" ], "severity": "Medium", - "text": "Is a process defined to regularly rotate cloudadmin (vCenter) and admin (NSX) credentials", - "waf": "Security" + "text": "Look at fine tuning models as way of increasing accuracy only when you have tried other basic approaches like prompt engineering and RAG with your data", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "586cb291-ec16-4a1d-876e-f9f141acdce5", - "service": "AVS", + "guid": "287d9cec-166c-4d07-8af9-b141a898a535", + "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/advanced-prompt-engineering?pivots=programming-language-chat-completions", + "service": "Azure OpenAI", "services": [ - "VM", - "AVS", - "WAF", - "Entra" + "WAF" ], - "severity": "High", - "text": "Use a centralized identity provider to be used for workloads (VM's) running on Azure VMware Solution", - "waf": "Security" + "severity": "Medium", + "text": "Use prompt engineering techniques to improve the accuracy of LLM responses", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "79377bcd-b375-41ab-8ab0-ead66e15d3d4", - "service": "AVS", + "guid": "e737897e-71ca-47da-acfa-962a1594946d", + "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/red-teaming", + "service": "Azure OpenAI", "services": [ "WAF" ], "severity": "Medium", - "text": "Is East-West traffic filtering implemented within NSX-T", + "text": "Red team your GenAI applications", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "a2adb1c3-d232-46af-825c-a44e1695fddd", - "service": "AVS", + "guid": "edb117e6-76aa-4f66-aca4-8e5a95f2223e", + "link": "https://www.microsoft.com/haxtoolkit/guideline/encourage-granular-feedback/", + "service": "Azure OpenAI", "services": [ - "AppGW", - "AVS", - "Firewall", "WAF" ], - "severity": "High", - "text": "Workloads on Azure VMware Solution are not directly exposed to the internet. Traffic is filtered and inspected by Azure Application Gateway, Azure Firewall or 3rd party solutions", - "waf": "Security" + "severity": "Medium", + "text": "Provide end users with scoring options for LLM responses and track these scores. ", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "eace4cb1-deb4-4c65-8c3f-c14eeab36938", - "service": "AVS", + "guid": "d5f3547c-c346-4d81-9028-a71ffe1b9b5d", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/optimizing-azure-openai-a-guide-to-limits-quotas-and-best/ba-p/4076268", + "service": "Azure OpenAI", "services": [ - "AVS", "WAF" ], "severity": "High", - "text": "Auditing and logging is implemented for inbound internet requests to Azure VMware Solution and Azure VMware Solution based workloads", - "waf": "Security" + "text": "Consider Quota management practices. Use dynamic quota for certain use cases when your application can use extra capacity opportunistically or the application itself is driving the rate at which the Azure OpenAI API is called", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "29e3eec2-1836-487a-8077-a2b5945bda43", - "service": "AVS", + "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc410", + "link": "https://github.com/Azure/aoai-apim/blob/main/README.md", + "service": "Azure OpenAI", "services": [ - "AVS", + "ACR", "WAF", - "Monitor" + "LoadBalancer", + "APIM", + "Entra" ], "severity": "Medium", - "text": "Session monitoring is implemented for outbound internet connections from Azure VMware Solution or Azure VMware Solution based workloads to identify suspicious/malicious activity", - "waf": "Security" + "text": "Use Load balancer solutions like APIM based gateway for balancing load and capacity across services and regions", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "graph": "resources| where type =~ 'Microsoft.Network/virtualNetworkGateways'| mv-expand ipConfigurations=properties.ipConfigurations| project subnetId=tostring(ipConfigurations.properties.subnet.id)| where isnotempty(subnetId)| join (resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,enableDdosProtection=tostring(properties.enableDdosProtection),subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,enableDdosProtection,subnetId=tostring(subnets.id)) on subnetId | distinct id,resourceGroup,name,enableDdosProtection | project id, compliant = (enableDdosProtection == 'true')", - "guid": "334fdf91-c234-4182-a652-75269440b4be", - "service": "AVS", + "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc411", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/fine-tuning?tabs=turbo%2Cpython-new&pivots=programming-language-studio#import-training-data-from-azure-blob-store", + "service": "Azure OpenAI", "services": [ - "VPN", - "DDoS", - "ExpressRoute", - "VNet", + "Storage", "WAF" ], "severity": "Medium", - "text": "Is DDoS standard protection enabled on ExR/VPN Gateway subnet in Azure", - "waf": "Security" + "text": "Follow the guidance for fine-tuning with large data files and import the data from an Azure blob store. Large files, 100 MB or larger, can become unstable when uploaded through multipart forms because the requests are atomic and can't be retried or resumed", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "3d3e0843-276d-44bd-a015-bcf219e4a1eb", - "service": "AVS", + "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc412", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/quota?tabs=rest", + "service": "Azure OpenAI", "services": [ - "AVS", + "Monitor", "WAF" ], "severity": "Medium", - "text": "Use a dedicated privileged access workstation (PAW) to manage Azure VMware Solution, vCenter, NSX manager and HCX manager", - "waf": "Security" + "text": "Manage rate limits for your model deployments and monitor usage of tokens per minute (TPM) and requests per minute (RPM) for pay-as-you-go deployments", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "9ccbd869-266a-4cca-874f-aa19bf39d95d", - "service": "AVS", + "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc413", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitor-openai", + "service": "Azure OpenAI", "services": [ - "AVS", - "WAF", - "Defender" + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Enable Advanced Threat Detection (Microsoft Defender for Cloud aka ASC) for workloads running on Azure VMware Solution", - "waf": "Security" + "text": "Monitor provision-managed utilization if you're using the provisioned throughput payment model", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "44c7c891-9ca1-4f6d-9315-ae524ba34d45", - "service": "AVS", + "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc414", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/content-filters", + "service": "Azure OpenAI", "services": [ - "AVS", - "WAF", - "Arc" + "WAF" ], "severity": "Medium", - "text": "Use Azure ARC for Servers to properly govern workloads running on Azure VMware Solution using Azure native technologies (Azure ARC for Azure VMware Solution is not yet available)", - "waf": "Security" + "text": "Tune content filters to minimize false positives from overly aggressive filters", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "85e12139-bd7b-4b01-8f7b-95ef6e043e2a", - "service": "AVS", + "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc415", + "link": "https://learn.microsoft.com/azure/ai-services/openai/encrypt-data-at-rest", + "service": "Azure OpenAI", "services": [ - "AVS", - "SQL", + "AKV", "WAF" ], - "severity": "Low", - "text": "Ensure workloads on Azure VMware Solution use sufficient data encryption during run-time (like in-guest disk encryption and SQL TDE). (vSAN encryption at rest is default)", + "severity": "Medium", + "text": "Use customer-managed keys for fine-tuned models and training data that's uploaded to Azure OpenAI", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "a3592718-e6e2-4051-9267-6ae46691e883", - "service": "AVS", + "graph": "resources | where type == 'microsoft.cognitiveservices/accounts' and kind =~ 'contentsafety' | project id, compliant = 1", + "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc416", + "link": "https://learn.microsoft.com/azure/ai-services/content-safety/concepts/jailbreak-detection", + "service": "Azure OpenAI", "services": [ - "AKV", + "LoadBalancer", "WAF" ], - "severity": "Low", - "text": "When in-guest encryption is used, store encryption keys in Azure Key vault when possible", + "severity": "Medium", + "text": "Implement jailbreak risk detection to safeguard your language model deployments against prompt injection attacks", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "5ac94222-3e13-4810-9230-81a941741583", - "service": "AVS", + "guid": "9de0d5d7-31d4-41e3-911c-817bfafbc417", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/monitor-openai", + "service": "Azure OpenAI", "services": [ - "AVS", "WAF" ], "severity": "Medium", - "text": "Consider using extended security update support for workloads running on Azure VMware Solution (Azure VMware Solution is eligible for ESU)", + "text": "Use security controls like throttling, service isolation and gateway pattern to prevent attacks that might exhaust model usage quotas", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "3ef7ad7c-6d37-4331-95c7-acbe44bbe609", - "service": "AVS", + "guid": "72d41e36-11cc-457b-9a4b-1410d43958a9", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", + "service": "Azure OpenAI", "services": [ + "Cost", "WAF" ], - "severity": "High", - "text": "Ensure that the appropriate vSAN Data redundancy method is used (RAID specification)", - "waf": "Reliability" + "severity": "Medium", + "text": "Develop your cost model, considering prompt sizes. Understanding prompt input and response sizes and how text translates into tokens helps you create a viable cost model", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "d88408f3-7273-44c8-96ba-280214590146", - "service": "AVS", + "guid": "72d41e36-11cc-457b-9a4b-1410d43958a1", + "link": "https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/", + "service": "Azure OpenAI", "services": [ - "AzurePolicy", - "Storage", + "Cost", "WAF" ], - "severity": "High", - "text": "Ensure that the Failure-to-tolerate policy is in place to meet your vSAN storage needs", - "waf": "Reliability" + "severity": "Medium", + "text": "Consider model pricing and capabilities when you choose models. Start with less-costly models for less-complex tasks like text generation or completion tasks and for complex tasks like language translation or content understanding, consider using more advanced models. Optimize costs while still achieving the desired application performance", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "d89f2e87-7784-424d-9167-85c6fa95b96a", - "service": "AVS", + "guid": "72d41e36-11cc-457b-9a4b-1410d43958a2", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", + "service": "Azure OpenAI", "services": [ - "ASR", + "Cost", "WAF" ], - "severity": "High", - "text": "Ensure that you have requested enough quota, ensuring you have considered growth and Disaster Recovery requirement", - "waf": "Reliability" + "severity": "Medium", + "text": "Maximize Azure OpenAI price breakpoints like fine-tuning and model breakpoints like image generation to your advantage. Fine-tuning is charged per hour, use as much time as you have available per hour to improve results without slipping into the next billing period. The cost for generating 100 images is the same as the cost for 1 image", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "5d38e53f-9ccb-4d86-a266-acca274faa19", - "service": "AVS", + "guid": "72d41e36-11cc-457b-9a4b-1410d43958a3", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", + "service": "Azure OpenAI", "services": [ "WAF" ], "severity": "Medium", - "text": "Ensure that access constraints to ESXi are understood, there are access limits which might affect 3rd party solutions.", - "waf": "Operations" + "text": "Remove unused fine-tuned models when they're no longer being consumed to avoid incurring an ongoing hosting fee", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "bf39d95d-44c7-4c89-89ca-1f6d5315ae52", - "service": "AVS", + "guid": "7f42c78e-78cb-46a2-8ad1-90916e6a8d8g", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/manage-costs", + "service": "Azure OpenAI", "services": [ - "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Ensure that you have a policy around ESXi host density and efficiency, keeping in mind the lead time for requesting new nodes", - "waf": "Operations" + "text": "Create concise prompts that provide enough context for the model to generate a useful response. Also ensure that you optimize the limit of the response length.", + "waf": "Cost Optimization" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "4ba34d45-85e1-4213-abd7-bb012f7b95ef", - "service": "AVS", + "guid": "b4861bc3-bc14-4aeb-9e66-e8d9a3aec219", + "link": "https://learn.microsoft.com/azure/ai-services/create-account-bicep", + "service": "Azure OpenAI", "services": [ - "AVS", - "WAF", - "Cost" + "WAF" ], "severity": "Medium", - "text": "Ensure a good cost management process is in place for Azure VMware Solution - Azure Cost Management can be used", - "waf": "Cost" + "text": "Use infrastructure as code (IaC) to deploy Azure OpenAI, model deployments, and other infrastructure required for fine-tuning models", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "6e043e2a-a359-4271-ae6e-205172676ae4", - "service": "AVS", + "guid": "2744293b-b628-4537-a551-19b08e8f5855", + "link": "https://learn.microsoft.com/azure/architecture/guide/multitenant/service/openai", + "service": "Azure OpenAI", "services": [ - "AVS", - "WAF", - "Cost" + "WAF" ], - "severity": "Low", - "text": "Are Azure reserved instances used to optimize cost for using Azure VMware Solution", - "waf": "Cost" + "severity": "Medium", + "text": "Consider using dedicated model deployments per consumer group to provide per-model usage isolation that can help prevent noisy neighbors between your consumer groups", + "waf": "Operational Excellence" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "6691e883-5ac9-4422-83e1-3810523081a9", - "service": "AVS", + "description": "Disable image export to prevent data exfiltration. Note that this will prevent image import of images into another ACR instance.", + "guid": "ab91932c-9fc9-4d1b-a880-37f5e6bfcb9e", + "link": "https://learn.microsoft.com/azure/container-registry/data-loss-prevention", + "query": "resources | where type =~ 'Microsoft.ContainerRegistry/registries' | extend acrName = name, acrId = id | extend exportPolicyStatus = properties.policies.exportPolicy.status | extend compliant = iif(exportPolicyStatus =~ 'Disabled', true, false) | project acrName, acrId, exportPolicyStatus, compliant", + "service": "ACR", "services": [ + "ACR", "WAF" ], - "severity": "Medium", - "text": "Consider the use of Azure Private-Link when using other Azure Native Services", + "severity": "High", + "text": "Disable Azure Container Registry image export", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "db611712-6904-40b4-aa3d-3e0803276d4b", - "service": "AVS", + "description": "Enable audit compliance visibility by enabling Azure Policy for Azure Container Registry", + "guid": "d503547c-d447-4e82-9128-a7100f1cac6d", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-azure-policy", + "service": "ACR", "services": [ + "ACR", + "AzurePolicy", "WAF" ], "severity": "High", - "text": "Ensure all required resource reside within the same Azure availability zone(s)", - "waf": "Performance" + "text": "Enable Azure Policies for Azure Container Registry", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "48b262d6-cc5f-4512-a253-98e6db9d37da", - "service": "AVS", + "description": "The Azure Key Vault (AKV) is used to store a signing key that can be utilized by?notation?with the notation AKV plugin (azure-kv) to sign and verify container images and other artifacts. The Azure Container Registry (ACR) allows you to attach these signatures using the?az?or?oras?CLI commands.", + "guid": "d345293c-7639-4637-a551-c5c04e401955", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-tutorial-sign-build-push", + "service": "ACR", "services": [ - "VM", - "AVS", - "WAF", - "Defender" + "ACR", + "AKV", + "WAF" ], - "severity": "Medium", - "text": "Enable Microsoft Defender for Cloud for Azure VMware Solution guest VM workloads", + "severity": "High", + "text": "Sign and Verify containers with notation (Notary v2)", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "41741583-3ef7-4ad7-a6d3-733165c7acbe", - "service": "AVS", + "description": "Azure Container Registry automatically encrypts images and other artifacts that you store. By default, Azure automatically encrypts the registry content at rest by using service-managed keys. By using a customer-managed key, you can supplement default encryption with an additional encryption layer.", + "graph": "resources | where type =~ 'Microsoft.ContainerRegistry/registries' | extend acrName = name, acrId = id | extend encryptionStatus = properties.encryption.status | extend compliant = iif(encryptionStatus == 'disabled', false, true) | project acrName, acrId, encryptionStatus, compliant", + "guid": "0bd05dc2-efd5-4d76-8d41-d2500cc47b49", + "link": "https://learn.microsoft.com/azure/container-registry/tutorial-customer-managed-keys", + "service": "ACR", "services": [ - "VM", - "AVS", - "WAF", - "Arc" + "ACR", + "AKV", + "WAF" ], "severity": "Medium", - "text": "Use Azure Arc enabled servers to manage your Azure VMware Solution guest VM workloads", + "text": "Encrypt registry with a customer managed key", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "88f03a4d-2cd4-463c-abbc-868295abc91a", - "service": "AVS", + "description": "Use managed identities to secure ACRPull/Push RBAC access from client applications", + "guid": "8f42d78e-79dc-47b3-9bd2-a1a27e7a8e90", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication-managed-identity", + "service": "ACR", "services": [ - "AVS", + "ACR", + "RBAC", + "Entra", "WAF" ], "severity": "High", - "text": "Enable Diagnostic and metric logging on Azure VMware Solution", - "waf": "Operations" + "text": "Use Managed Identities to connect instead of Service Principals", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "4ed90dae-2cc8-44c4-9b6b-781cbafe6c46", - "service": "AVS", + "description": "The local Administrator account is disabled by default and should not be enabled. Use either Token or RBAC-based access methods instead", + "graph": "resources | where type =~ 'microsoft.containerregistry/registries' | extend localAdminDisabled = properties.adminUserEnabled // Adjust this property as needed | extend compliant = iif(localAdminDisabled == 'false', true, false) // Check if local admin is disabled | project compliant, name, id, tags | distinct id, compliant", + "guid": "be0e38ce-e297-411b-b363-caaab79b198d", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication-managed-identity", + "service": "ACR", "services": [ - "VM", - "AVS", - "WAF", - "Monitor" + "RBAC", + "WAF" ], - "severity": "Medium", - "text": "Deploy the Log Analytics Agents to Azure VMware Solution guest VM workloads", - "waf": "Operations" + "severity": "High", + "text": "Disable local authentication for management plane access", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "589d457a-927c-4397-9d11-02cad6aae11e", - "service": "AVS", - "services": [ - "VM", - "AVS", - "Backup", - "AzurePolicy", + "description": "Disable Administrator account and assign RBAC roles to principals for ACR Pull/Push operations", + "graph": "resources | where type =~ 'microsoft.containerregistry/registries' | extend localAdminDisabled = properties.adminUserEnabled // Adjust this property as needed | extend compliant = iif(localAdminDisabled == 'false', true, false) // Check if local admin is disabled | project compliant, name, id, tags | distinct id, compliant", + "guid": "387e5ced-126c-4d13-8af5-b20c6998a646", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-roles?tabs=azure-cli", + "service": "ACR", + "services": [ + "ACR", + "RBAC", + "Entra", "WAF" ], - "severity": "Medium", - "text": "Ensure you have a documented and implemented backup policy and solution for Azure VMware Solution VM workloads", - "waf": "Operations" + "severity": "High", + "text": "Assign AcrPull & AcrPush RBAC roles rather than granting Administrative access to identity principals", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "ee29711b-d352-4caa-ab79-b198dab81932", - "service": "AVS", + "description": "Disable anonymous pull/push access", + "graph": "resources | where type =~ 'microsoft.containerregistry/registries' | extend compliant = iif(properties.anonymousPullEnabled == false, true, false) | project compliant, name, id, tags | distinct id, compliant", + "guid": "e338997e-41c7-47d7-acf6-a62a1194956d", + "link": "https://learn.microsoft.com/azure/container-registry/anonymous-pull-access#configure-anonymous-pull-access", + "service": "ACR", "services": [ - "AVS", - "Defender", - "WAF", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Use Microsoft Defender for Cloud for compliance monitoring of workloads running on Azure VMware Solution", + "text": "Disable Anonymous pull access", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "c9fc9d1b-b780-436f-9e6b-fbb9ed503547", - "service": "AVS", + "description": "Token authentication doesn't support assignment to an AAD principal. Any tokens provided are able to be used by anyone who can access the token", + "guid": "698dc3a2-fd27-4b2e-8870-1a1252beedf6", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-authentication?tabs=azure-cli", + "service": "ACR", "services": [ - "WAF", - "Defender" + "Entra", + "WAF" ], - "severity": "Medium", - "text": "Are the applicable compliance baselines added to Microsoft Defender for Cloud", + "severity": "High", + "text": "Disable repository-scoped access tokens", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "cc447e82-6128-4a71-b0f1-cac6d9ef1d5e", - "service": "AVS", + "description": "Deploy container images to an ACR behind a Private endpoint within a trusted network", + "guid": "b3bec3d4-f343-47c1-936d-b55f27a71eee", + "service": "ACR", "services": [ - "AVS", + "ACR", + "EventHubs", + "PrivateLink", "WAF" ], "severity": "High", - "text": "Was data residency evaluated when selecting Azure regions to use for Azure VMware Solution deployment", + "text": "Deploy images from a trusted environment", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "832e42e3-611c-4818-a0a0-bc510e43a18a", - "service": "AVS", + "description": "Only tokens with an ACR audience can be used for authentication. Used when enabling Conditional access policies for ACR", + "guid": "3a041fd3-2947-498b-8288-b3c6a56ceb54", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-enable-conditional-access-policy", + "service": "ACR", "services": [ + "ACR", + "Entra", + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Are data processing implications (service provider / service consumer model) clear and documented", + "severity": "Medium", + "text": "Disable Azure ARM audience tokens for authentication", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "547c1747-dc56-4068-a714-435cd19dd244", - "service": "AVS", + "description": "Set up a diagnostic setting to send 'repositoryEvents' & 'LoginEvents' to Log Analytics as the central destination for logging and monitoring. This allows you to monitor control plane activity on the ACR resource itself.", + "guid": "8a488cde-c486-42bc-9bd2-1be77f26e5e6", + "link": "https://learn.microsoft.com/azure/container-registry/monitor-service", + "service": "ACR", "services": [ + "ACR", + "Monitor", + "Entra", "WAF" ], "severity": "Medium", - "text": "Consider using CMK (Customer Managed Key) for vSAN only if needed for compliance reason(s).", + "text": "Enable diagnostics logging", "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "e43a18a9-cd28-49ce-b6b1-7db8255461e2", - "service": "AVS", + "description": "Service supports disabling public network access either through using service-level IP ACL filtering rule (not NSG or Azure Firewall) or using a 'Disable Public Network Access' toggle switch", + "guid": "21d41d25-00b7-407a-b9ea-b40fd3290798", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-private-link", + "service": "ACR", "services": [ - "AVS", - "WAF", - "Monitor" + "VNet", + "PrivateLink", + "Firewall", + "WAF" ], - "severity": "High", - "text": "Create dashboards to enable core Azure VMware Solution monitoring insights", - "waf": "Operations" + "severity": "Medium", + "text": "Control inbound network access with Private Link", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "graph": "resources| where type =~ 'Microsoft.AVS/privateClouds'| join kind=leftouter(resources| where type =~ 'Microsoft.Insights/metricalerts'| mv-expand scopes=properties.scopes| mv-expand criteria=properties.criteria.allOf| extend metricName=criteria.metricName| distinct tostring(scopes), tostring(metricName))on $left.id == $right.scopes| extend compliant=toint(metricName in ('UsageAverage', 'EffectiveCpuAverage', 'DiskUsedPercentage'))| summarize compliant=min(compliant) by id", - "guid": "6b84ee5d-f47d-42d9-8881-b1cd5d1e54a2", - "service": "AVS", + "description": "Disable public network access if inbound network access is secured using Private Link", + "graph": "resources | where type =~ 'Microsoft.ContainerRegistry/registries' | where sku.name =~ 'Premium' // Check for Premium SKU | extend publicAccessEnabled = properties.publicNetworkAccess | extend defaultAction = tostring(properties.networkRuleSet.defaultAction) // Extract defaultAction | extend compliant = iif(publicAccessEnabled != 'Enabled' or defaultAction == 'Deny', true, false) | project name, id, publicAccessEnabled, defaultAction, compliant", + "guid": "cd289ced-6b17-4db8-8554-62f2aee4553a", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-access-selected-networks#disable-public-network-access", + "service": "ACR", "services": [ - "AVS", - "WAF", - "Monitor" + "PrivateLink", + "WAF" ], - "severity": "High", - "text": "Create warning alerts for critical thresholds for automatic alerting on Azure VMware Solution performance (CPU >80%, Avg Memory >80%, vSAN >70%)", - "waf": "Operations" + "severity": "Medium", + "text": "Disable Public Network access", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "graph": "resources| where type =~ 'Microsoft.AVS/privateClouds'| join kind=leftouter(resources| where type =~ 'Microsoft.Insights/metricalerts'| mv-expand scopes=properties.scopes| mv-expand criteria=properties.criteria.allOf| extend metricName=criteria.metricName| distinct tostring(scopes), tostring(metricName))on $left.id == $right.scopes| extend compliant=toint(metricName in ('UsageAverage', 'EffectiveCpuAverage', 'DiskUsedPercentage'))| summarize compliant=min(compliant) by id", - "guid": "9659e396-80e7-4828-ac93-5657d02bff45", - "service": "AVS", + "description": "Only the ACR Premium SKU supports Private Link access", + "graph": "resources | where type =~ 'Microsoft.ContainerRegistry/registries' | extend skuName = sku.name // Extract the SKU name | extend compliant = iif(skuName == 'Premium', true, false) // Check if SKU is Premium | project name, id, skuName, compliant", + "guid": "fc833934-8b26-42d6-ac5f-512925498f6d", + "link": "https://learn.microsoft.com/azure/container-registry/container-registry-skus", + "service": "ACR", "services": [ - "AVS", - "WAF", - "Monitor" + "ACR", + "PrivateLink", + "WAF" ], - "severity": "High", - "text": "Ensure critical alert is created to monitor if vSAN consumption is below 75% as this is a support threshold from VMware", - "waf": "Operations" + "severity": "Medium", + "text": "Use an Azure Container Registry SKU that supports Private Link (Premium SKU)", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "graph": "resources| distinct subscriptionId| join kind=leftouter( resources | where type =~ 'microsoft.insights/activitylogalerts' | mv-expand condition1 = properties.condition.allOf | mv-expand condition2 = condition1.anyOf | extend alertEnabled = tostring(properties.enabled) | summarize set_condition1=make_set(condition1.equals), set_condition2=make_set(condition2.equals) by id, name,type,tenantId,resourceGroup,subscriptionId, alertEnabled | where set_has_element(set_condition1, 'ServiceHealth') | extend category = 'ServiceHealth' | extend all = iff(set_has_element(set_condition1, 'ServiceHealth') and array_length(set_condition2) == 0, true, false) | extend incident = iff(all, true, iff(set_has_element(set_condition1, 'Incident'), true, set_has_element(set_condition2, 'Incident'))) | extend maintenance = iff(all, true, iff(set_has_element(set_condition1, 'Maintenance'), true, set_has_element(set_condition2, 'Maintenance'))) | extend informational = iff(all, true, iff(set_has_element(set_condition1, 'Informational') or set_has_element(set_condition1, 'ActionRequired'), true, set_has_element(set_condition2, 'Informational') or set_has_element(set_condition2, 'ActionRequired'))) | extend security = iff(all, true, iff(set_has_element(set_condition1, 'Security'), true, set_has_element(set_condition2, 'Security'))) | project id, name, subscriptionId, category, tostring(alertEnabled), tostring(incident), tostring(maintenance), tostring(informational), tostring(security) | summarize count_alertEnabled=countif(alertEnabled == 'true'), count_incident=countif(incident == 'True'), count_maintenance=countif(maintenance == 'True'), count_informational=countif(informational == 'True'), count_security=countif(security == 'True') by subscriptionId) on subscriptionId| project subscriptionId, alertEnabled=iff(isnotnull(count_alertEnabled), count_alertEnabled, 0), incident=iff(isnotnull(count_incident), count_incident, 0), security=iff(isnotnull(count_security), count_security, 0), maintenance=iff(isnotnull(count_maintenance), count_maintenance, 0), informational=iff(isnotnull(count_informational), count_informational, 0)| order by incident, maintenance, informational, security desc| project id=subscriptionId, compliant=(alertEnabled > 0 and incident > 0 and security > 0 and maintenance > 0 and informational > 0)", - "guid": "64b0d934-a348-4726-be79-d6b5c3a36495", - "service": "AVS", + "description": "Azure Defender for containers or equivalent service should be used to scan container images for vulnerabilities", + "guid": "bad37dac-43bc-46ce-8d7a-a9b24604489a", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/defender-for-containers-introduction", + "service": "ACR", "services": [ - "WAF", - "Monitor" + "ACR", + "Defender", + "WAF" ], - "severity": "High", - "text": "Ensure alerts are configured for Azure Service Health alerts and notifications", - "waf": "Operations" + "severity": "Low", + "text": "Enable Defender for Containers to scan Azure Container Registry for vulnerabilities", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "b6abad38-aad5-43cc-99e1-d86667357c54", - "service": "AVS", + "description": "Deploy trusted code that was validated and scanned for vulnerabilities according to DevSecOps practices.", + "guid": "4451e1a2-d345-4293-a763-9637a551c5c0", + "service": "ACR", "services": [ - "Storage", - "AVS", "WAF" ], "severity": "Medium", - "text": "Configure Azure VMware Solution logging to be send to an Azure Storage account or Azure EventHub for processing", - "waf": "Operations" + "text": "Deploy validated container images", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "microsoft.containerregistry/registries", "checklist": "WAF checklist", - "guid": "9674c5ed-85b8-459c-9733-be2b1a27b775", - "service": "AVS", + "description": "Use the latest versions of supported platforms, programming languages, protocols, and frameworks.", + "guid": "4e401955-387e-45ce-b126-cd132af5b20c", + "service": "ACR", "services": [ - "AVS", "WAF" ], - "severity": "Low", - "text": "If deep insight in VMware vSphere is required: Is vRealize Operations and/or vRealize Network Insights used in the solution?", - "waf": "Operations" + "severity": "High", + "text": "Use up-to-date platforms, languages, protocols and frameworks", + "waf": "Security" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "a91be1f3-88f0-43a4-b2cd-463cbbbc8682", - "service": "AVS", + "description": "Using the correct approach to feed a datalake with cold data and having the Kusto query engine at your disposal at the same time, as in the short-term storage", + "guid": "ba7da7be-9951-4914-a384-5d997cb39132", + "link": "https://learn.microsoft.com/azure/data-explorer/kusto/management/data-export/continuous-data-export", + "service": "Azure Data Explorer", "services": [ - "AzurePolicy", + "Cost", "Storage", - "WAF", - "VM" + "WAF" ], - "severity": "High", - "text": "Ensure the vSAN storage policy for VM's is NOT the default storage policy as this policy applies thick provisioning", - "waf": "Operations" + "text": "Leverage External Tables and Continuous data export overview to reduce costs", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "d9ef1d5e-832d-442e-9611-c818b0afbc51", - "service": "AVS", + "description": "Azure Data Explorer provides an optional follower capability for a leader cluster to be followed by other follower clusters for read-only access to the leader's data and metadata. Changes in the leader, such as create, append, and drop are automatically synchronized to the follower. While the leaders could span Azure regions, the follower clusters should be hosted in the same region(s) as the leader. If the leader cluster is down or databases or tables are accidentally dropped, the follower clusters will lose access until access is recovered in the leader.", + "guid": "56a22586-f490-4641-addd-ea8a377cdeb3", + "link": "https://learn.microsoft.com/azure/data-explorer/follower?tabs=csharp", + "service": "Azure Data Explorer", "services": [ + "Storage", "WAF" ], - "severity": "Medium", - "text": "Ensure vSphere content libraries are not placed on vSAN as vSAN is a finite resource", - "waf": "Operations" + "text": "To share data, explore Leader-follower cluster configuration", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "0e43a18a-9cd2-489b-bd6b-17db8255461e", - "service": "AVS", + "description": "Azure Data Explorer doesn't support automatic protection against the outage of an entire Azure region. This disruption can happen during a natural disaster, like an earthquake. If you require a solution for a disaster recovery situation, do the following steps to ensure business continuity. In these steps, you'll replicate your clusters, management, and data ingestion in two Azure paired regions.", + "guid": "861bb2bc-14ae-4a6e-95d8-d9a3adc218e6", + "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-create-solution#create-multiple-independent-clusters", + "service": "Azure Data Explorer", "services": [ - "Storage", - "WAF", - "Backup" + "ASR", + "WAF" ], - "severity": "Medium", - "text": "Ensure data repositories for the backup solution are stored outside of vSAN storage. Either in Azure native or on a disk pool-backed datastore", - "waf": "Operations" + "text": "To protect against regional failure, create Multiple independent clusters, preferably in two Azure Paired regions", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "2aee3453-aec8-4339-848b-262d6cc5f512", - "service": "AVS", + "guid": "436b0635-cb45-4e57-a603-324ace8cc123", + "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-create-solution#replicate-management-activities", + "service": "Azure Data Explorer", "services": [ - "AVS", - "WAF", - "Arc" + "Storage", + "RBAC", + "WAF" ], - "severity": "Medium", - "text": "Ensure workloads running on Azure VMware Solution are hybrid managed using Azure Arc for Servers (Arc for Azure VMware Solution is in preview)", - "waf": "Operations" + "text": "Replicate all management activities such as creating new tables or managing user roles on each cluster.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "925398e6-da9d-437d-ac43-bc6cd1d79a9b", - "service": "AVS", + "guid": "18ca6017-0265-4f4b-a46a-393af7f31728", + "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-create-solution", + "service": "Azure Data Explorer", "services": [ - "AVS", - "WAF", - "Monitor" + "WAF" ], - "severity": "Medium", - "text": "Ensure workloads running on Azure VMware Solution are monitored using Azure Log Analytics and Azure Monitor", - "waf": "Operations" + "text": "Ingest data into each cluster in parallel", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "24604489-a8f4-42d7-ae78-cb6a33bd2a09", - "service": "AVS", + "description": "This configuration is also called 'always-on'. For critical application deployments with no tolerance for outages, you should use multiple Azure Data Explorer clusters across Azure paired regions.", + "guid": "58a9c279-9c42-4bb6-9d0c-65556246b338", + "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#active-active-active-configuration", + "service": "Azure Data Explorer", "services": [ - "AVS", + "ACR", "WAF" ], - "severity": "Medium", - "text": "Include workloads running on Azure VMware Solution in existing update management tooling or in Azure Update Management", - "waf": "Operations" + "text": "For critical application with no tolerance for outages, create Active-Active-Active (always-on) configuration", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "17e7a8d9-0ae0-4e27-aee2-9711bd352caa", - "service": "AVS", + "description": "This configuration is identical to the active-active-active configuration, but only involves two Azure paired regions. Configure dual ingestion, processing, and curation. Users are routed to the nearest region. The cluster SKU must be the same across regions.", + "guid": "563a4dc7-4a74-48b6-922a-d190916a6649", + "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#active-active-configuration", + "service": "Azure Data Explorer", "services": [ - "AzurePolicy", - "AVS", - "WAF", - "Monitor" + "ACR", + "WAF" ], - "severity": "Medium", - "text": "Use Azure Policy to onboard Azure VMware Solution workloads in the Azure Management, Monitoring and Security solutions", - "waf": "Operations" + "text": "For critical applications, create Active-Active configuration in two paired regions", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "aee3553a-fc83-4392-98b2-62d6cc5f5129", - "service": "AVS", + "description": "The Active-Hot configuration is similar to the Active-Active configuration in dual ingest, processing, and curation. While the standby cluster is online for ingestion, process, and curation, it isn't available to query. The standby cluster doesn't need to be in the same SKU as the primary cluster. It can be of a smaller SKU and scale, which may result in it being less performant. In a disaster scenario, users are redirected to the standby cluster, which can optionally be scaled up to increase performance.", + "guid": "8fadfe27-7de2-483b-8ac3-52baa9b75708", + "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#active-hot-standby-configuration", + "service": "Azure Data Explorer", "services": [ - "AVS", - "WAF", - "Defender" + "WAF" ], - "severity": "Medium", - "text": "Ensure workloads running on Azure VMware Solution are onboarded to Microsoft Defender for Cloud", - "waf": "Security" + "text": "For applications, which required only read during failure, create Active-Hot standby configuration", + "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "25398e6d-b9d3-47da-a43b-c6cd1d79a9b2", - "service": "AVS", + "description": "This solution offers the least resiliency (highest RPO and RTO), is the lowest in cost and highest in effort. In this configuration, there's no data recovery cluster. Configure continuous export of curated data (unless raw and intermediate data is also required) to a storage account that is configured GRS (Geo Redundant Storage). A data recovery cluster is spun up if there is a disaster recovery scenario. At that time, DDLs, configuration, policies, and processes are applied. Data is ingested from storage with the ingestion property kustoCreationTime to over-ride the ingestion time that defaults to system time.", + "guid": "49aa8092-dc8e-4b9d-8bb7-3b26a5a67eba", + "link": "https://learn.microsoft.com/azure/data-explorer/business-continuity-overview#on-demand-data-recovery-configuration", + "service": "Azure Data Explorer", "services": [ + "Cost", + "ASR", + "Storage", "WAF", - "Backup" + "AzurePolicy" ], - "severity": "Medium", - "text": "Ensure backups are not stored on vSAN as vSAN is a finite resource", + "text": "For applications, where cost is a concern and can withstand some downtime during failure, create on-demand data recovery cluster configuration", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "5e6bfbb9-ed50-4354-9cc4-47e826028a71", - "service": "AVS", + "description": "All database objects, policies, and configurations should be persisted in source control so they can be released to the cluster from your release automation tool.", + "guid": "5a907e1e-348e-4f25-9c27-d32e8bbac757", + "link": "https://learn.microsoft.com/azure/data-explorer/devops", + "service": "Azure Data Explorer", "services": [ + "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "Have all DR solutions been considered and a solution that is best for your business been decided upon? [SRM/JetStream/Zerto/Veeam/...]", + "text": "Wrap DevOps and source control around all your code", + "training": "https://learn.microsoft.com/learn/paths/secure-your-cloud-data/", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "f0f1cac6-d9ef-41d5-b832-d42e3611c818", - "service": "AVS", + "guid": "1559ab91-53e8-4908-ae28-b84c33b6b780", + "link": "https://learn.microsoft.com/azure/data-explorer/devops", + "service": "Azure Data Explorer", "services": [ - "ASR", "WAF" ], - "severity": "Medium", - "text": "Use Azure Site Recovery when the Disaster Recovery technology is native Azure IaaS", + "text": "Design, develop, and implement validation routines to ensure all clusters are in-sync from a data perspective.", + "training": "https://learn.microsoft.com/learn/modules/azure-active-directory/", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.Kusto/clusters", "checklist": "WAF checklist", - "guid": "b0afbc51-0e43-4a18-a9cd-289bed6b17db", - "service": "AVS", + "guid": "8b9fe5c4-1049-4d40-9a82-2c3474d00f18", + "link": "https://learn.microsoft.com/azure/data-explorer/devops", + "service": "Azure Data Explorer", "services": [ "WAF" ], - "severity": "High", - "text": "Use Automated recovery plans with either of the Disaster solutions, avoid manual tasks as much as possible", + "text": "Be fully cognizant of what it takes to build a cluster from scratch. Leverage Infrastructure as a Code for your deployments", + "training": "https://learn.microsoft.com/learn/modules/implement-hybrid-identity-windows-server/", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "8255461e-2aee-4345-9aec-8339248b262d", - "service": "AVS", + "guid": "ab91932c-9fc9-4d1b-a881-37f5e6c0cb9e", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/paas-foundations-playbooks-ADF_v1.docx", + "service": "Azure Data Factory", "services": [ - "ASR", "WAF" ], "severity": "Medium", - "text": "Use the geopolitical region pair as the secondary disaster recovery environment", + "text": "Leverage FTA Resiliency Playbook for Azure Data Factory", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "6cc5f512-9253-498e-9da9-d37dac43bc6c", - "service": "AVS", + "guid": "e503547c-d447-4e82-9138-a7200f1cac6d", + "link": "https://learn.microsoft.com/azure/architecture/example-scenario/analytics/pipelines-disaster-recovery", + "service": "Azure Data Factory", "services": [ "WAF" ], "severity": "High", - "text": "Use 2 different address spaces between the regions, for example: 10.0.0.0/16 and 192.168.0.0/16 for the different regions", + "text": "Use zone redundant pipelines in regions that support Availability Zones", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "d1d79a9b-2460-4448-aa8f-42d78e78cb6a", - "service": "AVS", + "guid": "9ef1d6e8-32e5-42e3-911c-818b1a0bc511", + "link": "https://learn.microsoft.com/azure/data-factory/source-control", + "service": "Azure Data Factory", "services": [ - "NVA", - "AVS", - "ExpressRoute", + "Backup", "WAF" ], "severity": "Medium", - "text": "Will ExpressRoute Global Reach be used for connectivity between the primary and secondary Azure VMware Solution Private Clouds or is routing done through network virtual appliances?", + "text": "Use DevOps to Backup the ARM templates with Github/Azure DevOps integration ", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "33bd2a09-17e7-4a8d-a0ae-0e27cee29711", - "service": "AVS", + "guid": "e43a18a9-cd29-49cf-b7b1-7db8255562f2", + "link": "https://learn.microsoft.com/azure/architecture/example-scenario/analytics/pipelines-disaster-recovery", + "service": "Azure Data Factory", "services": [ - "WAF", - "Backup" + "VM", + "WAF" ], "severity": "Medium", - "text": "Have all Backup solutions been considered and a solution that is best for your business been decided upon? [ MABS/CommVault/Metallic.io/Veeam/�. ]", + "text": "Make sure you replicate the Self-Hosted Integration Runtime VMs in another region ", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "bd352caa-ab79-4b18-adab-81932c9fc9d1", - "service": "AVS", + "guid": "aee4563a-fd83-4393-98b2-62d6dc5f512a", + "link": "https://learn.microsoft.com/azure/architecture/example-scenario/analytics/pipelines-disaster-recovery", + "service": "Azure Data Factory", "services": [ - "AVS", - "WAF", - "Backup" + "VNet", + "WAF" ], "severity": "Medium", - "text": "Deploy your backup solution in the same region as your Azure VMware Solution private cloud", + "text": "Make sure you replicate or duplicate your network in the sister region. You have to make a copy of your Vnet in another region", "waf": "Reliability" }, { - "arm-service": "Microsoft.AVS/privateClouds", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "bb77036f-5e6b-4fbb-aed5-03547cc447e8", - "service": "AVS", + "description": "If your ADF Pipelines use Key Vault you don't have to do anything to replicate Key Vault. Key Vault is a managed service and Microsoft takes care of it for you", + "guid": "25498f6d-bad3-47da-a43b-c6ce1d7aa9b2", + "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance", + "service": "Azure Data Factory", "services": [ - "WAF", - "Backup" + "AKV", + "WAF" ], - "severity": "Medium", - "text": "Deploy your backup solution outside of vSan, on Azure native components", + "severity": "Low", + "text": "If using Keyvault integration, use SLA of Keyvault to understand your availablity", "waf": "Reliability" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "26028a71-f0f1-4cac-9d9e-f1d5e832d42e", + "guid": "32e42e36-11c8-418b-8a0b-c510e43a18a9", "service": "AVS", "services": [ - "AVS", + "Subscriptions", + "Entra", "WAF" ], - "severity": "Low", - "text": "Is a process in place to request a restore of the VMware components managed by the Azure Platform?", - "waf": "Reliability" + "severity": "High", + "text": "Ensure ADDS domain controller(s) are deployed in the identity subscription in native Azure", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "4604489a-8f42-4d78-b78c-b7a33bd2a0a1", + "guid": "75089c20-990d-4927-b105-885576f76fc2", "service": "AVS", "services": [ + "AVS", "WAF" ], - "severity": "Low", - "text": "For manual deployments, all configuration and deployments must be documented", - "waf": "Operations" + "severity": "Medium", + "text": "Ensure ADDS sites and services is configured to keep authentication requests from Azure-based resources (including Azure VMware Solution) local to Azure", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "7e7a8d90-ae0e-437c-be29-711bd352caaa", + "guid": "de3aad1e-7c28-4ec9-9666-b7570449aa80", "service": "AVS", "services": [ - "AVS", "WAF" ], - "severity": "Low", - "text": "For manual deployments, consider implementing resource locks to prevent accidental actions on your Azure VMware Solution Private Cloud", - "waf": "Operations" + "severity": "High", + "text": "Ensure that vCenter is connected to ADDS to enable authentication based on 'named user accounts'", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "b79b198d-ab81-4932-a9fc-9d1bb78036f5", + "guid": "cd289ced-6b17-4db8-8554-61e2aee3553a", "service": "AVS", "services": [ "WAF" ], - "severity": "Low", - "text": "For automated deployments, deploy a minimal private cloud and scale as needed", - "waf": "Operations" + "severity": "Medium", + "text": "Ensure that the connection from vCenter to ADDS is using a secure protocol (LDAPS)", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "e6bfbb9e-d503-4547-ac44-7e826128a71f", + "guid": "b9d37dac-43bc-46cd-8d79-a9b24604489a", "service": "AVS", "services": [ "WAF" ], - "severity": "Low", - "text": "For automated deployments, request or reserve quota prior to starting the deployment", - "waf": "Operations" + "severity": "Medium", + "text": "CloudAdmin account in vCenter IdP is used only as an emergency account (break-glass)", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "0f1cac6d-9ef1-4d5e-a32e-42e3611c818b", + "guid": "53d88e89-d17b-473b-82a5-a67e7a9ed5b3", "service": "AVS", "services": [ - "AzurePolicy", + "Entra", "WAF" ], - "severity": "Low", - "text": "For automated deployment, ensure that relevant resource locks are created through the automation or through Azure Policy for proper governance", - "waf": "Operations" + "severity": "High", + "text": "Ensure that NSX-Manager is integrated with an external Identity provider (LDAPS)", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "e2cc95d4-8c6b-4791-bca0-f6c56589e558", + "guid": "ae0e37ce-e297-411b-b352-caaab79b198d", "service": "AVS", "services": [ - "AKV", + "RBAC", + "AVS", "WAF" ], - "severity": "Low", - "text": "Implement human understandable names for ExR authorization keys to allow for easy identification of the keys purpose/use", - "waf": "Operations" + "severity": "Medium", + "text": "Has an RBAC model been created for use within VMware vSphere", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "255461e2-aee3-4553-afc8-339248b262d6", + "guid": "ab81932c-9fc9-4d1b-a780-36f5e6bfbb9e", "service": "AVS", "services": [ - "AKV", - "AVS", - "ExpressRoute", + "RBAC", "WAF" ], - "severity": "Low", - "text": "Use Key vault to store secrets and authorization keys when separate Service Principles are used for deploying Azure VMware Solution and ExpressRoute", - "waf": "Operations" + "severity": "Medium", + "text": "RBAC permissions should be granted on ADDS groups and not on specific users", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "cc5f5129-2539-48e6-bb9d-37dac43bc6cd", + "guid": "d503547c-c447-4e82-9128-a71f0f1cac6d", "service": "AVS", "services": [ + "RBAC", "AVS", "WAF" ], - "severity": "Low", - "text": "Define resource dependencies for serializing actions in IaC when many resources need to be deployed in/on Azure VMware Solution as Azure VMware Solution only supports a limited number of parallel operations.", - "waf": "Operations" + "severity": "High", + "text": "RBAC permissions on the Azure VMware Solution resource in Azure are 'locked down' to a limited set of owners only", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "1d79a9b2-4604-4489-a8f4-2d78e78cb7a3", + "guid": "fd9f0df4-68dc-4976-b9a9-e6a79f7682c5", "service": "AVS", "services": [ + "RBAC", "WAF" ], - "severity": "Low", - "text": "When performing automated configuration of NSX-T segments with a single Tier-1 gateway, use Azure Portal APIs instead of NSX-Manager APIs", - "waf": "Operations" + "severity": "High", + "text": "Ensure all custom roles are scoped with CloudAdmin permitted authorizations", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "3bd2a0a1-7e7a-48d9-8ae0-e37cee29711b", + "guid": "9ef1d5e8-32e4-42e3-911c-818b0a0bc510", + "link": "https://github.com/Azure/AzureCAT-AVS/tree/main/networking", "service": "AVS", "services": [ "AVS", - "Subscriptions", "WAF" ], - "severity": "Medium", - "text": "When intending to use automated scale-out, be sure to apply for sufficient Azure VMware Solution quota for the subscriptions running Azure VMware Solution", + "severity": "High", + "text": "Is the correct Azure VMware Solution connectivity model selected for the customer use case at hand", "waf": "Performance" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "d352caaa-b79b-4198-bab8-1932c9fc9d1b", + "guid": "eb710a37-cbc1-4055-8dd5-a936a8bb7cf5", "service": "AVS", "services": [ - "AzurePolicy", - "Storage", - "WAF" + "ExpressRoute", + "Monitor", + "VPN", + "WAF", + "NetworkWatcher" ], - "severity": "Medium", - "text": "When intending to use automated scale-in, be sure to take storage policy requirements into account before performing such action", - "waf": "Performance" + "severity": "High", + "text": "Ensure ExpressRoute or VPN connections from on-premises to Azure are monitored using 'connection monitor'", + "waf": "Operations" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "b78036f5-e6bf-4bb9-bd50-3547cc447e82", + "guid": "976e24f2-a7f8-426c-9253-2a92a2a7ed99", "service": "AVS", "services": [ - "WAF" + "ExpressRoute", + "AVS", + "Monitor", + "WAF", + "VM", + "NetworkWatcher" ], "severity": "Medium", - "text": "Scaling operations always need to be serialized within a single SDDC as only one scale operation can be performed at a time (even when multiple clusters are used)", - "waf": "Performance" + "text": "Ensure a connection monitor is created from an Azure native resource to an Azure VMware Solution virtual machine to monitor the Azure VMware Solution back-end ExpressRoute connection", + "waf": "Operations" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "bf15bce2-19e4-4a0e-a588-79424d226786", + "guid": "f41ce6a0-64f3-4805-bc65-3ab50df01265", "service": "AVS", "services": [ - "WAF" + "Monitor", + "AVS", + "WAF", + "VM", + "NetworkWatcher" ], "severity": "Medium", - "text": "Consider and validate scaling operations on 3rd party solutions used in the architecture (supported or not)", - "waf": "Performance" + "text": "Ensure a connection monitor is created from an on-premises resource to an Azure VMware Solution virtual machine to monitor end-2-end connectivity", + "waf": "Operations" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "d20b56c5-7be5-4851-a0f8-3835c586cb29", + "guid": "563b4dc7-4a74-48b6-933a-d1a0916a6649", "service": "AVS", "services": [ + "ARS", "WAF" ], - "severity": "Medium", - "text": "Define and enforce scale in/out maximum limits for your environment in the automations", - "waf": "Performance" + "severity": "High", + "text": "When route server is used, ensure no more then 1000 routes are propagated from route server to ExR gateway to on-premises (ARS limit).", + "waf": "Operations" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "1dc15a1c-075e-4e9f-841a-cccd579376bc", + "guid": "6128a71f-0f1c-4ac6-b9ef-1d5e832e42e3", "service": "AVS", "services": [ - "WAF", - "Monitor" + "RBAC", + "AVS", + "Entra", + "WAF" ], - "severity": "Medium", - "text": "Implement monitoring rules to monitor automated scaling operations and monitor success and failure to enable appropriate (automated) responses", - "waf": "Operations" + "severity": "High", + "text": "Is Privileged Identity Management implemented for roles managing the Azure VMware Solution resource in the Azure Portal (no standing permissions allowed)", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "c5972cd4-cd21-4b07-9036-f5e6b4bfd3d5", - "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy#how-application-proxy-works", + "guid": "c4e2436b-b336-4d71-9f17-960eee0b9b5c", "service": "AVS", "services": [ - "VM", + "RBAC", + "AVS", + "Entra", "WAF" ], "severity": "High", - "text": "When using MON, be aware of the limits of simulataneously configured VMs (MON Limit for HCX [400 - standard, 1000 - Larger appliance])", - "training": "https://learn.microsoft.com/learn/modules/configure-azure-ad-application-proxy/", - "waf": "Reliability" + "text": "Privileged Identity Management audit reporting should be implemented for the Azure VMware Solution PIM roles", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "be1f38cf-03a8-422b-b463-cbbbc8ac299e", - "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy#how-application-proxy-works", + "guid": "78c447a8-26b2-4863-af0f-1cac599ef1d5", "service": "AVS", "services": [ + "AVS", + "Entra", "WAF" ], - "severity": "High", - "text": "When using MON, you cannot enable MON on more than 100 Network extensions", - "training": "https://learn.microsoft.com/learn/paths/implement-applications-external-access-azure-ad/", - "waf": "Reliability" + "severity": "Medium", + "text": "If using Privileged Identity Management is being used, ensure that a valid Entra ID enabled account is created with a valid SMTP record for Azure VMware Solution Automatic Host replacement notifications. (standing permissions required)", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "bc91a43d-90da-4e2c-a881-4706f7c1cbaf", + "guid": "8defc4d7-21d3-41d2-90fb-707ae9eab40e", "service": "AVS", "services": [ - "VPN", "WAF" ], - "severity": "Medium", - "text": "If using a VPN connection for migrations, adjust your MTU size accordingly.", - "waf": "Performance" + "severity": "High", + "text": "Limit use of CloudAdmin account to emergency access only", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "e614658d-d457-4e92-9139-b821102cad6e", + "guid": "d329f798-bc17-48bd-a5a0-6ca7144351d1", "service": "AVS", "services": [ + "RBAC", "WAF" ], "severity": "Medium", - "text": "For low connectivity regions connecting into Azure (500Mbps or less), considering deploying the HCX WAN optimization appliance", - "waf": "Performance" + "text": "Create custom RBAC roles in vCenter to implement a least-privilege model inside vCenter", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "ae01e6e8-43e5-42f4-922d-928c1b1cd521", + "guid": "9dd24429-eb72-4281-97a1-51c5bb4e4f18", "service": "AVS", "services": [ "WAF" ], "severity": "Medium", - "text": "Ensure that migrations are started from the on-premises appliance and NOT from the Cloud appliance (do NOT perform a reverse migration)", - "waf": "Reliability" + "text": "Is a process defined to regularly rotate cloudadmin (vCenter) and admin (NSX) credentials", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "e54a29a9-de39-4ac0-b7c2-8dc935657202", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings", + "guid": "586cb291-ec16-4a1d-876e-f9f141acdce5", "service": "AVS", "services": [ - "Storage", "VM", "AVS", + "Entra", "WAF" ], - "severity": "Medium", - "text": "When Azure Netapp Files is used to extend storage for Azure VMware Solution,consider using this as a VMware datastore instead of attaching directly to a VM.", - "waf": "Reliability" + "severity": "High", + "text": "Use a centralized identity provider to be used for workloads (VM's) running on Azure VMware Solution", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "bff4564b-0d93-44a3-98b2-63e7dd60513a", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#avoid-combining-traffic-manager-and-front-door", + "guid": "79377bcd-b375-41ab-8ab0-ead66e15d3d4", "service": "AVS", "services": [ - "Storage", - "ExpressRoute", "WAF" ], "severity": "Medium", - "text": "Ensure that a dedicated ExpressRoute Gateway is being used for external data storage solutions", - "waf": "Reliability" + "text": "Is East-West traffic filtering implemented within NSX-T", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "3649906e-bad3-48ea-b53c-c7de1d8aaab3", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-the-same-domain-name-on-front-door-and-your-origin", + "guid": "a2adb1c3-d232-46af-825c-a44e1695fddd", "service": "AVS", "services": [ - "Storage", - "ExpressRoute", + "AppGW", + "AVS", + "Firewall", "WAF" ], - "severity": "Medium", - "text": "Ensure that FastPath is enabled on the ExpressRoute Gateway that is being used for external data storage solutions", - "waf": "Reliability" + "severity": "High", + "text": "Workloads on Azure VMware Solution are not directly exposed to the internet. Traffic is filtered and inspected by Azure Application Gateway, Azure Firewall or 3rd party solutions", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "571549ab-8153-4d89-b89d-c7b33be2b1a2", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group", + "guid": "eace4cb1-deb4-4c65-8c3f-c14eeab36938", "service": "AVS", "services": [ - "ASR", + "AVS", "WAF" ], "severity": "High", - "text": "If using stretched cluster, ensure that your selected Disaster Recovery solution is supported by the vendor", - "waf": "Reliability" + "text": "Auditing and logging is implemented for inbound internet requests to Azure VMware Solution and Azure VMware Solution based workloads", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "4c486b6d-8bdc-4059-acf7-5ee8a1309888", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#select-good-health-probe-endpoints", + "guid": "29e3eec2-1836-487a-8077-a2b5945bda43", "service": "AVS", "services": [ + "Monitor", + "AVS", "WAF" ], - "severity": "High", - "text": "If using stretched cluster, ensure that the SLA provided will meet your requirements", - "waf": "Reliability" + "severity": "Medium", + "text": "Session monitoring is implemented for outbound internet connections from Azure VMware Solution or Azure VMware Solution based workloads to identify suspicious/malicious activity", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "9579d66b-896d-471f-a6ca-7be9955d04c3", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes", + "graph": "resources| where type =~ 'Microsoft.Network/virtualNetworkGateways'| mv-expand ipConfigurations=properties.ipConfigurations| project subnetId=tostring(ipConfigurations.properties.subnet.id)| where isnotempty(subnetId)| join (resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,enableDdosProtection=tostring(properties.enableDdosProtection),subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,enableDdosProtection,subnetId=tostring(subnets.id)) on subnetId | distinct id,resourceGroup,name,enableDdosProtection | project id, compliant = (enableDdosProtection == 'true')", + "guid": "334fdf91-c234-4182-a652-75269440b4be", "service": "AVS", "services": [ "ExpressRoute", - "WAF" + "WAF", + "VPN", + "VNet", + "DDoS" ], - "severity": "High", - "text": "If using stretched cluster, ensure that both ExpressRoute circuits are connected to your connectivity hub.", - "waf": "Reliability" + "severity": "Medium", + "text": "Is DDoS standard protection enabled on ExR/VPN Gateway subnet in Azure", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "c49d987c-b3d1-4325-aa12-4b6e4d0685ed", - "link": "https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity", + "guid": "3d3e0843-276d-44bd-a015-bcf219e4a1eb", "service": "AVS", "services": [ - "ExpressRoute", + "AVS", "WAF" ], - "severity": "High", - "text": "If using stretched cluster, ensure that both ExpressRoute circuits have GlobalReach enabled.", - "waf": "Reliability" + "severity": "Medium", + "text": "Use a dedicated privileged access workstation (PAW) to manage Azure VMware Solution, vCenter, NSX manager and HCX manager", + "waf": "Security" }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "dce9793b-7bcd-4b3b-91eb-2ec14eea6e59", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates", + "guid": "9ccbd869-266a-4cca-874f-aa19bf39d95d", "service": "AVS", "services": [ + "Defender", + "AVS", "WAF" ], - "severity": "High", - "text": "Have site disaster tolerance settings been properly considered and changed for your business if needed.", - "waf": "Reliability" + "severity": "Medium", + "text": "Enable Advanced Threat Detection (Microsoft Defender for Cloud aka ASC) for workloads running on Azure VMware Solution", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "4238f409-2ea0-43be-a06b-2a993c98aa7b", - "link": "https://learn.microsoft.com/en-us/azure/azure-functions/functions-scale#overview-of-plans", - "service": "Azure Functions", + "guid": "44c7c891-9ca1-4f6d-9315-ae524ba34d45", + "service": "AVS", "services": [ + "Arc", + "AVS", "WAF" ], - "severity": "High", - "text": "Select the right Function hosting plan based on your business & SLO requirements", - "waf": "Reliability" + "severity": "Medium", + "text": "Use Azure ARC for Servers to properly govern workloads running on Azure VMware Solution using Azure native technologies (Azure ARC for Azure VMware Solution is not yet available)", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "a9808100-d640-4f77-ac56-1ec0600f6752", - "link": "https://learn.microsoft.com/en-us/azure/azure-functions/functions-scale#overview-of-plans", - "query": "resources | where type =~ 'Microsoft.Web/sites' and kind has 'functionapp' and tolower(kind) !contains 'workflow' | extend aspResourceId = tostring(properties.serverFarmId), managedEnvId = tostring(properties.managedEnvironmentId), sku = tostring(properties.sku) | extend sku = iif(isnotempty(sku), sku, iif(isnotempty(managedEnvId), 'ContainerApps', '')) | where sku !in ('Dynamic', 'FlexConsumption', '') | extend aspName = tostring(split(aspResourceId, '/').[-1]), managedEnvName = tostring(split(managedEnvId, '/').[-1]) | extend HostingPlan = tostring(iif(isnotempty(aspName), aspName, managedEnvName)) | project functionAppName = name, functionAppId = id, HostingPlan, sku | join kind=inner ( resources | where type =~ 'Microsoft.Web/serverfarms' or type =~ 'Microsoft.App/managedEnvironments' | extend HostingPlan = tostring(name), zoneRedundant = tostring(properties.zoneRedundant), compliant = tobool(properties.zoneRedundant) | project HostingPlan, resourceId = id, zoneRedundant, compliant ) on HostingPlan | project functionAppName, functionAppId, sku, HostingPlan, resourceId, zoneRedundant, compliant", - "service": "Azure Functions", + "guid": "85e12139-bd7b-4b01-8f7b-95ef6e043e2a", + "service": "AVS", "services": [ + "AVS", + "SQL", "WAF" ], - "severity": "High", - "text": "Leverage Availability Zones where regionally applicable (not available for Consumption tier)", - "waf": "Reliability" + "severity": "Low", + "text": "Ensure workloads on Azure VMware Solution use sufficient data encryption during run-time (like in-guest disk encryption and SQL TDE). (vSAN encryption at rest is default)", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "5969d03e-eacf-4042-b127-73c55e3575fa", - "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-functions?tabs=azure-portal#cross-region-disaster-recovery-and-business-continuity", - "service": "Azure Functions", + "guid": "a3592718-e6e2-4051-9267-6ae46691e883", + "service": "AVS", "services": [ + "AKV", "WAF" ], - "severity": "Medium", - "text": "Consider a Cross-Region DR strategy for critical workloads", - "waf": "Reliability" + "severity": "Low", + "text": "When in-guest encryption is used, store encryption keys in Azure Key vault when possible", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "47a0aae0-d8a0-43b1-9791-e934dee3754c", - "link": "https://learn.microsoft.com/en-us/azure/app-service/environment/intro", - "service": "Azure Functions", + "guid": "5ac94222-3e13-4810-9230-81a941741583", + "service": "AVS", "services": [ - "AppSvc", + "AVS", "WAF" ], - "severity": "High", - "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", - "waf": "Reliability" + "severity": "Medium", + "text": "Consider using extended security update support for workloads running on Azure VMware Solution (Azure VMware Solution is eligible for ESU)", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "17232891-f89f-4eaa-90f1-3b34bf798ed5", - "link": "https://learn.microsoft.com/en-us/azure/azure-functions/dedicated-plan#always-on", - "query": "resources | where type =~ 'Microsoft.Web/sites' and kind has 'functionapp' | where tolower(kind) !contains 'workflow' | where isnotempty(properties.serverFarmId) | extend sku = tostring(properties.sku) | where isnotempty(sku) | where sku !in ('Dynamic', 'FlexConsumption', 'ElasticPremium') | extend alwaysOn = properties.siteConfig.alwaysOn | project functionAppName = name, functionAppId = id, serverFarmId = tostring(properties.serverFarmId), sku, alwaysOn, compliant = tobool(alwaysOn)", - "service": "Azure Functions", + "guid": "3ef7ad7c-6d37-4331-95c7-acbe44bbe609", + "service": "AVS", "services": [ - "AppSvc", "WAF" ], "severity": "High", - "text": "Ensure 'Always On' is enabled for all Function Apps running on App Service Plan", + "text": "Ensure that the appropriate vSAN Data redundancy method is used (RAID specification)", "waf": "Reliability" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "40a325c2-7c0e-49e6-86d8-c273b4dc21ba", - "link": "https://learn.microsoft.com/en-us/azure/azure-functions/storage-considerations?tabs=azure-cli#shared-storage-accounts", - "service": "Azure Functions", + "guid": "d88408f3-7273-44c8-96ba-280214590146", + "service": "AVS", "services": [ "Storage", + "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "Pair a Function App to its own storage account. Try not to re-use storage accounts for Function Apps unless they are tightly coupled", + "severity": "High", + "text": "Ensure that the Failure-to-tolerate policy is in place to meet your vSAN storage needs", "waf": "Reliability" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "bb42650c-257d-4cb0-822a-131138b8e6f0", - "link": "https://learn.microsoft.com/en-us/training/modules/deploy-azure-functions/", - "service": "Azure Functions", + "guid": "d89f2e87-7784-424d-9167-85c6fa95b96a", + "service": "AVS", "services": [ + "ASR", "WAF" ], - "severity": "Medium", - "text": "Leverage Azure DevOps or GitHub to streamline CI/CD and safeguard your Function App code", - "waf": "Operations" + "severity": "High", + "text": "Ensure that you have requested enough quota, ensuring you have considered growth and Disaster Recovery requirement", + "waf": "Reliability" }, { - "arm-service": "Microsoft.BotService/botServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "6ad48408-ee72-4734-a476-ba28fdcf590c", - "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-bot", - "service": "Bot service", + "guid": "5d38e53f-9ccb-4d86-a266-acca274faa19", + "service": "AVS", "services": [ "WAF" ], "severity": "Medium", - "text": "Follow reliability support recommendations in Azure Bot Service", - "waf": "Reliability" + "text": "Ensure that access constraints to ESXi are understood, there are access limits which might affect 3rd party solutions.", + "waf": "Operations" }, { - "arm-service": "Microsoft.BotService/botServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "e65de8e1-3f9c-4cbd-9682-66abca264f9a", - "link": "https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-concept-regionalization", - "service": "Bot service", + "guid": "bf39d95d-44c7-4c89-89ca-1f6d5315ae52", + "service": "AVS", "services": [ + "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Deploying bots with local data residency and regional compliance", - "waf": "Reliability" + "text": "Ensure that you have a policy around ESXi host density and efficiency, keeping in mind the lead time for requesting new nodes", + "waf": "Operations" }, { - "arm-service": "Microsoft.BotService/botServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "19bfe9d5-5d04-4c3c-9919-ca1b2d1215ae", - "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-bot#cross-region-disaster-recovery-in-multi-region-geography", - "service": "Bot service", + "guid": "4ba34d45-85e1-4213-abd7-bb012f7b95ef", + "service": "AVS", "services": [ + "Cost", + "AVS", "WAF" ], "severity": "Medium", - "text": "Azure Bot Service runs in active-active mode for both global and regional services. When an outage occurs, you don't need to detect errors or manage the service. Azure Bot Service automatically performs auto failover and auto recovery in a multi-region geographical architecture. For the EU bot regional service, Azure Bot Service provides two full regions inside Europe with active/active replication to ensure redundancy. For the global bot service, all available regions/geographies can be served as the global footprint.", - "waf": "Reliability" + "text": "Ensure a good cost management process is in place for Azure VMware Solution - Azure Cost Management can be used", + "waf": "Cost" }, { - "arm-service": "Microsoft.AppPlatform/Spring", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "6d8e32a8-3892-479d-a40b-10f6b4f6f298", - "link": "https://learn.microsoft.com/azure/spring-apps/concepts-blue-green-deployment-strategies", - "service": "Spring Apps", + "guid": "6e043e2a-a359-4271-ae6e-205172676ae4", + "service": "AVS", "services": [ + "Cost", + "AVS", "WAF" ], - "severity": "Medium", - "text": "Azure Spring Apps permits two deployments for every app, only one of which receives production traffic. You can achieve zero downtime with blue green deployment strategies. Blue green deployment is only available in Standard and Enterprise tiers. You could automate deployment using CI/CD with ADO/GitHub actions", - "waf": "Reliability" + "severity": "Low", + "text": "Are Azure reserved instances used to optimize cost for using Azure VMware Solution", + "waf": "Cost" }, { - "arm-service": "Microsoft.AppPlatform/Spring", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "fbcb40ac-9480-4a6d-bcf4-8081252a6716", - "link": "https://learn.microsoft.com/azure/architecture/web-apps/spring-apps/architectures/spring-apps-multi-region", - "service": "Spring Apps", + "guid": "6691e883-5ac9-4422-83e1-3810523081a9", + "service": "AVS", "services": [ - "TrafficManager", - "WAF", - "FrontDoor" + "WAF" ], "severity": "Medium", - "text": "Azure Spring Apps instances could be created in multiple regions for your applications and traffic could be routed by Traffic Manager/Front Door.", - "waf": "Reliability" + "text": "Consider the use of Azure Private-Link when using other Azure Native Services", + "waf": "Security" }, { - "arm-service": "Microsoft.AppPlatform/Spring", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "ff1ae6a7-9301-4feb-9d11-56cd72f1d4ef", - "link": "https://learn.microsoft.com/azure/reliability/reliability-spring-apps", - "service": "Spring Apps", + "guid": "db611712-6904-40b4-aa3d-3e0803276d4b", + "service": "AVS", "services": [ - "WAF", - "ACR" + "WAF" ], - "severity": "Medium", - "text": "In supported region, Azure Spring Apps can be deployed as zone redundant, which means that instances are automatically distributed across availability zones. This feature is only available in Standard and Enterprise tiers.", - "waf": "Reliability" + "severity": "High", + "text": "Ensure all required resource reside within the same Azure availability zone(s)", + "waf": "Performance" }, { - "arm-service": "Microsoft.AppPlatform/Spring", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "ffc735ad-fbb1-4802-b43f-ad6387c4c066", - "link": "https://learn.microsoft.com/azure/spring-apps/concept-understand-app-and-deployment", - "service": "Spring Apps", + "guid": "48b262d6-cc5f-4512-a253-98e6db9d37da", + "service": "AVS", "services": [ + "Defender", + "VM", + "AVS", "WAF" ], "severity": "Medium", - "text": "Use more than 1 app instance for your apps", - "waf": "Reliability" + "text": "Enable Microsoft Defender for Cloud for Azure VMware Solution guest VM workloads", + "waf": "Security" }, { - "arm-service": "Microsoft.AppPlatform/Spring", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "7504c230-6035-4183-95a5-85762acc6075", - "link": "https://learn.microsoft.com/azure/spring-apps/diagnostic-services", - "service": "Spring Apps", + "guid": "41741583-3ef7-4ad7-a6d3-733165c7acbe", + "service": "AVS", "services": [ - "WAF", - "Monitor" + "Arc", + "VM", + "AVS", + "WAF" ], "severity": "Medium", - "text": "Monitor Azure Spring Apps with logs, metrics and tracing. Integrate ASA with application insights and track failures and create workbooks.", - "waf": "Reliability" + "text": "Use Azure Arc enabled servers to manage your Azure VMware Solution guest VM workloads", + "waf": "Security" }, { - "arm-service": "Microsoft.AppPlatform/Spring", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "1eb48d58-3eec-4ef5-80b0-d2b0dde3f0c6", - "link": "https://learn.microsoft.com/azure/spring-apps/how-to-configure-enterprise-spring-cloud-gateway", - "service": "Spring Apps", + "guid": "88f03a4d-2cd4-463c-abbc-868295abc91a", + "service": "AVS", "services": [ + "AVS", "WAF" ], - "severity": "Medium", - "text": "Set up autoscaling in Spring Cloud Gateway", - "waf": "Reliability" + "severity": "High", + "text": "Enable Diagnostic and metric logging on Azure VMware Solution", + "waf": "Operations" }, { - "arm-service": "Microsoft.AppPlatform/Spring", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "97411607-b6fd-4335-99d1-9885faf4e392", - "link": "https://learn.microsoft.com/azure/spring-apps/how-to-setup-autoscale", - "service": "Spring Apps", + "guid": "4ed90dae-2cc8-44c4-9b6b-781cbafe6c46", + "service": "AVS", "services": [ + "VM", + "Monitor", + "AVS", "WAF" ], - "severity": "Low", - "text": "Enable autoscale for the apps with Standard consumption & dedicated plan.", - "waf": "Reliability" + "severity": "Medium", + "text": "Deploy the Log Analytics Agents to Azure VMware Solution guest VM workloads", + "waf": "Operations" }, { - "arm-service": "Microsoft.AppPlatform/Spring", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "dfcaffd1-d27c-4ef2-998d-64c1df3a7ac3", - "link": "https://learn.microsoft.com/azure/spring-apps/overview", - "service": "Spring Apps", + "guid": "589d457a-927c-4397-9d11-02cad6aae11e", + "service": "AVS", "services": [ - "WAF" + "AVS", + "Backup", + "WAF", + "VM", + "AzurePolicy" ], "severity": "Medium", - "text": "Use Enterprise plan for commercial support of spring boot for mission critical apps. With other tiers you get OSS support.", - "waf": "Reliability" + "text": "Ensure you have a documented and implemented backup policy and solution for Azure VMware Solution VM workloads", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Apply guidance from the Microsoft cloud security benchmark related to Storage", - "guid": "d237de14-3b16-4c21-b7aa-9b64604489a8", - "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/storage-security-baseline", - "service": "Azure Storage", + "guid": "ee29711b-d352-4caa-ab79-b198dab81932", + "service": "AVS", "services": [ - "Storage", + "Defender", + "Monitor", + "AVS", "WAF" ], "severity": "Medium", - "text": "Consider the 'Azure security baseline for storage'", + "text": "Use Microsoft Defender for Cloud for compliance monitoring of workloads running on Azure VMware Solution", "waf": "Security" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Azure Storage by default has a public IP address and is Internet-reachable. Private endpoints allow to securely expose Azure Storage only to those Azure Compute resources that need access, thus eliminating exposure to the public Internet", - "graph": "resources | where type =~ 'Microsoft.Storage/StorageAccounts' | where isnull(properties.privateEndpointConnections) or properties.privateEndpointConnections[0].properties.provisioningState != ('Succeeded') or (isnull(properties.networkAcls) and properties.publicNetworkAccess == 'Enabled') | extend compliant = (isnotnull(properties.privateEndpointConnections) and properties.privateEndpointConnections[0].properties.provisioningState == 'Succeeded' and properties.publicNetworkAccess == 'Disabled') | distinct id, compliant", - "guid": "f42d78e7-9d17-4a73-a22a-5a67e7a8ed4b", - "link": "https://learn.microsoft.com/azure/storage/common/storage-private-endpoints", - "service": "Azure Storage", + "guid": "c9fc9d1b-b780-436f-9e6b-fbb9ed503547", + "service": "AVS", "services": [ - "Storage", - "WAF", - "PrivateLink" + "Defender", + "WAF" ], - "severity": "High", - "text": "Consider using private endpoints for Azure Storage", + "severity": "Medium", + "text": "Are the applicable compliance baselines added to Microsoft Defender for Cloud", "waf": "Security" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Newly created storage accounts are created using the ARM deployment model, so that RBAC, auditing etc. are all enabled. Ensure that there are no old storage accounts with classic deployment model in a subscription", - "guid": "30e37c3e-2971-41b2-963c-eee079b598de", - "link": "https://learn.microsoft.com/azure/virtual-machines/migration-classic-resource-manager-overview#migration-of-storage-accounts", - "service": "Azure Storage", + "guid": "cc447e82-6128-4a71-b0f1-cac6d9ef1d5e", + "service": "AVS", "services": [ - "RBAC", - "Storage", - "Subscriptions", + "AVS", "WAF" ], - "severity": "Medium", - "text": "Ensure older storage accounts are not using 'classic deployment model'", + "severity": "High", + "text": "Was data residency evaluated when selecting Azure regions to use for Azure VMware Solution deployment", "waf": "Security" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Leverage Microsoft Defender to learn about suspicious activity and misconfigurations.", - "graph": "resources | where type =~ 'Microsoft.Storage/StorageAccounts' | project storageAccountId = id | join kind=leftouter (resourceContainers | where type == 'microsoft.security/pricings' | where name == 'StorageAccounts' | project resourceId = id, pricingTier = properties.pricingTier) on $left.storageAccountId == $right.resourceId | where isnull(pricingTier) or pricingTier != 'Standard' | extend compliant = false | distinct storageAccountId, compliant", - "guid": "fc5972cd-4cd2-41b0-a803-7f5e6b4bfd3d", - "link": "https://learn.microsoft.com/azure/storage/common/azure-defender-storage-configure", - "service": "Azure Storage", + "guid": "832e42e3-611c-4818-a0a0-bc510e43a18a", + "service": "AVS", "services": [ - "Storage", - "WAF", - "Defender" + "WAF" ], "severity": "High", - "text": "Enable Microsoft Defender for all of your storage accounts", + "text": "Are data processing implications (service provider / service consumer model) clear and documented", "waf": "Security" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "The soft-delete mechanism allows to recover accidentally deleted blobs.", - "guid": "503547c1-447e-4c66-828a-7100f1ce16dd", - "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-overview", - "service": "Azure Storage", + "guid": "547c1747-dc56-4068-a714-435cd19dd244", + "service": "AVS", "services": [ - "Storage", "WAF" ], "severity": "Medium", - "text": "Enable 'soft delete' for blobs", + "text": "Consider using CMK (Customer Managed Key) for vSAN only if needed for compliance reason(s).", "waf": "Security" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Consider selectively disabling 'soft delete' for certain blob containers, for example if the application must ensure that deleted information is immediately deleted, e.g. for confidentiality, privacy or compliance reasons. ", - "guid": "3f1d5e87-2e52-4e36-81cc-58b4a4b1510e", - "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-enable", - "service": "Azure Storage", + "guid": "e43a18a9-cd28-49ce-b6b1-7db8255461e2", + "service": "AVS", "services": [ - "Storage", + "Monitor", + "AVS", "WAF" ], - "severity": "Medium", - "text": "Disable 'soft delete' for blobs", - "waf": "Security" + "severity": "High", + "text": "Create dashboards to enable core Azure VMware Solution monitoring insights", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Soft delete for containers enables you to recover a container after it has been deleted, for example recover from an accidental delete operation.", - "guid": "43a58a9c-2289-4c3d-9b57-d0c655462f2a", - "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-container-overview", - "service": "Azure Storage", + "graph": "resources| where type =~ 'Microsoft.AVS/privateClouds'| join kind=leftouter(resources| where type =~ 'Microsoft.Insights/metricalerts'| mv-expand scopes=properties.scopes| mv-expand criteria=properties.criteria.allOf| extend metricName=criteria.metricName| distinct tostring(scopes), tostring(metricName))on $left.id == $right.scopes| extend compliant=toint(metricName in ('UsageAverage', 'EffectiveCpuAverage', 'DiskUsedPercentage'))| summarize compliant=min(compliant) by id", + "guid": "6b84ee5d-f47d-42d9-8881-b1cd5d1e54a2", + "service": "AVS", "services": [ + "Monitor", + "AVS", "WAF" ], "severity": "High", - "text": "Enable 'soft delete' for containers", - "waf": "Security" + "text": "Create warning alerts for critical thresholds for automatic alerting on Azure VMware Solution performance (CPU >80%, Avg Memory >80%, vSAN >70%)", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Consider selectively disabling 'soft delete' for certain blob containers, for example if the application must ensure that deleted information is immediately deleted, e.g. for confidentiality, privacy or compliance reasons. ", - "guid": "3e3453a3-c863-4964-ab65-2d6c15f51296", - "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-container-enable", - "service": "Azure Storage", + "graph": "resources| where type =~ 'Microsoft.AVS/privateClouds'| join kind=leftouter(resources| where type =~ 'Microsoft.Insights/metricalerts'| mv-expand scopes=properties.scopes| mv-expand criteria=properties.criteria.allOf| extend metricName=criteria.metricName| distinct tostring(scopes), tostring(metricName))on $left.id == $right.scopes| extend compliant=toint(metricName in ('UsageAverage', 'EffectiveCpuAverage', 'DiskUsedPercentage'))| summarize compliant=min(compliant) by id", + "guid": "9659e396-80e7-4828-ac93-5657d02bff45", + "service": "AVS", "services": [ - "Storage", + "Monitor", + "AVS", "WAF" ], - "severity": "Medium", - "text": "Disable 'soft delete' for containers", - "waf": "Security" + "severity": "High", + "text": "Ensure critical alert is created to monitor if vSAN consumption is below 75% as this is a support threshold from VMware", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Prevents accidental deletion of a storage account, by forcing the user to first remove the deletion lock, prior to deletion", - "guid": "5398e6de-d227-4dd1-92b0-6c21d7999a64", - "link": "https://learn.microsoft.com/azure/storage/common/lock-account-resource", - "service": "Azure Storage", + "graph": "resources| distinct subscriptionId| join kind=leftouter( resources | where type =~ 'microsoft.insights/activitylogalerts' | mv-expand condition1 = properties.condition.allOf | mv-expand condition2 = condition1.anyOf | extend alertEnabled = tostring(properties.enabled) | summarize set_condition1=make_set(condition1.equals), set_condition2=make_set(condition2.equals) by id, name,type,tenantId,resourceGroup,subscriptionId, alertEnabled | where set_has_element(set_condition1, 'ServiceHealth') | extend category = 'ServiceHealth' | extend all = iff(set_has_element(set_condition1, 'ServiceHealth') and array_length(set_condition2) == 0, true, false) | extend incident = iff(all, true, iff(set_has_element(set_condition1, 'Incident'), true, set_has_element(set_condition2, 'Incident'))) | extend maintenance = iff(all, true, iff(set_has_element(set_condition1, 'Maintenance'), true, set_has_element(set_condition2, 'Maintenance'))) | extend informational = iff(all, true, iff(set_has_element(set_condition1, 'Informational') or set_has_element(set_condition1, 'ActionRequired'), true, set_has_element(set_condition2, 'Informational') or set_has_element(set_condition2, 'ActionRequired'))) | extend security = iff(all, true, iff(set_has_element(set_condition1, 'Security'), true, set_has_element(set_condition2, 'Security'))) | project id, name, subscriptionId, category, tostring(alertEnabled), tostring(incident), tostring(maintenance), tostring(informational), tostring(security) | summarize count_alertEnabled=countif(alertEnabled == 'true'), count_incident=countif(incident == 'True'), count_maintenance=countif(maintenance == 'True'), count_informational=countif(informational == 'True'), count_security=countif(security == 'True') by subscriptionId) on subscriptionId| project subscriptionId, alertEnabled=iff(isnotnull(count_alertEnabled), count_alertEnabled, 0), incident=iff(isnotnull(count_incident), count_incident, 0), security=iff(isnotnull(count_security), count_security, 0), maintenance=iff(isnotnull(count_maintenance), count_maintenance, 0), informational=iff(isnotnull(count_informational), count_informational, 0)| order by incident, maintenance, informational, security desc| project id=subscriptionId, compliant=(alertEnabled > 0 and incident > 0 and security > 0 and maintenance > 0 and informational > 0)", + "guid": "64b0d934-a348-4726-be79-d6b5c3a36495", + "service": "AVS", "services": [ - "Storage", + "Monitor", "WAF" ], "severity": "High", - "text": "Enable resource locks on storage accounts", - "waf": "Security" + "text": "Ensure alerts are configured for Azure Service Health alerts and notifications", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Consider 'legal hold' or 'time-based retention' policies for blobs, so that is is impossible to delete the blob, the container, or the storage account. Please note that 'impossible' actually means 'impossible'; once a storage account contains an immutable blob, the only way to 'get rid' of that storage account is by cancelling the Azure subscription.", - "guid": "6f4389a8-f42c-478e-98c0-6a73a22a4956", - "link": "https://learn.microsoft.com/azure/storage/blobs/immutable-storage-overview", - "service": "Azure Storage", + "guid": "b6abad38-aad5-43cc-99e1-d86667357c54", + "service": "AVS", "services": [ - "AzurePolicy", "Storage", - "Subscriptions", + "AVS", "WAF" ], - "severity": "High", - "text": "Consider immutable blobs", - "waf": "Security" + "severity": "Medium", + "text": "Configure Azure VMware Solution logging to be send to an Azure Storage account or Azure EventHub for processing", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Consider disabling unprotected HTTP/80 access to the storage account, so that all data transfers are encrypted, integrity protected, and the server is authenticated. ", - "graph": "resources | where type =~ 'Microsoft.Storage/StorageAccounts' | extend compliant = (properties.supportsHttpsTrafficOnly == false) | distinct id, compliant", - "guid": "e7a8dc4a-20e2-47c3-b297-11b1352beee0", - "link": "https://learn.microsoft.com/azure/storage/common/storage-require-secure-transfer", - "service": "Azure Storage", + "guid": "9674c5ed-85b8-459c-9733-be2b1a27b775", + "service": "AVS", "services": [ - "Storage", + "AVS", "WAF" ], - "severity": "High", - "text": "Require HTTPS, i.e. disable port 80 on the storage account", - "waf": "Security" + "severity": "Low", + "text": "If deep insight in VMware vSphere is required: Is vRealize Operations and/or vRealize Network Insights used in the solution?", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "When configuring a custom domain (hostname) on a storage account, check whether you need TLS/HTTPS; if so, you might have to put Azure CDN in front of your storage account.", - "guid": "79b588de-fc49-472c-b3cd-21bf77036e5e", - "link": "https://learn.microsoft.com/azure/storage/blobs/storage-custom-domain-name", - "service": "Azure Storage", + "guid": "a91be1f3-88f0-43a4-b2cd-463cbbbc8682", + "service": "AVS", "services": [ "Storage", + "VM", + "AzurePolicy", "WAF" ], "severity": "High", - "text": "When enforcing HTTPS (disabling HTTP), check that you do not use custom domains (CNAME) for the storage account.", - "waf": "Security" + "text": "Ensure the vSAN storage policy for VM's is NOT the default storage policy as this policy applies thick provisioning", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Requiring HTTPS when a client uses a SAS token to access blob data helps to minimize the risk of credential loss.", - "guid": "6b4bed3d-5035-447c-8347-dc56028a71ff", - "link": "https://learn.microsoft.com/azure/storage/common/storage-sas-overview", - "service": "Azure Storage", + "guid": "d9ef1d5e-832d-442e-9611-c818b0afbc51", + "service": "AVS", "services": [ - "Storage", "WAF" ], "severity": "Medium", - "text": "Limit shared access signature (SAS) tokens to HTTPS connections only", - "waf": "Security" + "text": "Ensure vSphere content libraries are not placed on vSAN as vSAN is a finite resource", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": ". Enforcing the latest TLS version will reject request from clients using the older version. ", - "graph": "resources | where type == 'microsoft.storage/storageaccounts' | extend compliant = (isnull(properties.minimumTlsVersion) == false and properties.minimumTlsVersion in ('TLS1_2', 'TLS1_3')) | distinct id, compliant", - "guid": "e12be569-a18f-4562-8d5d-ce151b9e7d55", - "link": "https://learn.microsoft.com/azure/storage/common/transport-layer-security-configure-minimum-version", - "service": "Azure Storage", + "guid": "0e43a18a-9cd2-489b-bd6b-17db8255461e", + "service": "AVS", "services": [ "Storage", + "Backup", "WAF" ], - "severity": "High", - "text": "Enforce the latest TLS version for a storage account", - "waf": "Security" + "severity": "Medium", + "text": "Ensure data repositories for the backup solution are stored outside of vSAN storage. Either in Azure native or on a disk pool-backed datastore", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Microsoft Entra ID tokens should be favored over shared access signatures, wherever possible", - "guid": "e1ce15dd-3f0d-45e7-92d4-1e3611cc57b4", - "link": "https://learn.microsoft.com/azure/storage/common/authorize-data-access", - "service": "Azure Storage", + "guid": "2aee3453-aec8-4339-848b-262d6cc5f512", + "service": "AVS", "services": [ - "Storage", - "WAF", - "Entra" + "Arc", + "AVS", + "WAF" ], - "severity": "High", - "text": "Use Microsoft Entra ID tokens for blob access", - "waf": "Security" + "severity": "Medium", + "text": "Ensure workloads running on Azure VMware Solution are hybrid managed using Azure Arc for Servers (Arc for Azure VMware Solution is in preview)", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "When assigning a role to a user, group, or application, grant that security principal only those permissions that are necessary for them to perform their tasks. Limiting access to resources helps prevent both unintentional and malicious misuse of your data.", - "guid": "a4b1410d-4395-48a8-a228-9b3d6b57cfc6", - "service": "Azure Storage", + "guid": "925398e6-da9d-437d-ac43-bc6cd1d79a9b", + "service": "AVS", "services": [ - "RBAC", + "Monitor", + "AVS", "WAF" ], "severity": "Medium", - "text": "Least privilege in IaM permissions", - "waf": "Security" + "text": "Ensure workloads running on Azure VMware Solution are monitored using Azure Log Analytics and Azure Monitor", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "A user delegation SAS is secured with Azure Active Directory (Azure AD) credentials and also by the permissions specified for the SAS. A user delegation SAS is analogous to a service SAS in terms of its scope and function, but offers security benefits over the service SAS. ", - "guid": "55461e1a-3e34-453a-9c86-39648b652d6c", - "link": "https://learn.microsoft.com/azure/storage/common/storage-sas-overview?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json#best-practices-when-using-sas", - "service": "Azure Storage", + "guid": "24604489-a8f4-42d7-ae78-cb6a33bd2a09", + "service": "AVS", "services": [ - "Storage", - "WAF", - "Entra" + "AVS", + "WAF" ], - "severity": "High", - "text": "When using SAS, prefer 'user delegation SAS' over storage-account-key based SAS.", - "waf": "Security" + "severity": "Medium", + "text": "Include workloads running on Azure VMware Solution in existing update management tooling or in Azure Update Management", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Storage account keys ('shared keys') have very little audit capabilities. While it can be monitored on who/when fetched a copy of the keys, once the keys are in the hands of multiple people, it is impossible to attribute usage to a specific user. Solely relying on Entra ID authentication makes it easier to tie storage access to a user. ", - "graph": "resources | where type == 'microsoft.storage/storageaccounts' | extend allowSharedKeyAccess = tostring(properties.allowSharedKeyAccess) | extend compliant = (isnotempty(allowSharedKeyAccess) and allowSharedKeyAccess == 'false') | distinct id, compliant", - "guid": "15f51296-5398-4e6d-bd22-7dd142b06c21", - "link": "https://learn.microsoft.com/rest/api/storageservices/authorize-with-shared-key", - "service": "Azure Storage", + "guid": "17e7a8d9-0ae0-4e27-aee2-9711bd352caa", + "service": "AVS", "services": [ - "Entra", - "Storage", - "AKV", - "WAF", - "Monitor" + "Monitor", + "AVS", + "AzurePolicy", + "WAF" ], - "severity": "High", - "text": "Consider disabling storage account keys, so that only Microsoft Entra ID access (and user delegation SAS) is supported.", - "waf": "Security" + "severity": "Medium", + "text": "Use Azure Policy to onboard Azure VMware Solution workloads in the Azure Management, Monitoring and Security solutions", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Use Activity Log data to identify 'when', 'who', 'what' and 'how' the security of your storage account is being viewed or changed (i.e. storage account keys, access policies, etc.).", - "guid": "d7999a64-6f43-489a-af42-c78e78c06a73", - "link": "https://learn.microsoft.com/azure/storage/blobs/blob-storage-monitoring-scenarios#audit-account-activity", - "service": "Azure Storage", + "guid": "aee3553a-fc83-4392-98b2-62d6cc5f5129", + "service": "AVS", "services": [ - "Storage", - "AzurePolicy", - "Monitor", - "AKV", + "Defender", + "AVS", "WAF" ], - "severity": "High", - "text": "Consider using Azure Monitor to audit control plane operations on the storage account", + "severity": "Medium", + "text": "Ensure workloads running on Azure VMware Solution are onboarded to Microsoft Defender for Cloud", "waf": "Security" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "A key expiration policy enables you to set a reminder for the rotation of the account access keys. The reminder is displayed if the specified interval has elapsed and the keys have not yet been rotated.", - "guid": "a22a4956-e7a8-4dc4-a20e-27c3e29711b1", - "link": "https://learn.microsoft.com/azure/storage/common/storage-account-keys-manage?tabs=azure-portal#create-a-key-expiration-policy", - "service": "Azure Storage", + "guid": "25398e6d-b9d3-47da-a43b-c6cd1d79a9b2", + "service": "AVS", "services": [ - "AKV", - "Storage", - "AzurePolicy", + "Backup", "WAF" ], "severity": "Medium", - "text": "When using storage account keys, consider enabling a 'key expiration policy'", - "waf": "Security" + "text": "Ensure backups are not stored on vSAN as vSAN is a finite resource", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "A SAS expiration policy specifies a recommended interval over which the SAS is valid. SAS expiration policies apply to a service SAS or an account SAS. When a user generates service SAS or an account SAS with a validity interval that is larger than the recommended interval, they'll see a warning.", - "guid": "352beee0-79b5-488d-bfc4-972cd3cd21bf", - "link": "https://learn.microsoft.com/azure/storage/common/sas-expiration-policy", - "service": "Azure Storage", + "guid": "5e6bfbb9-ed50-4354-9cc4-47e826028a71", + "service": "AVS", "services": [ - "AzurePolicy", "WAF" ], "severity": "Medium", - "text": "Consider configuring an SAS expiration policy", - "waf": "Security" + "text": "Have all DR solutions been considered and a solution that is best for your business been decided upon? [SRM/JetStream/Zerto/Veeam/...]", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Stored access policies give you the option to revoke permissions for a service SAS without having to regenerate the storage account keys. ", - "guid": "77036e5e-6b4b-4ed3-b503-547c1347dc56", - "link": "https://learn.microsoft.com/rest/api/storageservices/define-stored-access-policy", - "service": "Azure Storage", + "guid": "f0f1cac6-d9ef-41d5-b832-d42e3611c818", + "service": "AVS", "services": [ - "AzurePolicy", - "Storage", - "WAF", - "AKV" + "ASR", + "WAF" ], "severity": "Medium", - "text": "Consider linking SAS to a stored access policy", - "waf": "Security" + "text": "Use Azure Site Recovery when the Disaster Recovery technology is native Azure IaaS", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "028a71ff-e1ce-415d-b3f0-d5e772d41e36", - "link": "https://microsoft.github.io/code-with-engineering-playbook/continuous-integration/dev-sec-ops/secret-management/recipes/detect-secrets-ado/", - "service": "Azure Storage", + "guid": "b0afbc51-0e43-4a18-a9cd-289bed6b17db", + "service": "AVS", "services": [ - "AKV", - "Storage", "WAF" ], - "severity": "Medium", - "text": "Consider configuring your application's source code repository to detect checked-in connection strings and storage account keys.", - "waf": "Security" + "severity": "High", + "text": "Use Automated recovery plans with either of the Disaster solutions, avoid manual tasks as much as possible", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Ideally, your application should be using a managed identity to authenticate to Azure Storage. If that is not possible, consider having the storage credential (connection string, storage account key, SAS, service principal credential) in Azure KeyVault or an equivalent service.", - "guid": "11cc57b4-a4b1-4410-b439-58a8c2289b3d", - "link": "https://learn.microsoft.com/azure/architecture/framework/security/design-storage-keys", - "service": "Azure Storage", + "guid": "8255461e-2aee-4345-9aec-8339248b262d", + "service": "AVS", "services": [ - "Storage", - "WAF", - "Entra" + "ASR", + "WAF" ], - "severity": "High", - "text": "Consider storing connection strings in Azure KeyVault (in scenarios where managed identities are not possible)", - "waf": "Security" + "severity": "Medium", + "text": "Use the geopolitical region pair as the secondary disaster recovery environment", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Use near-term expiration times on an ad hoc SAS service SAS or account SAS. In this way, even if a SAS is compromised, it's valid only for a short time. This practice is especially important if you cannot reference a stored access policy. Near-term expiration times also limit the amount of data that can be written to a blob by limiting the time available to upload to it.", - "guid": "27138b82-1102-4cac-9eae-01e6e842e52f", - "link": "https://learn.microsoft.com/rest/api/storageservices/delegate-access-with-shared-access-signature", - "service": "Azure Storage", + "guid": "6cc5f512-9253-498e-9da9-d37dac43bc6c", + "service": "AVS", "services": [ - "AzurePolicy", - "Storage", "WAF" ], "severity": "High", - "text": "Strive for short validity periods for ad-hoc SAS", - "waf": "Security" + "text": "Use 2 different address spaces between the regions, for example: 10.0.0.0/16 and 192.168.0.0/16 for the different regions", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "When creating a SAS, be as specific and restrictive as possible. Prefer a SAS for a single resource and operation over a SAS which gives much broader access.", - "guid": "4721d928-c1b1-4cd5-81e5-4a29a9de399c", - "link": "https://learn.microsoft.com/rest/api/storageservices/delegate-access-with-shared-access-signature", - "service": "Azure Storage", + "guid": "d1d79a9b-2460-4448-aa8f-42d78e78cb6a", + "service": "AVS", "services": [ + "NVA", + "ExpressRoute", + "AVS", "WAF" ], "severity": "Medium", - "text": "Apply a narrow scope to a SAS", - "waf": "Security" + "text": "Will ExpressRoute Global Reach be used for connectivity between the primary and secondary Azure VMware Solution Private Clouds or is routing done through network virtual appliances?", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "A SAS can include parameters on which client IP addresses or address ranges are authorized to request a resource using the SAS. ", - "guid": "fd7b28dc-9355-4562-82bf-e4564b0d834a", - "link": "https://learn.microsoft.com/rest/api/storageservices/create-account-sas", - "service": "Azure Storage", + "guid": "33bd2a09-17e7-4a8d-a0ae-0e27cee29711", + "service": "AVS", "services": [ + "Backup", "WAF" ], "severity": "Medium", - "text": "Consider scoping SAS to a specific client IP address, wherever possible", - "waf": "Security" + "text": "Have all Backup solutions been considered and a solution that is best for your business been decided upon? [ MABS/CommVault/Metallic.io/Veeam/�. ]", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "A SAS cannot constrain how much data a client uploads; given the pricing model of amount of storage over time, it might make sense to validate whether clients uploaded maliciously large contents.", - "guid": "348b263e-6dd6-4051-8a36-498f6dbad38e", - "service": "Azure Storage", + "guid": "bd352caa-ab79-4b18-adab-81932c9fc9d1", + "service": "AVS", "services": [ - "Storage", + "Backup", + "AVS", "WAF" ], - "severity": "Low", - "text": "Consider checking uploaded data, after clients used a SAS to upload a file. ", - "waf": "Security" + "severity": "Medium", + "text": "Deploy your backup solution in the same region as your Azure VMware Solution private cloud", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "When accessing blob storage via SFTP using a 'local user account', the 'usual' RBAC controls do not apply. Blob access via NFS or REST might be more restrictive than SFTP access. Unfortunately, as of early 2023, local users are the only form of identity management that is currently supported for the SFTP endpoint", - "guid": "ad53cc7c-e1d7-4aaa-a357-1449ab8053d8", - "link": "https://learn.microsoft.com/azure/storage/blobs/secure-file-transfer-protocol-support#sftp-permission-model", - "service": "Azure Storage", + "guid": "bb77036f-5e6b-4fbb-aed5-03547cc447e8", + "service": "AVS", "services": [ - "RBAC", - "Storage", - "WAF", - "Entra" + "Backup", + "WAF" ], - "severity": "High", - "text": "SFTP: Limit the amount of 'local users' for SFTP access, and audit whether access is needed over time.", - "waf": "Security" + "severity": "Medium", + "text": "Deploy your backup solution outside of vSan, on Azure native components", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "9f89dc7b-33be-42a1-a27f-7b9e91be1f38", - "link": "https://learn.microsoft.com/azure/storage/blobs/secure-file-transfer-protocol-known-issues#authentication-and-authorization", - "service": "Azure Storage", + "guid": "26028a71-f0f1-4cac-9d9e-f1d5e832d42e", + "service": "AVS", "services": [ + "AVS", "WAF" ], - "severity": "Medium", - "text": "SFTP: The SFTP endpoint does not support POSIX-like ACLs.", - "waf": "Security" + "severity": "Low", + "text": "Is a process in place to request a restore of the VMware components managed by the Azure Platform?", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Storage supports CORS (Cross-Origin Resource Sharing), i.e. an HTTP feature that enables web apps from a different domain to loosen the same-origin policy. When enabling CORS, keep the CorsRules to the least privilege.", - "guid": "cef39812-bd46-43cb-aac8-ac199ebb91a3", - "link": "https://learn.microsoft.com/rest/api/storageservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services", - "service": "Azure Storage", + "guid": "4604489a-8f42-4d78-b78c-b7a33bd2a0a1", + "service": "AVS", "services": [ - "AzurePolicy", - "Storage", "WAF" ], - "severity": "High", - "text": "Avoid overly broad CORS policies", - "waf": "Security" + "severity": "Low", + "text": "For manual deployments, all configuration and deployments must be documented", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Data at rest is always encrypted server-side, and in addition might be encrypted client-side as well. Server-side encryption might happen using a platform-managed key (default) or customer-managed key. Client-side encryption might happen by either having the client supply an encryption/decryption key on a per-blob basis to Azure storage, or by completely handling encryption on the client-side. thus not relying on Azure Storage at all for confidentiality guarantees.", - "guid": "3d90cae2-cc88-4137-86f7-c0cbafe61464", - "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", - "service": "Azure Storage", + "guid": "7e7a8d90-ae0e-437c-be29-711bd352caaa", + "service": "AVS", "services": [ - "Storage", + "AVS", "WAF" ], - "severity": "High", - "text": "Determine how data at rest should be encrypted. Understand the thread model for data.", - "waf": "Security" + "severity": "Low", + "text": "For manual deployments, consider implementing resource locks to prevent accidental actions on your Azure VMware Solution Private Cloud", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "8dd457e9-2713-48b8-8110-2cac6eae01e6", - "link": "https://learn.microsoft.com/azure/storage/common/customer-managed-keys-overview?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json&bc=%2Fazure%2Fstorage%2Fblobs%2Fbreadcrumb%2Ftoc.json", - "service": "Azure Storage", + "guid": "b79b198d-ab81-4932-a9fc-9d1bb78036f5", + "service": "AVS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Determine which/if platform encryption should be used.", - "waf": "Security" + "severity": "Low", + "text": "For automated deployments, deploy a minimal private cloud and scale as needed", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "e842e52f-4721-4d92-ac1b-1cd521e54a29", - "link": "https://learn.microsoft.com/azure/storage/blobs/encryption-customer-provided-keys", - "service": "Azure Storage", + "guid": "e6bfbb9e-d503-4547-ac44-7e826128a71f", + "service": "AVS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Determine which/if client-side encryption should be used.", - "waf": "Security" + "severity": "Low", + "text": "For automated deployments, request or reserve quota prior to starting the deployment", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "description": "Anonymous access may present a security risk. We recommend that you disable anonymous access for optimal security. Disallowing anonymous access helps to prevent data breaches caused by undesired anonymous access.", - "graph": "resources | where type == 'microsoft.storage/storageaccounts' | extend compliant = (properties.allowBlobPublicAccess == 'false') | distinct id, compliant", - "guid": "659ae558-b937-4d49-a5e1-112dbd7ba012", - "link": "https://learn.microsoft.com/azure/storage/blobs/anonymous-read-access-configure?tabs=portal#allow-or-disallow-public-read-access-for-a-storage-account", - "service": "Azure Storage", + "guid": "0f1cac6d-9ef1-4d5e-a32e-42e3611c818b", + "service": "AVS", "services": [ - "Storage", + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Consider whether public blob anonymous access is needed, or whether it can be disabled for certain storage accounts. ", - "waf": "Security" + "severity": "Low", + "text": "For automated deployment, ensure that relevant resource locks are created through the automation or through Azure Policy for proper governance", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "cb8eb8c0-aa62-4a25-a495-6eaa8dc4a243", - "link": "https://learn.microsoft.com/azure/storage/common/storage-account-upgrade?tabs=azure-portal", - "service": "Azure Storage", + "guid": "e2cc95d4-8c6b-4791-bca0-f6c56589e558", + "service": "AVS", "services": [ - "Storage", + "AKV", "WAF" ], - "severity": "High", - "text": "Leverage a storagev2 account type for better performance and reliability", - "waf": "Reliability" + "severity": "Low", + "text": "Implement human understandable names for ExR authorization keys to allow for easy identification of the keys purpose/use", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.Storage/StorageAccounts' | extend compliant = (sku.name != 'Standard_LRS' and sku.name != 'Premium_LRS') | distinct id, compliant", - "guid": "e05bbe20-9d49-4fda-9777-8424d116785c", - "link": "https://learn.microsoft.com/azure/storage/common/storage-redundancy", - "service": "Azure Storage", + "guid": "255461e2-aee3-4553-afc8-339248b262d6", + "service": "AVS", "services": [ - "Storage", + "AKV", + "ExpressRoute", + "AVS", "WAF" ], - "severity": "High", - "text": "Leverage GRS, ZRS or GZRS storage for the highest availability", - "waf": "Reliability" + "severity": "Low", + "text": "Use Key vault to store secrets and authorization keys when separate Service Principles are used for deploying Azure VMware Solution and ExpressRoute", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "2fa56c56-ad48-4408-be72-734c486ba280", - "link": "https://learn.microsoft.com/azure/storage/common/storage-disaster-recovery-guidance", - "service": "Azure Storage", + "guid": "cc5f5129-2539-48e6-bb9d-37dac43bc6cd", + "service": "AVS", "services": [ + "AVS", "WAF" ], - "severity": "Medium", - "text": "For write operation after failover, use customer-Managed Failover ", - "waf": "Reliability" + "severity": "Low", + "text": "Define resource dependencies for serializing actions in IaC when many resources need to be deployed in/on Azure VMware Solution as Azure VMware Solution only supports a limited number of parallel operations.", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "dc0590cf-65de-48e1-909c-cbd579266bcc", - "link": "https://learn.microsoft.com/azure/storage/common/storage-disaster-recovery-guidance#microsoft-managed-failover", - "service": "Azure Storage", + "guid": "1d79a9b2-4604-4489-a8f4-2d78e78cb7a3", + "service": "AVS", "services": [ "WAF" ], - "severity": "Medium", - "text": "Understand Microsoft-Managed Failover details", - "waf": "Reliability" + "severity": "Low", + "text": "When performing automated configuration of NSX-T segments with a single Tier-1 gateway, use Azure Portal APIs instead of NSX-Manager APIs", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "a274faa1-abfe-49d5-9d04-c3c4919cb1b3", - "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-enable?tabs=azure-portal", - "service": "Azure Storage", + "guid": "3bd2a0a1-7e7a-48d9-8ae0-e37cee29711b", + "service": "AVS", "services": [ + "Subscriptions", + "AVS", "WAF" ], "severity": "Medium", - "text": "Enable Soft Delete", - "waf": "Reliability" + "text": "When intending to use automated scale-out, be sure to apply for sufficient Azure VMware Solution quota for the subscriptions running Azure VMware Solution", + "waf": "Performance" }, { - "arm-service": "Microsoft.Search/searchServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "41faa1ed-b7f0-447d-8cba-4a4905e5bb83", - "link": "https://learn.microsoft.com/azure/search/search-reliability#high-availability", - "service": "Cognitive Search", + "guid": "d352caaa-b79b-4198-bab8-1932c9fc9d1b", + "service": "AVS", "services": [ + "Storage", + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Enable 2 replicas to have 99.9% availability for read operations", - "waf": "Reliability" + "severity": "Medium", + "text": "When intending to use automated scale-in, be sure to take storage policy requirements into account before performing such action", + "waf": "Performance" }, { - "arm-service": "Microsoft.Search/searchServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "7d956fd9-788a-4845-9b9f-c0340972d810", - "link": "https://learn.microsoft.com/azure/search/search-reliability#high-availability", - "service": "Cognitive Search", + "guid": "b78036f5-e6bf-4bb9-bd50-3547cc447e82", + "service": "AVS", "services": [ "WAF" ], "severity": "Medium", - "text": "Enable 3 replicas to have 99.9% availability for read/write operations", - "waf": "Reliability" + "text": "Scaling operations always need to be serialized within a single SDDC as only one scale operation can be performed at a time (even when multiple clusters are used)", + "waf": "Performance" }, { - "arm-service": "Microsoft.Search/searchServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "44dc5f2b-a032-4d03-aae8-90c3f2c0a4c3", - "link": "https://learn.microsoft.com/azure/search/search-reliability#availability-zone-support", - "service": "Cognitive Search", + "guid": "bf15bce2-19e4-4a0e-a588-79424d226786", + "service": "AVS", "services": [ "WAF" ], - "severity": "High", - "text": "Leverage Availability Zones by enabling read and/or write replicas", - "waf": "Reliability" + "severity": "Medium", + "text": "Consider and validate scaling operations on 3rd party solutions used in the architecture (supported or not)", + "waf": "Performance" }, { - "arm-service": "Microsoft.Search/searchServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "cd0730f0-0ff1-4b77-9a2b-2a1f7dd5e291", - "link": "https://learn.microsoft.com/azure/search/search-reliability#multiple-services-in-separate-geographic-regions", - "service": "Cognitive Search", + "guid": "d20b56c5-7be5-4851-a0f8-3835c586cb29", + "service": "AVS", "services": [ - "WAF", - "ACR" + "WAF" ], "severity": "Medium", - "text": "For regional redudancy, Manually create services in 2 or more regions for Search as it doesn't provide an automated method of replicating search indexes across geographic regions", - "waf": "Reliability" + "text": "Define and enforce scale in/out maximum limits for your environment in the automations", + "waf": "Performance" }, { - "arm-service": "Microsoft.Search/searchServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "3c964882-aec9-4d44-9f68-4b5f2efbbdb6", - "link": "https://learn.microsoft.com/azure/search/search-reliability#synchronize-data-across-multiple-services", - "service": "Cognitive Search", + "guid": "1dc15a1c-075e-4e9f-841a-cccd579376bc", + "service": "AVS", "services": [ - "WAF", - "ACR" + "Monitor", + "WAF" ], "severity": "Medium", - "text": "To synchronize data across multiple services either Use indexers for updating content on multiple services or Use REST APIs for pushing content updates on multiple services", - "waf": "Reliability" + "text": "Implement monitoring rules to monitor automated scaling operations and monitor success and failure to enable appropriate (automated) responses", + "waf": "Operations" }, { - "arm-service": "Microsoft.Search/searchServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "85ee93c9-f53c-4803-be51-e6e4aa37ff4e", - "link": "https://learn.microsoft.com/azure/search/search-reliability#use-azure-traffic-manager-to-coordinate-requests", - "service": "Cognitive Search", + "guid": "c5972cd4-cd21-4b07-9036-f5e6b4bfd3d5", + "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy#how-application-proxy-works", + "service": "AVS", "services": [ - "TrafficManager", + "VM", "WAF" ], - "severity": "Medium", - "text": "Use Azure Traffic Manager to coordinate requests", + "severity": "High", + "text": "When using MON, be aware of the limits of simulataneously configured VMs (MON Limit for HCX [400 - standard, 1000 - Larger appliance])", + "training": "https://learn.microsoft.com/learn/modules/configure-azure-ad-application-proxy/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Search/searchServices", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "7be10278-57c1-4a61-8ee3-895aebfec5aa", - "link": "https://learn.microsoft.com/azure/search/search-reliability#back-up-and-restore-alternatives", - "service": "Cognitive Search", + "guid": "be1f38cf-03a8-422b-b463-cbbbc8ac299e", + "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy#how-application-proxy-works", + "service": "AVS", "services": [ - "Storage", - "WAF", - "Backup" + "WAF" ], "severity": "High", - "text": "Backup and Restore an Azure Cognitive Search Index. Use this sample code to back up index definition and snapshot to a series of Json files", + "text": "When using MON, you cannot enable MON on more than 100 Network extensions", + "training": "https://learn.microsoft.com/learn/paths/implement-applications-external-access-azure-ad/", "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "21c30d25-ffb7-4f6a-b9ea-b3fec328f787", - "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/paas-foundations-playbooks-cog_svcs_v1.docx", - "service": "Cognitive Services", + "guid": "bc91a43d-90da-4e2c-a881-4706f7c1cbaf", + "service": "AVS", "services": [ + "VPN", "WAF" ], "severity": "Medium", - "text": "Leverage FTA HandBook for Cognitive Services", - "waf": "Reliability" + "text": "If using a VPN connection for migrations, adjust your MTU size accordingly.", + "waf": "Performance" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "78c34698-16b2-4763-aefe-1b9b599de0d5", - "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/advanced-prompt-engineering?pivots=programming-language-chat-completions", - "service": "Cognitive Services", + "guid": "e614658d-d457-4e92-9139-b821102cad6e", + "service": "AVS", "services": [ - "WAF", - "Backup" + "WAF" ], "severity": "Medium", - "text": "Backup Your Prompts", - "waf": "Reliability" + "text": "For low connectivity regions connecting into Azure (500Mbps or less), considering deploying the HCX WAN optimization appliance", + "waf": "Performance" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "750ab2ab-039d-4a6d-95d7-c892adb107d5", - "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/business-continuity-disaster-recovery", - "service": "Cognitive Services", + "guid": "ae01e6e8-43e5-42f4-922d-928c1b1cd521", + "service": "AVS", "services": [ - "ASR", "WAF" ], - "severity": "High", - "text": "Business Continuity and Disaster Recovery (BCDR) considerations with Azure OpenAI Service", + "severity": "Medium", + "text": "Ensure that migrations are started from the on-premises appliance and NOT from the Cloud appliance (do NOT perform a reverse migration)", "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "325af625-ca44-4e46-a5e2-223ace8bb123", - "link": "https://github.com/abacaj/chatgpt-backup#backup-your-chatgpt-conversations", - "service": "Cognitive Services", + "guid": "e54a29a9-de39-4ac0-b7c2-8dc935657202", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings", + "service": "AVS", "services": [ - "WAF", - "Backup" + "Storage", + "VM", + "AVS", + "WAF" ], "severity": "Medium", - "text": "Backup Your ChatGPT conversations", + "text": "When Azure Netapp Files is used to extend storage for Azure VMware Solution,consider using this as a VMware datastore instead of attaching directly to a VM.", "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "07ca5f17-f154-4e3a-a369-2829e7e31618", - "link": "https://learn.microsoft.com/azure/ai-services/speech-service/how-to-custom-speech-continuous-integration-continuous-deployment", - "service": "Cognitive Services", + "guid": "bff4564b-0d93-44a3-98b2-63e7dd60513a", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#avoid-combining-traffic-manager-and-front-door", + "service": "AVS", "services": [ + "Storage", + "ExpressRoute", "WAF" ], "severity": "Medium", - "text": "CI/CD for custom speech", + "text": "Ensure that a dedicated ExpressRoute Gateway is being used for external data storage solutions", "waf": "Reliability" }, { - "arm-service": "Microsoft.CognitiveServices/accounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "3687a046-7a1f-4893-9bda-43324f248116", - "link": "https://learn.microsoft.com/azure/ai-services/qnamaker/tutorials/export-knowledge-base", - "service": "Cognitive Services", + "guid": "3649906e-bad3-48ea-b53c-c7de1d8aaab3", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-the-same-domain-name-on-front-door-and-your-origin", + "service": "AVS", "services": [ + "Storage", + "ExpressRoute", "WAF" ], - "severity": "Low", - "text": "Move a knowledge base using export-import", + "severity": "Medium", + "text": "Ensure that FastPath is enabled on the ExpressRoute Gateway that is being used for external data storage solutions", "waf": "Reliability" }, { - "arm-service": "Microsoft.App/containerApps", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "af416482-663c-4ed6-b195-b44c7068e09c", - "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#availability-zone-support", - "query": "resources | where type =~ 'Microsoft.App/managedEnvironments' | project name, resourceGroup, location, zoneRedundancy = tolower(tostring(properties.zoneRedundant)) | extend Compliance = iff(zoneRedundancy == 'true', true, false)", - "service": "Container Apps", + "guid": "571549ab-8153-4d89-b89d-c7b33be2b1a2", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group", + "service": "AVS", "services": [ + "ASR", "WAF" ], "severity": "High", - "text": "Leverage Availability Zones if regionally applicable", + "text": "If using stretched cluster, ensure that your selected Disaster Recovery solution is supported by the vendor", "waf": "Reliability" }, { - "arm-service": "Microsoft.App/containerApps", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "95bc80ec-6499-4d14-a7d2-7d296b1d8abc", - "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#set-up-zone-redundancy-in-your-container-apps-environment", - "query": "resources | where type =~ 'Microsoft.App/containerApps' | project name, resourceGroup, location, minReplicas = toint(properties.template.scale.minReplicas), maxReplicas = toint(properties.template.scale.maxReplicas) | extend Compliance = iff(minReplicas >= 1, true, false)", - "service": "Container Apps", + "guid": "4c486b6d-8bdc-4059-acf7-5ee8a1309888", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#select-good-health-probe-endpoints", + "service": "AVS", "services": [ "WAF" ], "severity": "High", - "text": "Use more than one replica and enable Zone Redundancy.", + "text": "If using stretched cluster, ensure that the SLA provided will meet your requirements", "waf": "Reliability" }, { - "arm-service": "Microsoft.App/containerApps", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "ccaa4fc2-fdbc-4432-8bb7-f7e6469e4dc3", - "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#cross-region-disaster-recovery-and-business-continuity", - "service": "Container Apps", + "guid": "9579d66b-896d-471f-a6ca-7be9955d04c3", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes", + "service": "AVS", "services": [ + "ExpressRoute", "WAF" ], "severity": "High", - "text": "For cross-region DR, deploy container apps in multiple regions and follow active/active or active/passive application guidance.", + "text": "If using stretched cluster, ensure that both ExpressRoute circuits are connected to your connectivity hub.", "waf": "Reliability" }, { - "arm-service": "Microsoft.App/containerApps", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "2ffada86-c031-4933-bf7d-0c45bc4e5919", - "link": "https://learn.microsoft.com/azure/reliability/reliability-azure-container-apps?tabs=azure-cli#cross-region-disaster-recovery-and-business-continuity", - "service": "Container Apps", + "guid": "c49d987c-b3d1-4325-aa12-4b6e4d0685ed", + "link": "https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity", + "service": "AVS", "services": [ - "TrafficManager", - "WAF", - "FrontDoor" + "ExpressRoute", + "WAF" ], "severity": "High", - "text": "Use Front Door or Traffic Manager to route traffic to the closest region", + "text": "If using stretched cluster, ensure that both ExpressRoute circuits have GlobalReach enabled.", "waf": "Reliability" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "Microsoft.AVS/privateClouds", "checklist": "WAF checklist", - "guid": "43e52f47-22d9-428c-8b1c-d521e54a29a9", - "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foundations-playbooks-CosmosDB_v1.docx", - "service": "CosmosDB", + "guid": "dce9793b-7bcd-4b3b-91eb-2ec14eea6e59", + "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates", + "service": "AVS", "services": [ "WAF" ], - "severity": "Medium", - "text": "FTA Resiliency Playbook", + "severity": "High", + "text": "Have site disaster tolerance settings been properly considered and changed for your business if needed.", "waf": "Reliability" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "de39ac0e-7c28-4dc9-9565-7202bff4564b", - "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#slas", - "service": "CosmosDB", + "description": "Azure Event Hub provides encryption of data at rest. If you use your own key, the data is still encrypted using the Microsoft-managed key, but in addition the Microsoft-managed key will be encrypted using the customer-managed key. ", + "guid": "7aaf12e7-b94e-4f6e-847d-2d92981b1cd6", + "link": "https://learn.microsoft.com/azure/event-hubs/configure-customer-managed-key", + "service": "Event Hubs", "services": [ + "EventHubs", "WAF" ], - "severity": "High", - "text": "Leverage Availablity Zones where regionally applicable and ofcourse if the service offers it", - "waf": "Reliability" + "severity": "Low", + "text": "Use customer-managed key option in data at rest encryption when required", + "training": "https://learn.microsoft.com/learn/modules/plan-implement-administer-conditional-access/", + "waf": "Security" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "0d934a34-8b26-43e7-bd60-513a3649906e", - "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#replica-outages", - "service": "CosmosDB", + "description": "Azure Event Hubs namespaces permit clients to send and receive data with TLS 1.0 and above. To enforce stricter security measures, you can configure your Event Hubs namespace to require that clients send and receive data with a newer version of TLS. If an Event Hubs namespace requires a minimum version of TLS, then any requests made with an older version will fail. ", + "guid": "d2f54b29-769e-43a6-a0e7-828ac936657e", + "link": "https://learn.microsoft.com/azure/event-hubs/transport-layer-security-configure-minimum-version", + "service": "Event Hubs", "services": [ + "EventHubs", "WAF" ], "severity": "Medium", - "text": "Run multiple replicas of the database (>1 ) in Prod", - "waf": "Reliability" + "text": "Enforce a minimum required version of Transport Layer Security (TLS) for requests ", + "training": "https://learn.microsoft.com/learn/modules/secure-aad-users-with-mfa/", + "waf": "Security" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "Multi-region writes capability allows you to take advantage of the provisioned throughput for your databases and containers across the globe", - "guid": "bad38ead-53cc-47de-8d8a-aab3571449ab", - "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#multiple-write-regions", - "service": "CosmosDB", + "description": "When you create an Event Hubs namespace, a policy rule named RootManageSharedAccessKey is automatically created for the namespace. This policy has manage permissions for the entire namespace. It�s recommended that you treat this rule like an administrative root account and don�t use it in your application. Using AAD as an authentication provider with RBAC is recommended. ", + "guid": "13b0f566-4b1e-4944-a459-837ee79d6c6d", + "link": "https://learn.microsoft.com/azure/event-hubs/authorize-access-shared-access-signature#shared-access-authorization-policies", + "service": "Event Hubs", "services": [ + "AzurePolicy", + "EventHubs", + "RBAC", + "TrafficManager", "WAF", - "ACR" + "Entra" ], "severity": "Medium", - "text": "Leverage Multi-Region Writes", - "waf": "Reliability" + "text": "Avoid using root account when it is not necessary", + "training": "https://learn.microsoft.com/learn/paths/azure-administrator-manage-identities-governance/", + "waf": "Security" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "Span Cosmos account across two or more regions with multi-region writes", - "guid": "8153d89f-89dc-47b3-9be2-b1a27f7b9e91", - "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#slas", - "service": "CosmosDB", + "description": "Managed identities for Azure resources can authorize access to Event Hubs resources using Azure AD credentials from applications running in Azure Virtual Machines (VMs), Function apps, Virtual Machine Scale Sets, and other services. By using managed identities for Azure resources together with Azure AD authentication, you can avoid storing credentials with your applications that run in the cloud. ", + "guid": "3a365a5c-7acb-4e48-abd5-4cd79f2e8776", + "link": "https://learn.microsoft.com/azure/event-hubs/authenticate-managed-identity?tabs=latest", + "service": "Event Hubs", "services": [ + "AKV", + "EventHubs", + "Storage", "WAF", - "ACR" + "VM", + "Entra" ], "severity": "Medium", - "text": "Distribute your data globally", - "waf": "Reliability" + "text": "When possible, your application should be using a managed identity to authenticate to Azure Event Hub. If not, consider having the storage credential (SAS, service principal credential) in Azure Key Vault or an equivalent service", + "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", + "waf": "Security" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "Choose from various consistency levels such as Eventual, Consistent Prefix, Session, Bounded Staleness and strong", - "guid": "9f8ea848-25ec-4140-bc32-2758e6ee9ac0", - "link": "https://learn.microsoft.com/azure/cosmos-db/consistency-levels", - "service": "CosmosDB", + "description": "When creating permissions, provide fine-grained control over a client's access to Azure Event Hub. Permissions in Azure Event Hub can and should be scoped to the individual resource level e.g. consumer group, event hub entity, event hub namespaces, etc.", + "guid": "8357c559-675c-45ee-a5b8-6ad8844ce3b2", + "link": "https://learn.microsoft.com/azure/event-hubs/authorize-access-azure-active-directory#azure-built-in-roles-for-azure-event-hubs", + "service": "Event Hubs", "services": [ + "RBAC", + "EventHubs", "WAF" ], "severity": "High", - "text": "Choose from several well-defined consistency models", - "waf": "Reliability" + "text": "Use least privilege data plane RBAC", + "training": "https://learn.microsoft.com/learn/modules/explore-basic-services-identity-types/", + "waf": "Security" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "Maintain business continuity during regional outages. Azure Cosmos DB supports service-managed failover during a regional outage. During a regional outage, Azure Cosmos DB continues to maintain its latency, availability, consistency, and throughput SLAs. To help make sure that your entire application is highly available, Azure Cosmos DB offers a manual failover API to simulate a regional outage. By using this API, you can carry out regular business continuity drills.", - "guid": "a47e4d1e-bb79-43f9-bf87-69e1032b72fe", - "link": "https://learn.microsoft.com/azure/cosmos-db/how-to-manage-database-account#automatic-failover", - "service": "CosmosDB", + "description": "Azure Event Hub resource logs include operational logs, virtual network and Kafka logs. Runtime audit logs capture aggregated diagnostic information for all data plane access operations (such as send or receive events) in Event Hubs.", + "guid": "b38b875b-a1cf-4104-a900-3a4d3ce474db", + "link": "https://learn.microsoft.com/azure/event-hubs/monitor-event-hubs-reference", + "service": "Event Hubs", "services": [ - "WAF", - "CosmosDB" + "VNet", + "EventHubs", + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Enable Service managed failover", - "waf": "Reliability" + "text": "Enable logging for security investigation. Use Azure Monitor to captured metrics and logs such as resource logs, runtime audit logs and Kafka logs", + "training": "https://learn.microsoft.com/learn/paths/manage-identity-and-access/", + "waf": "Security" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "Azure Cosmos DB automatically takes backups of your data at regular intervals. The automatic backups are taken without affecting the performance or availability of the database operations. All the backups are stored separately in a storage service.", - "guid": "3499c9c1-133d-42f7-a4b1-a5bd06ff1a90", - "link": "https://learn.microsoft.com/azure/cosmos-db/online-backup-and-restore", - "service": "CosmosDB", + "description": "Azure Event Hub by default has a public IP address and is Internet-reachable. Private endpoints allow traffic between your virtual network and Azure Event Hub traverses over the Microsoft backbone network. In addition to that, you should disable public endpoints if those are not used. ", + "guid": "5abca2a4-eda1-4dae-8cc9-5d48c6b791dc", + "link": "https://learn.microsoft.com/azure/event-hubs/private-link-service", + "service": "Event Hubs", "services": [ - "Storage", - "CosmosDB", - "WAF", - "Backup" + "VNet", + "PrivateLink", + "EventHubs", + "WAF" ], "severity": "Medium", - "text": "Enable Automatic Backups", - "training": "https://learn.microsoft.com/learn/modules/explore-basic-services-identity-types/", - "waf": "Reliability" + "text": "Consider using private endpoints to access Azure Event Hub and disable public network access when applicable.", + "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", + "waf": "Security" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "This mode is the default backup mode for all existing accounts. In this mode, backup is taken at a periodic interval and the data is restored by creating a request with the support team. In this mode, you configure a backup interval and retention for your account. The maximum retention period extends to a month. The minimum backup interval can be one hour.", - "guid": "a6eb33f6-005c-4d92-9286-7655672d6121", - "link": "https://learn.microsoft.com/azure/cosmos-db/periodic-backup-restore-introduction", - "service": "CosmosDB", + "description": "With IP firewall, you can restrict public endpoint further to only a set of IPv4 addresses or IPv4 address ranges in CIDR (Classless Inter-Domain Routing) notation. ", + "guid": "a0e6c465-89e5-458b-a37d-3974d1112dbd", + "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-ip-filtering", + "service": "Event Hubs", "services": [ - "WAF", - "Backup" + "EventHubs", + "WAF" ], "severity": "Medium", - "text": "Perform Periodic Backups", - "training": "https://learn.microsoft.com/learn/paths/manage-identity-and-access/", - "waf": "Reliability" + "text": "Consider only allowing access to Azure Event Hub namespace from specific IP addresses or ranges", + "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", + "waf": "Security" }, { - "arm-service": "microsoft.documentdb/databaseAccounts", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "Continous 7 day retention and 30 day retention backups. Azure Cosmos DB performs data backup in the background without consuming any extra provisioned throughput (RUs) or affecting the performance and availability of your database. Continuous backups are taken in every region where the account exists.", - "guid": "d43918a8-cd28-49be-b6b1-7cb8245461e1", - "link": "https://learn.microsoft.com/azure/cosmos-db/continuous-backup-restore-introduction", - "service": "CosmosDB", + "guid": "31d41e36-11c8-417b-8afb-c410d4391898", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/paas-foundations-playbooks-AEH_v1.docx", + "service": "Event Hubs", "services": [ - "CosmosDB", - "WAF", - "Backup" + "WAF" ], "severity": "Medium", - "text": "Continous Backup with point-in-time restore in Azure Cosmos DB", - "training": "https://learn.microsoft.com/learn/modules/create-custom-azure-roles-with-rbac/", + "text": "Leverage FTA Resillency HandBook", "waf": "Reliability" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "a95b86ad-8840-48e3-9273-4b875ba18f20", - "link": "https://learn.microsoft.com/azure/architecture/guide/multitenant/considerations/tenancy-models", - "service": "Azure Monitor", + "description": " This will be turned on automatically for a new EH namespace created from the portal with Premium, Dedicated, or Standard SKUs in a zone-enabled region. Both the EH metadata and the event data itself are replicated across zones", + "guid": "f15bce21-9e4a-40eb-9787-9424d226786d", + "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-premium-overview#high-availability-with-availability-zones", + "service": "Event Hubs", "services": [ - "WAF", - "Monitor" + "ACR", + "EventHubs", + "WAF" ], - "severity": "Medium", - "text": "Data collection rules in Azure Monitor -https://learn.microsoft.com/azure/azure-monitor/essentials/data-collection-rule-overview", - "training": "https://azure.microsoft.com/pricing/reservations/", - "waf": "Cost" + "severity": "High", + "text": "Leverage Availability Zones if regionally applicable", + "waf": "Reliability" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "45901365-d38e-443f-abcb-d868266abca2", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/automation", - "service": "Azure Backup", + "guid": "20b56c56-ad58-4519-8f82-735c586bb281", + "link": "https://learn.microsoft.com/azure/event-hubs/compare-tiers", + "service": "Event Hubs", "services": [ - "WAF", - "Backup" + "WAF" ], "severity": "Medium", - "text": "check backup instances with the underlying datasource not found", - "waf": "Cost" + "text": "Use the Premium or Dedicated SKUs for predicable performance", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "64f9a19a-f29c-495d-94c6-c7919ca0f6c5", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/lighthouse", - "service": "VM", + "description": "The built-in geo-disaster recovery feature, when enabled, ensures that the entire configuration of anamespace (Event Hubs, Consumer Groups and settings) is continuously replicated from a primary namespace to a secondary namespace, and it allows a once-only failover move from the primary to the secondary at any time. Active/Passive feature is designed to make it easier to recover from and abandon a failed Azure region without having to change application configurations", + "guid": "dc15a1c0-75ee-49f1-90ac-ccd579376bcd", + "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-geo-dr?tabs=portal", + "service": "Event Hubs", "services": [ + "ASR", + "EventHubs", "WAF" ], - "severity": "Medium", - "text": "Delete or archive unassociated services (disks, nics, ip addresses etc)", - "waf": "Cost" + "severity": "High", + "text": "Plan for Geo Disaster Recovery using Active Passive configuration", + "waf": "Reliability" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "69bad37a-ad53-4cc7-ae1d-76667357c449", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", - "service": "Azure Backup", + "description": "Should be used for DR configurations where an outage or loss of event data in the downed region cannot be tolerated. For these cases, follow the replication guidance and do not use the built-in geo-disaster recovery capability (active/passive). With Active/Active, Maintain multiple Event Hubs in different regions and namespaces, and events will be replicated between the hubs", + "guid": "6e31b67d-67ba-4591-89c0-9e805d597c7e", + "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-federation-overview", + "service": "Event Hubs", "services": [ - "Storage", "ASR", - "WAF", - "Backup" + "EventHubs", + "WAF" ], "severity": "Medium", - "text": "Consider a good balance between site recovery storage and backup for non mission critical applications", - "waf": "Cost" + "text": "For Business Critical Applications, use Active Active configuration", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "674b5ed8-5a85-49c7-933b-e2a1a27b765a", - "link": "https://learn.microsoft.com/azure/cost-management-billing/manage/direct-ea-administration#manage-notification-contacts", - "service": "Azure Monitor", + "guid": "9ced16ad-d186-4f0a-a241-a999a68af77c", + "link": "https://learn.microsoft.com/azure/architecture/serverless/event-hubs-functions/resilient-design", + "service": "Event Hubs", "services": [ - "WAF", - "Monitor" + "EventHubs", + "WAF" ], "severity": "Medium", - "text": "Check spending and savings opportunities among the 40 different log analytics workspaces- use different retention and data collection for nonprod workspaces-create daily cap for awareness and tier sizing - If you do set a daily cap, in addition to creating an alert when the cap is reached,ensure that you also create an alert rule to be notified when some percentage has been reached (90% for example). - consider workspace transformation if possible - https://learn.microsoft.com/azure/azure-monitor/essentials/data-collection-transformations#workspace-transformation-dcr ", - "training": "https://learn.microsoft.com/azure/cost-management-billing/costs/understand-work-scopes", - "waf": "Cost" + "text": "Design Resilient Event Hubs", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Insights/components", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "91be1f38-8ef3-494c-8bd4-63cbbac75819", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", - "service": "Azure Monitor", + "guid": "21c30d25-ffb7-4f6a-b9ea-b3fec328f787", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/paas-foundations-playbooks-cog_svcs_v1.docx", + "service": "Cognitive Services", "services": [ - "AzurePolicy", - "Storage", "WAF" ], "severity": "Medium", - "text": "Enforce a purging log policy and automation (if needed, logs can be moved to cold storage)", - "training": "https://www.youtube.com/watch?v=nHQYcYGKuyw", - "waf": "Cost" + "text": "Leverage FTA HandBook for Cognitive Services", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "6aae01e6-a84d-4e5d-b36d-1d92881a1bd5", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", - "service": "VM", + "guid": "78c34698-16b2-4763-aefe-1b9b599de0d5", + "link": "https://learn.microsoft.com/azure/ai-services/openai/concepts/advanced-prompt-engineering?pivots=programming-language-chat-completions", + "service": "Cognitive Services", "services": [ - "Storage", - "WAF", - "Backup" + "Backup", + "WAF" ], "severity": "Medium", - "text": "Check that the disks are really needed, if not: delete. If they are needed, find lower storage tiers or use backup -", - "training": "https://learn.microsoft.com/azure/cost-management-billing/costs/manage-automation", - "waf": "Cost" + "text": "Backup Your Prompts", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "d1e44a19-659d-4395-afd7-7289b835556d", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", - "service": "Storage", + "guid": "750ab2ab-039d-4a6d-95d7-c892adb107d5", + "link": "https://learn.microsoft.com/azure/ai-services/openai/how-to/business-continuity-disaster-recovery", + "service": "Cognitive Services", "services": [ - "AzurePolicy", - "Storage", + "ASR", "WAF" ], - "severity": "Medium", - "text": "Consider moving unused storage to lower tier, with customized rule - https://learn.microsoft.com/azure/storage/blobs/lifecycle-management-policy-configure ", - "training": "https://learn.microsoft.com/azure/cost-management-billing/costs/enable-tag-inheritance", - "waf": "Cost" + "severity": "High", + "text": "Business Continuity and Disaster Recovery (BCDR) considerations with Azure OpenAI Service", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "d0102cac-6aae-401e-9a84-de5de36d1d92", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "VM", + "guid": "325af625-ca44-4e46-a5e2-223ace8bb123", + "link": "https://github.com/abacaj/chatgpt-backup#backup-your-chatgpt-conversations", + "service": "Cognitive Services", "services": [ - "VM", + "Backup", "WAF" ], "severity": "Medium", - "text": "Make sure advisor is configured for VM right sizing ", - "waf": "Cost" + "text": "Backup Your ChatGPT conversations", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "description": "check by searching the Meter Category Licenses in the Cost analysys", - "guid": "59ae568b-a38d-4498-9e22-13dbd7bb012f", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/manage/centralize-operations", - "service": "VM", + "guid": "07ca5f17-f154-4e3a-a369-2829e7e31618", + "link": "https://learn.microsoft.com/azure/ai-services/speech-service/how-to-custom-speech-continuous-integration-continuous-deployment", + "service": "Cognitive Services", "services": [ - "AzurePolicy", - "VM", - "WAF", - "Cost" + "WAF" ], "severity": "Medium", - "text": "run the script on all windows VMs https://learn.microsoft.com/azure/virtual-machines/windows/hybrid-use-benefit-licensing?ref=andrewmatveychuk.com#convert-an-existing-vm-using-azure-hybrid-benefit-for-windows-server- consider implementing a policy if windows VMs are created frequently", - "waf": "Cost" + "text": "CI/CD for custom speech", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.CognitiveServices/accounts", "checklist": "WAF checklist", - "guid": "7b95e06e-158e-42ea-9992-c2de6e2065b3", - "link": "https://learn.microsoft.com/azure/active-directory/privileged-identity-management/pim-configure", - "service": "VM", + "guid": "3687a046-7a1f-4893-9bda-43324f248116", + "link": "https://learn.microsoft.com/azure/ai-services/qnamaker/tutorials/export-knowledge-base", + "service": "Cognitive Services", "services": [ - "LoadBalancer", "WAF" ], - "severity": "Medium", - "text": " this can be also put under AHUB if you already have licenses https://learn.microsoft.com/azure/virtual-machines/linux/azure-hybrid-benefit-linux?tabs=rhelpayg%2Crhelbyos%2CrhelEnablebyos%2Crhelcompliance", - "waf": "Cost" + "severity": "Low", + "text": "Move a knowledge base using export-import", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "75c1e945-b459-4837-bf7a-e7c6d3b475a5", - "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-groups-create-azure-portal", - "service": "VM", + "graph": "resources | where type=~'Microsoft.ServiceFabric/managedClusters' | extend compliant = (sku=~'{\"name\":\"Standard\"}') | distinct id,compliant", + "guid": "182840d2-9ef8-4238-8fd6-0d76186830ac", + "link": "https://learn.microsoft.com/azure/service-fabric/overview-managed-cluster#service-fabric-managed-cluster-skus", + "service": "Azure Service Fabric", "services": [ - "VM", "WAF" ], "severity": "Medium", - "text": "Consolidate reserved VM families with flexibility option (no more than 4-5 families)", - "training": "https://learn.microsoft.com/azure/automation/automation-solution-vm-management", - "waf": "Cost" + "text": "Use Standard SKU for production scenarios.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "c7acbe49-bbe6-44dd-a9f2-e87778468d55", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access#prerequisites-for-a-landing-zone---design-recommendations", - "service": "VM", + "graph": "resources | where type=~'Microsoft.ServiceFabric/clusters' | extend nodeTypes= array_concat(properties.nodeTypes) | mv-expand nodeTypes | summarize BronzeDurabilityCount = countif(nodeTypes.durabilityLevel == 'Bronze') by id | extend compliant = (BronzeDurabilityCount == 0) | distinct id,compliant", + "guid": "182840d2-9ef8-4238-8fd6-0d76186830ac", + "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-cluster-capacity#durability-characteristics-of-the-cluster", + "service": "Azure Service Fabric", "services": [ "VM", - "WAF", - "Cost", - "ARS" + "WAF" ], "severity": "Medium", - "text": "Utilize Azure Reserved Instances: This feature allows you to reserve VMs for a period of 1 or 3 years, providing significant cost savings compared to PAYG prices.", - "waf": "Cost" + "text": "Use durability level Silver (5 VMs) or greater for production scenarios", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "a6bcca2b-4fea-41db-b3dd-95d48c7c891d", - "link": "https://learn.microsoft.com/azure/active-directory-domain-services/overview", - "service": "VM", + "graph": "resources | where type=~'Microsoft.ServiceFabric/managedClusters' | extend compliant= ( properties.zonalResiliency =~ 'true') | distinct id,compliant", + "guid": "2363878d-55c4-4cbd-9bc2-94523c85f12e", + "link": "https://learn.microsoft.com/azure/service-fabric/how-to-managed-cluster-availability-zones", + "service": "Azure Service Fabric", "services": [ + "ACR", "WAF" ], "severity": "Medium", - "text": "Only larger disks can be reserved => 1 TiB -", - "waf": "Cost" + "text": "Consider using Availability Zones for your Service Fabric clusters. Service Fabric managed cluster supports deployments that span across multiple Availability Zones to provide zone resiliency. This configuration will ensure high-availability of the critical system services and your applications to protect from single-points-of-failure.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "cb1f7d57-59ae-4568-aa38-d4985e2213db", - "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/identity/adds-extend-domain", - "service": "VM", + "guid": "5ba74cc8-3ca2-44d5-9a67-bdc8e102e7b4", + "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-api-management-overview", + "service": "Azure Service Fabric", "services": [ + "APIM", "WAF" ], "severity": "Medium", - "text": "After the right-sizing optimization", - "waf": "Cost" + "text": "Consider using Azure API Management to expose and offload cross-cutting functionality for APIs hosted on the cluster. API Management can integrate with Service Fabric directly.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Sql/servers", "checklist": "WAF checklist", - "guid": "d7bb012f-7b95-4e06-b158-e2ea3992c2de", - "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy", - "service": "Azure SQL", + "guid": "ef17bb8f-4e2c-488b-8ceb-a07c3d750dd3", + "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-reliable-services-introduction", + "service": "Azure Service Fabric", "services": [ - "AzurePolicy", - "SQL", - "WAF", - "Cost" + "WAF" ], "severity": "Medium", - "text": "Check if applicable and enforce policy/change https://learn.microsoft.com/azure/azure-sql/azure-hybrid-benefit?view=azuresql&tabs=azure-portalhttps://learn.microsoft.com/azure/cost-management-billing/scope-level/create-sql-license-assignments?source=recommendations", - "waf": "Cost" + "text": "For stateful workload scenarios, consider using Reliable Services. The Reliable Services model allows your services to stay up even in unreliable environments where your machines fail or hit network issues, or in cases where the services themselves encounter errors and crash or fail. For stateful services, your state is preserved even in the presence of network or other failures.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "6e2065b3-a76a-4f4a-991e-8839ada46667", - "link": "https://learn.microsoft.com/azure/active-directory/roles/best-practices", - "service": "VM", + "graph": "resources | where type=~'Microsoft.Compute/virtualMachineScaleSets' | extend vmssExtension= array_concat(properties.virtualMachineProfile.extensionProfile.extensions) | mv-expand vmssExtension | where vmssExtension.properties.publisher matches regex '^Microsoft.Azure.ServiceFabric.*' | summarize arg_max(id, *) | summarize compliant = countif(sku.name matches regex '^Standard_[^d]*$' ) by id", + "guid": "4da21268-f775-4c89-a271-eb80543c8df7", + "service": "Azure Service Fabric", "services": [ "VM", "WAF" ], "severity": "Medium", - "text": "The VM + license part discount (ahub + 3YRI) is around 70% discount", + "text": "Avoid VM SKUs with temp disk offerings. Service Fabric uses managed disks by default, so avoiding temp disk offerings ensures you don't pay for unneeded resources.", "waf": "Cost" }, { - "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "ccbd9792-a6bc-4ca2-a4fe-a1dbf3dd95d4", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", - "service": "VM", + "guid": "1890b796-f300-41a3-a8d4-29738c1f4ad0", + "link": "https://learn.microsoft.com/azure/service-fabric/how-to-managed-cluster-stateless-node-type#temporary-disk-support", + "service": "Azure Service Fabric", "services": [ "VM", "WAF" ], "severity": "Medium", - "text": "Consider using a VMSS to match demand rather than flat sizing", + "text": "If you need to select a certain VM SKU for capacity reasons and it happens to offer temp disk, consider using temporary disk support for your stateless workloads.", "waf": "Cost" }, { - "arm-service": "microsoft.containerservice/managedClusters", "checklist": "WAF checklist", - "guid": "c1b1cd52-1e54-4a29-a9de-39ac0e7c28dc", - "link": "https://learn.microsoft.com/azure/reliability/cross-region-replication-azure", - "service": "AKS", + "guid": "5247bb32-6778-49c7-8b40-e171c9a3ce1e", + "service": "Azure Service Fabric", "services": [ - "AKS", "WAF" ], "severity": "Medium", - "text": "Use AKS autoscaler to match your clusters usage (make sure the pods requirements match the scaler)", + "text": "Align SKU selection and managed disk size with workload requirements. Matching your selection to your workload demands ensures you don't pay for unneeded resources.", "waf": "Cost" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "44be3b1a-27f8-4b9e-a1be-1f38df03a822", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/data-retention-archive?tabs=portal-1%2Cportal-2#how-retention-and-archiving-work", - "service": "Azure Backup", + "guid": "6028759b-446a-41bc-8b0e-7728e61ca704", + "link": "https://learn.microsoft.com/azure/service-fabric/how-to-managed-cluster-networking#manage-nsg-rules", + "service": "Azure Service Fabric", "services": [ + "VNet", + "APIM", "WAF" ], "severity": "Medium", - "text": "Move recovery points to vault-archive where applicable (Validate)", - "training": "https://azure.microsoft.com/pricing/reservations/", - "waf": "Cost" + "text": "Ensure Network Security Groups (NSG) are configured to restrict traffic flow between subnets and node types. For example, you may have an API Management instance (one subnet), a frontend subnet (exposing a website directly), and a backend subnet (accessible only to frontend).", + "waf": "Security" }, { - "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "cd463cbb-bc8a-4c29-aebc-91a43da1dae2", - "link": "https://learn.microsoft.com/azure/databricks/clusters/cluster-config-best-practices#automatic-termination", - "service": "Databricks", + "graph": "resources | where type=~'Microsoft.Compute/virtualMachineScaleSets' | extend vmssExtension= array_concat(properties.virtualMachineProfile.extensionProfile.extensions) | mv-expand vmssExtension | where vmssExtension.properties.publisher matches regex '^Microsoft.Azure.ServiceFabric.*' | summarize arg_max(id, *) | extend compliant = (isnotnull(properties.virtualMachineProfile.osProfile.secrets))", + "guid": "4e98c903-14cf-4c72-9c45-b8b23bc4cbd8", + "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-best-practices-security#deploy-key-vault-certificates-to-service-fabric-cluster-virtual-machine-scale-sets", + "service": "Azure Service Fabric", "services": [ + "AKV", + "Storage", + "WAF", "VM", - "LoadBalancer", - "WAF" + "Entra" ], "severity": "Medium", - "text": "Consider using Spot VMs with fallback where possible. Consider autotermination of clusters.", - "waf": "Cost" + "text": "Deploy Key Vault certificates to Service Fabric cluster virtual machine scale sets. Centralizing storage of application secrets in Azure Key Vault allows you to control their distribution. Key Vault greatly reduces the chances that secrets may be accidentally leaked.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "cc881470-607c-41cc-a0e6-14658dd458e9", - "link": "https://learn.microsoft.com/azure/governance/policy/how-to/guest-configuration-create", - "service": "Azure Functions", + "guid": "001cbb6f-d88d-4431-8434-d01333397776", + "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-best-practices-security#apply-an-access-control-list-acl-to-your-certificate-for-your-service-fabric-cluster", + "service": "Azure Service Fabric", "services": [ "WAF" ], "severity": "Medium", - "text": "Functions - Reuse connections", - "training": "https://learn.microsoft.com/azure/cost-management-billing/reservations/reservation-apis?toc=%2Fazure%2Fcost-management-billing%2Ftoc.json", - "waf": "Cost" + "text": "Apply an Access Control List (ACL) to your client certificate for your Service Fabric cluster. Using an ACL provides an additional level of authentication.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "27139b82-1102-4dbd-9eaf-11e6f843e52f", - "link": "https://learn.microsoft.com/azure/automation/update-management/overview", - "service": "Azure Functions", + "guid": "4b74b7a5-bb1e-4fca-948c-037ba95fb73b", + "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-resource-governance#resource-governance-mechanism", + "service": "Azure Service Fabric", "services": [ + "ACR", "WAF" ], "severity": "Medium", - "text": "Functions - Cache data locally", - "training": "https://learn.microsoft.com/learn/paths/azure-administrator-manage-compute-resources/", - "waf": "Cost" + "text": "Use resource requests and limits to govern resource usage across the nodes in your cluster. Enforcing resource limits helps ensure that one service doesn't consume too many resources and starve other services.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "4722d928-c1b1-4cd5-81e5-4a29b9de39ac", - "link": "https://learn.microsoft.com/azure/network-watcher/network-watcher-monitoring-overview", - "service": "Azure Functions", + "guid": "cd9233ba-f3aa-4353-8d2f-7ea4a64160e6", + "link": "", + "service": "Azure Service Fabric", "services": [ - "Storage", "WAF" ], "severity": "Medium", - "text": "Functions - Cold starts-Use the 'Run from package' functionality. This way, the code is downloaded as a single zip file. This can, for example, result in significant improvements with Javascript functions, which have a lot of node modules.Use language specific tools to reduce the package size, for example, tree shaking Javascript applications.", - "training": "https://learn.microsoft.com/learn/modules/configure-network-watcher/", - "waf": "Cost" + "text": "Encrypt Service Fabric package secret values. Encryption on your secret values provides an additional level of security.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "0e7c28dc-9366-4572-82bf-f4564b0d934a", - "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", - "service": "Azure Functions", + "guid": "44b989d4-9f72-42b6-99da-ec2a79f83299", + "link": "", + "service": "Azure Service Fabric", "services": [ + "AKV", "WAF" ], "severity": "Medium", - "text": "Functions - Keep your functions warm", - "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", - "waf": "Cost" + "text": "Include client certificates in Service Fabric applications. Having your applications use client certificates for authentication provides opportunities for security at both the cluster and workload level.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "359c363e-7dd6-4162-9a36-4a907ebae38e", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "service": "Azure Functions", + "guid": "28e66ff7-4a77-4b2c-910d-0335f141208a", + "link": "https://learn.microsoft.com/azure/service-fabric/how-to-managed-identity-managed-cluster-virtual-machine-scale-sets", + "service": "Azure Service Fabric", "services": [ + "Entra", "WAF" ], "severity": "Medium", - "text": "When using autoscale with different functions, there might be one driving all the autoscale for all the resources - consider moving it to a separate consumption plan (and consider higher plan for CPU)", - "waf": "Cost" + "text": "Authenticate Service Fabric applications to Azure Resources using Managed Identity. Using Managed Identity allow you to securely manage the credentials in your code for authenticating to various services without saving them locally on a developer workstation or in source control.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "ad53cc7d-e2e8-4aaa-a357-1549ab9153d8", - "link": "https://learn.microsoft.com/azure/service-health/alerts-activity-log-service-notifications-portal", - "service": "Azure Functions", + "guid": "f16c413c-00a6-43aa-852c-b97292c33a56", + "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-best-practices-security#hosting-untrusted-applications-in-a-service-fabric-cluster", + "service": "Azure Service Fabric", "services": [ "WAF" ], "severity": "Medium", - "text": "Function apps in a given plan are all scaled together, so any issues with scaling can affect all apps in the plan.", - "waf": "Cost" + "text": "Follow Service Fabric best practices when hosting untrusted applications. Following the best practices provides a security standard to follow.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.AppPlatform/Spring", "checklist": "WAF checklist", - "guid": "9f89dc7b-44be-43b1-a27f-8b9e91be1f38", - "link": "https://learn.microsoft.com/azure/azure-monitor/alerts/action-groups", - "service": "Azure Functions", + "guid": "6d8e32a8-3892-479d-a40b-10f6b4f6f298", + "link": "https://learn.microsoft.com/azure/spring-apps/concepts-blue-green-deployment-strategies", + "service": "Spring Apps", "services": [ "WAF" ], "severity": "Medium", - "text": "Am I billed for 'await time'? This question is typically asked in the context of a C# function that does an async operation and waits for the result, e.g. await Task.Delay(1000) or await client.GetAsync('http://google.com'). The answer is yes - the GB second calculation is based on the start and end time of the function and the memory usage over that period. What actually happens over that time in terms of CPU activity is not factored into the calculation.One exception to this rule is if you are using durable functions. You are not billed for time spent at awaits in orchestrator functions.apply demand shaping techinques where possible (dev environments?) https://github.com/Azure-Samples/functions-csharp-premium-scaler", - "waf": "Cost" + "text": "Azure Spring Apps permits two deployments for every app, only one of which receives production traffic. You can achieve zero downtime with blue green deployment strategies. Blue green deployment is only available in Standard and Enterprise tiers. You could automate deployment using CI/CD with ADO/GitHub actions", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.AppPlatform/Spring", "checklist": "WAF checklist", - "guid": "3da1dae2-cc88-4147-8607-c1cca0e61465", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", - "service": "Front Door", + "guid": "fbcb40ac-9480-4a6d-bcf4-8081252a6716", + "link": "https://learn.microsoft.com/azure/architecture/web-apps/spring-apps/architectures/spring-apps-multi-region", + "service": "Spring Apps", "services": [ - "EventHubs", - "WAF", - "FrontDoor" + "FrontDoor", + "TrafficManager", + "WAF" ], "severity": "Medium", - "text": "Frontdoor - Turn off the default homepageIn the application settings of your App, set AzureWebJobsDisableHomepage to true. This will return a 204 (No Content) to the PoP so only header data is returned.", - "waf": "Cost" + "text": "Azure Spring Apps instances could be created in multiple regions for your applications and traffic could be routed by Traffic Manager/Front Door.", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/frontdoors", + "arm-service": "Microsoft.AppPlatform/Spring", "checklist": "WAF checklist", - "guid": "8dd458e9-2713-49b8-8110-2dbd6eaf11e6", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-setup-guide/monitoring-reporting?tabs=AzureMonitor", - "service": "Front Door", + "guid": "ff1ae6a7-9301-4feb-9d11-56cd72f1d4ef", + "link": "https://learn.microsoft.com/azure/reliability/reliability-spring-apps", + "service": "Spring Apps", "services": [ - "AppSvc", - "WAF", - "FrontDoor" + "ACR", + "WAF" ], "severity": "Medium", - "text": "Frontdoor - Route to something that returns nothing. Either set up a Function, Function Proxy, or add a route in your WebApp that returns 200 (OK) and sends no or minimal content. The advantage of this is you will be able to log out when it is called.", - "waf": "Cost" + "text": "In supported region, Azure Spring Apps can be deployed as zone redundant, which means that instances are automatically distributed across availability zones. This feature is only available in Standard and Enterprise tiers.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AppPlatform/Spring", "checklist": "WAF checklist", - "guid": "7e31c67d-68cf-46a6-8a11-94956d697dc3", - "link": "https://learn.microsoft.com/azure/architecture/best-practices/monitoring", - "service": "Storage", + "guid": "ffc735ad-fbb1-4802-b43f-ad6387c4c066", + "link": "https://learn.microsoft.com/azure/spring-apps/concept-understand-app-and-deployment", + "service": "Spring Apps", "services": [ "WAF" ], "severity": "Medium", - "text": "Consider archiving tiers for less used data", - "waf": "Cost" + "text": "Use more than 1 app instance for your apps", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.AppPlatform/Spring", "checklist": "WAF checklist", - "guid": "a2ed27b2-d186-4f1a-8252-bddde68a487c", - "link": "https://learn.microsoft.com/azure/automation/how-to/region-mappings", - "service": "VM", + "guid": "7504c230-6035-4183-95a5-85762acc6075", + "link": "https://learn.microsoft.com/azure/spring-apps/diagnostic-services", + "service": "Spring Apps", "services": [ + "Monitor", "WAF" ], "severity": "Medium", - "text": "Check disk sizes where the size does not match the tier (i.e. A 513 GiB disk will pay a P30 (1TiB) and consider resizing", - "waf": "Cost" + "text": "Monitor Azure Spring Apps with logs, metrics and tracing. Integrate ASA with application insights and track failures and create workbooks.", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AppPlatform/Spring", "checklist": "WAF checklist", - "guid": "dec4861b-c3bc-410a-b77e-26e4d5a3bec2", - "link": "https://learn.microsoft.com/azure/governance/policy/concepts/guest-configuration", - "service": "Storage", + "guid": "1eb48d58-3eec-4ef5-80b0-d2b0dde3f0c6", + "link": "https://learn.microsoft.com/azure/spring-apps/how-to-configure-enterprise-spring-cloud-gateway", + "service": "Spring Apps", "services": [ "WAF" ], "severity": "Medium", - "text": "Consider using standard SSD rather than Premium or Ultra where possible", - "waf": "Cost" + "text": "Set up autoscaling in Spring Cloud Gateway", + "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.AppPlatform/Spring", "checklist": "WAF checklist", - "guid": "c4e2436b-1336-4db5-9f17-960eee0bdf5c", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#monitoring-for-configuration-drift", - "service": "Storage", + "guid": "97411607-b6fd-4335-99d1-9885faf4e392", + "link": "https://learn.microsoft.com/azure/spring-apps/how-to-setup-autoscale", + "service": "Spring Apps", + "services": [ + "WAF" + ], + "severity": "Low", + "text": "Enable autoscale for the apps with Standard consumption & dedicated plan.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.AppPlatform/Spring", + "checklist": "WAF checklist", + "guid": "dfcaffd1-d27c-4ef2-998d-64c1df3a7ac3", + "link": "https://learn.microsoft.com/azure/spring-apps/overview", + "service": "Spring Apps", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Use Enterprise plan for commercial support of spring boot for mission critical apps. With other tiers you get OSS support.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.ServiceBus/namespaces", + "checklist": "WAF checklist", + "description": "Azure Service Bus Premium provides encryption of data at rest. If you use your own key, the data is still encrypted using the Microsoft-managed key, but in addition the Microsoft-managed key will be encrypted using the customer-managed key. ", + "guid": "87af4a79-1f89-439b-ba47-768e14c11567", + "link": "https://learn.microsoft.com/azure/service-bus-messaging/configure-customer-managed-key", + "service": "Service Bus", "services": [ - "Storage", + "ServiceBus", "WAF" ], - "severity": "Medium", - "text": "For storage accounts, make sure that the chosen tier is not adding up transaction charges (it might be cheaper to move to the next tier)", - "waf": "Cost" + "severity": "Low", + "text": "Use customer-managed key option in data at rest encryption when required", + "training": "https://learn.microsoft.com/learn/modules/plan-implement-administer-conditional-access/", + "waf": "Security" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", + "arm-service": "Microsoft.ServiceBus/namespaces", "checklist": "WAF checklist", - "guid": "c2efc5d7-61d4-41d2-900b-b47a393a040f", - "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", - "service": "Site Recovery", + "description": "Communication between a client application and an Azure Service Bus namespace is encrypted using Transport Layer Security (TLS). Azure Service Bus namespaces permit clients to send and receive data with TLS 1.0 and above. To enforce stricter security measures, you can configure your Service Bus namespace to require that clients send and receive data with a newer version of TLS.", + "guid": "5c1ea55b-46a9-448f-b8ae-7d7e4b475b6c", + "link": "https://learn.microsoft.com/azure/service-bus-messaging/transport-layer-security-enforce-minimum-version", + "service": "Service Bus", "services": [ - "ASR", + "ServiceBus", "WAF" ], "severity": "Medium", - "text": "For ASR, consider using Standard SSD disks if the RPO/RTO and replication throughput allow it", - "waf": "Cost" + "text": "Enforce a minimum required version of Transport Layer Security (TLS) for requests ", + "training": "https://learn.microsoft.com/learn/modules/secure-aad-users-with-mfa/", + "waf": "Security" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "Microsoft.ServiceBus/namespaces", "checklist": "WAF checklist", - "guid": "d3294798-b118-48b2-a5a4-6ceb544451e1", - "link": "https://learn.microsoft.com/azure/architecture/framework/resiliency/backup-and-recovery", - "service": "Storage", + "description": "When you create a Service Bus namespace, a SAS rule named RootManageSharedAccessKey is automatically created for the namespace. This policy has Manage permissions for the entire namespace. It's recommended that you treat this rule like an administrative root account and don't use it in your application. Using AAD as an authentication provider with RBAC is recommended. ", + "guid": "8bcbf59b-ce65-4de8-a03f-97879468d66a", + "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-sas#shared-access-authorization-policies", + "service": "Service Bus", "services": [ - "Storage", - "WAF" + "AzurePolicy", + "RBAC", + "TrafficManager", + "WAF", + "ServiceBus", + "Entra" ], "severity": "Medium", - "text": "Storage accounts: check hot tier and/or GRS necessary", - "waf": "Cost" + "text": "Avoid using root account when it is not necessary", + "training": "https://learn.microsoft.com/learn/paths/azure-administrator-manage-identities-governance/", + "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.ServiceBus/namespaces", "checklist": "WAF checklist", - "guid": "92d34429-3c76-4286-97a5-51c5b04e4f18", - "link": "https://learn.microsoft.com/azure/backup/backup-center-overview", - "service": "VM", + "description": "Microsoft Entra ID provides superior security and ease of use over shared access signatures (SAS). With Microsoft Entra ID, there’s no need to store the tokens in your code and risk potential security vulnerabilities. We recommend that you use Microsoft Entra ID with your Azure Service Bus applications when possible.", + "graph": "Resources | where type =~ 'microsoft.servicebus/namespaces' | extend compliant = iif(properties.disableLocalAuth == 'false', 'No', 'Yes') | project id, compliant", + "guid": "786d60f9-6c96-4ad8-a55d-04c2b39c986b", + "link": "https://learn.microsoft.com/en-us/azure/service-bus-messaging/disable-local-authentication", + "service": "Service Bus", "services": [ + "ServiceBus", + "Entra", "WAF" ], "severity": "Medium", - "text": "Disks - validate use of Premium SSD disks everywhere: for example, non-prod could swap to Standard SSD or on-demand Premium SSD ", - "waf": "Cost" + "text": "When possible, disable SAS key authentication (or local authentication) and use only Microsoft Entra ID for authentication", + "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", + "waf": "Security" }, { - "arm-service": "Microsoft.Synapse/workspaces", + "arm-service": "Microsoft.ServiceBus/namespaces", "checklist": "WAF checklist", - "guid": "54387e5c-ed12-46cd-832a-f5b2fc6998a5", - "link": "https://learn.microsoft.com/azure/reliability/availability-zones-overview", - "service": "Synapse", + "description": "When creating permissions, provide fine-grained control over a client's access to Azure Service Bus. Permissions in Azure Service Bus can and should be scoped to the individual resource level e.g. queue, topic or subscription. ", + "guid": "f615658d-e558-4f93-9249-b831112dbd7e", + "link": "https://learn.microsoft.com/azure/service-bus-messaging/authenticate-application#azure-built-in-roles-for-azure-service-bus", + "service": "Service Bus", "services": [ - "EventHubs", "WAF", - "Cost", - "Monitor" + "Storage", + "RBAC", + "Subscriptions", + "ServiceBus" ], - "severity": "Medium", - "text": "Create budgets to manage costs and create alerts that automatically notify stakeholders of spending anomalies and overspending risks.", - "waf": "Cost" + "severity": "High", + "text": "Use least privilege data plane RBAC", + "training": "https://learn.microsoft.com/learn/modules/explore-basic-services-identity-types/", + "waf": "Security" }, { - "arm-service": "Microsoft.Synapse/workspaces", + "arm-service": "Microsoft.ServiceBus/namespaces", "checklist": "WAF checklist", - "guid": "35e33789-7e31-4c67-b68c-f6a62a119495", - "link": "https://learn.microsoft.com/azure/virtual-machines/availability", - "service": "Synapse", + "description": "Azure Service Bus resource logs include operational logs, virtual network and IP filtering logs. Runtime audit logs capture aggregated diagnostic information for various data plane access operations (such as send or receive messages) in Service Bus.", + "guid": "af12e7f9-43f6-4304-922d-929c2b1cd622", + "link": "https://learn.microsoft.com/azure/service-bus-messaging/monitor-service-bus-reference", + "service": "Service Bus", "services": [ - "Storage", - "WAF", - "Cost" + "ServiceBus", + "VNet", + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Export cost data to a storage account for additional data analysis.", - "waf": "Cost" + "text": "Enable logging for security investigation. Use Azure Monitor to trace resource logs and runtime audit logs (currently available only in the premium tier)", + "training": "https://learn.microsoft.com/learn/paths/manage-identity-and-access/", + "waf": "Security" }, { - "arm-service": "Microsoft.Synapse/workspaces", + "arm-service": "Microsoft.ServiceBus/namespaces", "checklist": "WAF checklist", - "guid": "6d697dc3-a2ed-427b-8d18-6f1a1252bddd", - "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", - "service": "Synapse", + "description": "Azure Service Bus by default has a public IP address and is Internet-reachable. Private endpoints allow traffic between your virtual network and Azure Service Bus traverses over the Microsoft backbone network. In addition to that, you should disable public endpoints if those are not used. ", + "guid": "9ae669ca-48e4-4a85-b222-3ece8bb12307", + "link": "https://learn.microsoft.com/azure/service-bus-messaging/private-link-service", + "service": "Service Bus", "services": [ - "SQL", - "WAF", - "Cost" + "VNet", + "ServiceBus", + "PrivateLink", + "WAF" ], "severity": "Medium", - "text": "Control costs for a dedicated SQL pool by pausing the resource when it is not in use.", - "waf": "Cost" + "text": "Consider using private endpoints to access Azure Service Bus and disable public network access when applicable.", + "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", + "waf": "Security" }, { - "arm-service": "Microsoft.Synapse/workspaces", + "arm-service": "Microsoft.ServiceBus/namespaces", "checklist": "WAF checklist", - "guid": "e68a487c-dec4-4861-ac3b-c10ae77e26e4", - "link": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/overview", - "service": "Synapse", + "description": "With IP firewall, you can restrict the public endpoint further to only a set of IPv4 addresses or IPv4 address ranges in CIDR (Classless Inter-Domain Routing) notation. ", + "guid": "ca5f06f1-58e3-4ea3-a92c-2de7e2165c3a", + "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-ip-filtering", + "service": "Service Bus", "services": [ + "ServiceBus", "WAF" ], "severity": "Medium", - "text": "Enable the serverless Apache Spark automatic pause feature and set your timeout value accordingly.", - "waf": "Cost" + "text": "Consider only allowing access to Azure Service Bus namespace from specific IP addresses or ranges", + "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", + "waf": "Security" }, { "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "d5a3bec2-c4e2-4436-a133-6db55f17960e", - "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-latest-version-for-customer-managed-certificates", - "service": "Synapse", + "description": "Restrict the use of local authentication methods for data plane access. Instead, use Microsoft Entra ID as the default authentication method to control your data plane access.", + "guid": "32d41e36-11c8-417b-8afb-c410d4391898", + "service": "Azure Synapse Analytics", "services": [ + "Entra", + "SQL", "WAF" ], - "severity": "Medium", - "text": "Create multiple Apache Spark pool definitions of various sizes.", - "waf": "Cost" + "severity": "High", + "text": "Restrict use of local users on sql workloads on Synapse", + "waf": "Security" }, { "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "ee0bdf5c-c2ef-4c5d-961d-41d2500bb47a", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups#management-groups-in-the-azure-landing-zone-accelerator", - "service": "Synapse", + "description": "Use Microsoft Entra ID as the default authentication method to control your data plane access.", + "guid": "cd289bed-6b17-4cb8-8454-61e1aee3453a", + "link": "https://learn.microsoft.com/azure/synapse-analytics/synapse-service-identity?context=%2Fazure%2Fsynapse-analytics%2Fcontext%2Fcontext", + "service": "Azure Synapse Analytics", "services": [ - "WAF", - "Cost" + "Entra", + "WAF" ], "severity": "Medium", - "text": "Purchase Azure Synapse commit units (SCU) for one year with a pre-purchase plan to save on your Azure Synapse Analytics costs.", - "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", - "waf": "Cost" + "text": "Use managed identity to authenticate to the services", + "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "393a040f-d329-4479-ab11-88b2c5a46ceb", - "link": "https://learn.microsoft.com/azure/application-gateway/overview-v2", - "service": "VM", + "description": "If not required for routine administrative operations, disable or restrict any local admin accounts for only emergency use.", + "guid": "ec823923-7a15-42d6-ac5e-402925388e5d", + "service": "Azure Synapse Analytics", "services": [ - "VM", - "WAF", - "Cost" + "Entra", + "AzurePolicy", + "WAF" ], - "severity": "Medium", - "text": "Use Spot VMs for interruptible jobs: These are VMs that can be bid on and purchased at a discounted price, providing a cost-effective solution for non-critical workloads.", - "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", - "waf": "Cost" + "severity": "High", + "text": "Separate and limit highly privileged/administrative users and enable MFA and conditional policies", + "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "544451e1-92d3-4442-a3c7-628637a551c5", - "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", - "service": "VM", + "description": "Azure Synapse also includes Synapse role-based access control (RBAC) roles to manage different aspects of Synapse Studio. Leverage these built-in roles to assign permissions to users, groups, or other security principals to manage who can Publish code artifacts and list or access published code artifacts,Execute code on Apache Spark pools and integration runtimes,Access linked (data) services that are protected by credentials,Monitor or cancel job executions, review job output and execution logs.", + "guid": "a9c27d9c-42bb-46cd-8c79-99a246f3389a", + "link": "https://learn.microsoft.com/azure/synapse-analytics/security/synapse-workspace-understand-what-role-you-need", + "service": "Azure Synapse Analytics", "services": [ - "VM", + "Storage", + "RBAC", + "Monitor", "WAF" ], "severity": "Medium", - "text": "Right-sizing all VMs", - "waf": "Cost" + "text": "Use Azure RBAC to control access on storage and Synapse RBAC to control access on workspace level depending on the personas of the team to fine grain the access on data and compute", + "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "b04e4f18-5438-47e5-aed1-26cd032af5b2", - "link": "https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet", - "service": "VM", + "guid": "7f42c78e-78cb-46a2-8ad1-a0916e6a8d8f", + "link": "https://learn.microsoft.com/sql/relational-databases/security/row-level-security?view=sql-server-ver16&context=%2Fazure%2Fsynapse-analytics%2Fcontext%2Fcontext", + "service": "Azure Synapse Analytics", "services": [ - "VM", + "SQL", "WAF" ], "severity": "Medium", - "text": "Swap VM sized with normalized and most recent sizes", - "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", - "waf": "Cost" + "text": "Implement RLS, CLS and data masking on sql workloads in dedicated sql pool to add additional layer of security", + "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "fc6998a5-35e3-4378-a7e3-1c67d68cf6a6", - "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", - "service": "VM", + "description": "When you create your Azure Synapse workspace, you can choose to associate it to a Microsoft Azure Virtual Network. The Virtual Network associated with your workspace is managed by Azure Synapse. This Virtual Network is called a Managed workspace Virtual Network. This can be selected when deploying a workspace", + "guid": "e2436b03-36db-455e-8796-0eee0bdf4cc2", + "link": "https://learn.microsoft.com/azure/synapse-analytics/security/synapse-workspace-managed-vnet?view=sql-server-ver16", + "service": "Azure Synapse Analytics", "services": [ - "VM", - "WAF", - "Monitor" + "VNet", + "WAF" ], "severity": "Medium", - "text": "right-sizing VMs - start with monitoring usage below 5% and then work up to 40%", - "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", - "waf": "Cost" + "text": "Use managed vnet workspace to restrict the access over public internet", + "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "2a119495-6d69-47dc-9a2e-d27b2d186f1a", - "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", - "service": "VM", + "description": "To protect any sensitive data, it's recommended to disable public access to the workspace endpoints entirely. By doing so, it ensures all workspace endpoints can only be accessed using�private endpoints.", + "guid": "efc4d761-c31d-425f-bbb4-7a393a040ed3", + "link": "https://learn.microsoft.com/azure/synapse-analytics/security/synapse-workspace-managed-private-endpoints?view=sql-server-ver16", + "service": "Azure Synapse Analytics", "services": [ - "VM", + "PrivateLink", "WAF" ], "severity": "Medium", - "text": "Containerizing an application can improve VM density and save money on scaling it", - "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", - "waf": "Cost" + "text": "Configure private endpoints to connect to the external services and disable public access", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/provisioningServices", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "cb26b2ba-a9db-45d1-8260-d9c6ec1447d9", - "link": "https://learn.microsoft.com/en-us/azure/logic-apps/single-tenant-overview-compare", - "service": "IoT Hub DPS", + "description": "If public access needs to be enabled, it's highly recommended to configure the IP firewall rules to allow inbound connections only from the specified list of public IP addresses.", + "guid": "294798b1-178a-42c5-a46c-eb544350d092", + "link": "https://learn.microsoft.com/azure/synapse-analytics/security/synapse-workspace-ip-firewall", + "service": "Azure Synapse Analytics", "services": [ "WAF" ], - "severity": "High", - "text": "Select the right Logic App hosting plan based on your business & SLO requirements", - "waf": "Reliability" + "text": "If enabling public access highly recommended to configure IP firewall rules", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/provisioningServices", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "f6dd7977-1123-4f39-b488-f91415a8430a", - "link": "https://learn.microsoft.com/en-us/azure/logic-apps/set-up-zone-redundancy-availability-zones?tabs=standard#next-steps", - "service": "IoT Hub DPS", + "guid": "d234292b-7528-4537-a551-c5bf4e4f1854", + "link": "https://learn.microsoft.com/azure/data-factory/create-self-hosted-integration-runtime?tabs=data-factory", + "service": "Azure Synapse Analytics", "services": [ + "VNet", + "VM", "WAF" ], - "severity": "High", - "text": "Protect logic apps from region failures with zone redundancy and availability zones", - "waf": "Reliability" + "severity": "Medium", + "text": "Deploy SHIR VMs in your vnet if you are working with sensitive data that shouldn�t leave your corporate network", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/provisioningServices", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "8aed4fbf-0830-4883-899d-222a154af478", - "link": "https://learn.microsoft.com/en-us/azure/logic-apps/business-continuity-disaster-recovery-guidance?toc=%2Fazure%2Freliability%2Ftoc.json&bc=%2Fazure%2Freliability%2Fbreadcrumb%2Ftoc.json", - "service": "IoT Hub DPS", + "description": "This can be done only when deploying the workspace, but Python libraries installed from public repositories like PyPI are not supported. (Think about the limitation before enabling it)", + "guid": "287d5cdc-126c-4c03-8af5-b1fc6898a535", + "link": "https://learn.microsoft.com/azure/synapse-analytics/security/how-to-create-a-workspace-with-data-exfiltration-protection", + "service": "Azure Synapse Analytics", "services": [ "WAF" ], - "severity": "High", - "text": "Consider a Cross-Region DR strategy for critical workloads", - "waf": "Reliability" + "severity": "Medium", + "text": "Enable Data Exfiltration Protection (DEP)", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/provisioningServices", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "da0f033e-d180-4f36-9aa4-c468dba14203", - "link": "https://learn.microsoft.com/en-us/azure/app-service/environment/intro", - "service": "IoT Hub DPS", + "description": "First layer of encryption is done by Microsoft managed keys, you can add a second layer of encryption using Customer managed Keys", + "guid": "e337897e-31b6-47d6-9be5-962a1193846d", + "link": "https://learn.microsoft.com/azure/synapse-analytics/security/workspaces-encryption", + "service": "Azure Synapse Analytics", "services": [ - "AppSvc", + "AKV", "WAF" ], - "severity": "High", - "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", - "waf": "Reliability" + "severity": "Medium", + "text": "Data Encryption at rest using Customer managed Keys for workspace", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/provisioningServices", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "62711604-c9d1-4b0a-bdb7-5fda54a4f6c1", - "link": "https://learn.microsoft.com/en-us/training/modules/deploy-azure-functions/", - "service": "IoT Hub DPS", + "description": "Azure Synapse leverages TLS to ensure data is encrypted in motion. SQL dedicated pools support TLS 1.0, TLS 1.1, and TLS 1.2 versions for encryption wherein Microsoft-provided drivers use TLS 1.2 by default. Serverless SQL pool and Apache Spark pool use TLS 1.2 for all outbound connections.", + "guid": "697cc391-ed16-4b2d-886f-0a1241bddde6", + "link": "https://learn.microsoft.com/azure/synapse-analytics/guidance/security-white-paper-data-protection#data-in-transit", + "service": "Azure Synapse Analytics", "services": [ + "SQL", "WAF" ], "severity": "Medium", - "text": "Leverage Azure DevOps or GitHub to streamline CI/CD and safeguard your Logic App code", - "waf": "Operations" + "text": "Data Encryption in transit ", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/deviceUpdateServices", + "arm-service": "Microsoft.Synapse/workspaces", "checklist": "WAF checklist", - "guid": "0e03f5ee-4648-423c-bb86-7239480f9171", - "link": "https://learn.microsoft.com/en-us/azure/iot-dps/iot-dps-ha-dr#high-availability", - "service": "Device Update for IoT Hub", + "description": "Use Keyvaults to store your secrets and credentials", + "guid": "8a477cde-b486-41bc-9bc1-0ae66e25e4d5", + "service": "Azure Synapse Analytics", "services": [ + "AKV", "WAF" ], "severity": "High", - "text": "Leverage Availability Zones if regionally applicable (this is automatically enabled).", - "waf": "Reliability" + "text": "Store passwords, secerts and keys in Azure key vault", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/deviceUpdateServices", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "c0c273bd-00ad-419a-9f2f-fc72fb181e55", - "link": "https://learn.microsoft.com/en-us/azure/iot-dps/iot-dps-ha-dr#high-availability", - "service": "Device Update for IoT Hub", + "description": "Restrict the use of local authentication methods for data plane access. Instead, use Microsoft Entra ID as the default authentication method to control your data plane access.", + "guid": "0bdf4cc2-efc4-4d76-8c31-d25ffbb47a39", + "service": "Azure Data Factory", "services": [ + "Entra", "WAF" ], "severity": "High", - "text": "Be aware of Microsoft-initiated failovers. These are exercised by Microsoft in rare situations to fail over all the DPS instances from an affected region to the corresponding geo-paired region.", - "waf": "Reliability" + "text": "Restrict use of local users whereever necessary", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/deviceUpdateServices", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "3af8abe6-07eb-4287-b393-6c4abe3702eb", - "link": "https://learn.microsoft.com/en-us/azure/logic-apps/business-continuity-disaster-recovery-guidance?toc=%2Fazure%2Freliability%2Ftoc.json&bc=%2Fazure%2Freliability%2Fbreadcrumb%2Ftoc.json", - "service": "Device Update for IoT Hub", + "description": "Managed identities eliminate the need to manage credentials. Managed identities provide an identity for the service instance when connecting to resources that support Microsoft Entra authentication.", + "guid": "3a040ed3-2947-498b-8178-a2c5a46ceb54", + "link": "https://learn.microsoft.com/azure/data-factory/data-factory-service-identity", + "service": "Azure Data Factory", "services": [ + "Entra", "WAF" ], - "severity": "High", - "text": "Consider a Cross-Region DR strategy for critical workloads", - "waf": "Reliability" + "severity": "Medium", + "text": "Use managed identity to authenticate to the services", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/deviceUpdateServices", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "guid": "bd91245c-fe32-4e98-a085-794a40f4bfe1", - "link": "https://learn.microsoft.com/en-us/azure/app-service/environment/intro", - "service": "Device Update for IoT Hub", + "description": "If not required for routine administrative operations, disable or restrict any local admin accounts for only emergency use.", + "guid": "4350d092-d234-4292-a752-8537a551c5bf", + "service": "Azure Data Factory", "services": [ - "AppSvc", + "Entra", + "AzurePolicy", "WAF" ], "severity": "High", - "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", - "waf": "Reliability" + "text": "Separate and limit highly privileged/administrative users and enable MFA and conditional policies", + "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "description": "Azure Event Hub provides encryption of data at rest. If you use your own key, the data is still encrypted using the Microsoft-managed key, but in addition the Microsoft-managed key will be encrypted using the customer-managed key. ", - "guid": "7aaf12e7-b94e-4f6e-847d-2d92981b1cd6", - "link": "https://learn.microsoft.com/azure/event-hubs/configure-customer-managed-key", - "service": "Event Hubs", + "guid": "6898a535-e337-4897-b31b-67d67be5962a", + "service": "Azure Data Factory", "services": [ - "EventHubs", + "VNet", + "VM", "WAF" ], - "severity": "Low", - "text": "Use customer-managed key option in data at rest encryption when required", - "training": "https://learn.microsoft.com/learn/modules/plan-implement-administer-conditional-access/", + "severity": "Medium", + "text": "Deploy SHIR VMs in your vnet if you are working with sensitive data that shouldn�t leave your corporate network", "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "description": "Azure Event Hubs namespaces permit clients to send and receive data with TLS 1.0 and above. To enforce stricter security measures, you can configure your Event Hubs namespace to require that clients send and receive data with a newer version of TLS. If an Event Hubs namespace requires a minimum version of TLS, then any requests made with an older version will fail. ", - "guid": "d2f54b29-769e-43a6-a0e7-828ac936657e", - "link": "https://learn.microsoft.com/azure/event-hubs/transport-layer-security-configure-minimum-version", - "service": "Event Hubs", + "description": "When you create an Azure integration runtime within a Data Factory managed virtual network, the integration runtime is provisioned with the managed virtual network. It uses private endpoints to securely connect to supported data stores.", + "guid": "1193846d-697c-4c39-8ed1-6b2d186f0a12", + "service": "Azure Data Factory", "services": [ - "EventHubs", + "PrivateLink", + "VNet", "WAF" ], "severity": "Medium", - "text": "Enforce a minimum required version of Transport Layer Security (TLS) for requests ", - "training": "https://learn.microsoft.com/learn/modules/secure-aad-users-with-mfa/", + "text": "Use managed vnet IR to restrict the access over public internet for Azure Integration Runtime", "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "description": "When you create an Event Hubs namespace, a policy rule named RootManageSharedAccessKey is automatically created for the namespace. This policy has manage permissions for the entire namespace. It�s recommended that you treat this rule like an administrative root account and don�t use it in your application. Using AAD as an authentication provider with RBAC is recommended. ", - "guid": "13b0f566-4b1e-4944-a459-837ee79d6c6d", - "link": "https://learn.microsoft.com/azure/event-hubs/authorize-access-shared-access-signature#shared-access-authorization-policies", - "service": "Event Hubs", + "description": "Managed private endpoints are private endpoints created in the Data Factory managed virtual network that establishes a private link to Azure resources. Data Factory manages these private endpoints on your behalf.", + "guid": "41bddde6-8a47-47cd-bb48-61bc3bc10ae6", + "link": "https://learn.microsoft.com/azure/data-factory/managed-virtual-network-private-endpoint#managed-private-endpoints", + "service": "Azure Data Factory", "services": [ - "Entra", - "TrafficManager", + "VNet", + "PrivateLink", "EventHubs", - "AzurePolicy", - "RBAC", "WAF" ], "severity": "Medium", - "text": "Avoid using root account when it is not necessary", - "training": "https://learn.microsoft.com/learn/paths/azure-administrator-manage-identities-governance/", + "text": "Configure managed private endpoints to connect to resources using managed azure IR", "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "description": "Managed identities for Azure resources can authorize access to Event Hubs resources using Azure AD credentials from applications running in Azure Virtual Machines (VMs), Function apps, Virtual Machine Scale Sets, and other services. By using managed identities for Azure resources together with Azure AD authentication, you can avoid storing credentials with your applications that run in the cloud. ", - "guid": "3a365a5c-7acb-4e48-abd5-4cd79f2e8776", - "link": "https://learn.microsoft.com/azure/event-hubs/authenticate-managed-identity?tabs=latest", - "service": "Event Hubs", + "description": "This is a default setting", + "guid": "6ceb5443-5135-4922-9442-93bb628637a5", + "service": "Azure Data Factory", "services": [ - "VM", - "Entra", - "Storage", - "EventHubs", "AKV", "WAF" ], "severity": "Medium", - "text": "When possible, your application should be using a managed identity to authenticate to Azure Event Hub. If not, consider having the storage credential (SAS, service principal credential) in Azure Key Vault or an equivalent service", - "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", + "text": "Data Encryption at rest by Microsoft managed keys", "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "description": "When creating permissions, provide fine-grained control over a client's access to Azure Event Hub. Permissions in Azure Event Hub can and should be scoped to the individual resource level e.g. consumer group, event hub entity, event hub namespaces, etc.", - "guid": "8357c559-675c-45ee-a5b8-6ad8844ce3b2", - "link": "https://learn.microsoft.com/azure/event-hubs/authorize-access-azure-active-directory#azure-built-in-roles-for-azure-event-hubs", - "service": "Event Hubs", + "description": "This is a default setting", + "guid": "5119b08e-8f58-4543-a7e9-cec166cd072a", + "service": "Azure Data Factory", "services": [ - "EventHubs", - "RBAC", + "AKV", "WAF" ], - "severity": "High", - "text": "Use least privilege data plane RBAC", - "training": "https://learn.microsoft.com/learn/modules/explore-basic-services-identity-types/", - "waf": "Security" - }, - { - "arm-service": "microsoft.eventhub/namespaces", - "checklist": "WAF checklist", - "description": "Azure Event Hub resource logs include operational logs, virtual network and Kafka logs. Runtime audit logs capture aggregated diagnostic information for all data plane access operations (such as send or receive events) in Event Hubs.", - "guid": "b38b875b-a1cf-4104-a900-3a4d3ce474db", - "link": "https://learn.microsoft.com/azure/event-hubs/monitor-event-hubs-reference", - "service": "Event Hubs", - "services": [ - "EventHubs", - "VNet", - "WAF", - "Monitor" - ], "severity": "Medium", - "text": "Enable logging for security investigation. Use Azure Monitor to captured metrics and logs such as resource logs, runtime audit logs and Kafka logs", - "training": "https://learn.microsoft.com/learn/paths/manage-identity-and-access/", + "text": "Data Encryption in transit by Microsoft managed keys", "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "description": "Azure Event Hub by default has a public IP address and is Internet-reachable. Private endpoints allow traffic between your virtual network and Azure Event Hub traverses over the Microsoft backbone network. In addition to that, you should disable public endpoints if those are not used. ", - "guid": "5abca2a4-eda1-4dae-8cc9-5d48c6b791dc", - "link": "https://learn.microsoft.com/azure/event-hubs/private-link-service", - "service": "Event Hubs", - "services": [ - "EventHubs", - "PrivateLink", - "VNet", + "description": "When you specify a customer-managed key, Data Factory uses�both�the factory system key and the CMK to encrypt customer data. Missing either would result in Deny of Access to data and factory.", + "guid": "f9b241a9-98a5-435e-9378-97e71ca7da8c", + "link": "https://learn.microsoft.com/azure/data-factory/enable-customer-managed-key", + "service": "Azure Data Factory", + "services": [ + "AKV", "WAF" ], "severity": "Medium", - "text": "Consider using private endpoints to access Azure Event Hub and disable public network access when applicable.", - "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", + "text": "Data Encryption in transit by BYOK (Customer managed keys)", "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", + "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "WAF checklist", - "description": "With IP firewall, you can restrict public endpoint further to only a set of IPv4 addresses or IPv4 address ranges in CIDR (Classless Inter-Domain Routing) notation. ", - "guid": "a0e6c465-89e5-458b-a37d-3974d1112dbd", - "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-ip-filtering", - "service": "Event Hubs", + "guid": "faa62a15-9495-46da-a7dc-3a23267b2258", + "link": "https://learn.microsoft.com/azure/data-factory/store-credentials-in-key-vault, https:/learn.microsoft.com/azure/data-factory/how-to-use-azure-key-vault-secrets-pipeline-activities", + "service": "Azure Data Factory", "services": [ - "EventHubs", + "AKV", "WAF" ], - "severity": "Medium", - "text": "Consider only allowing access to Azure Event Hub namespace from specific IP addresses or ranges", - "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", + "severity": "High", + "text": "Store passwords, secrets in Azure Key Vault", "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "31d41e36-11c8-417b-8afb-c410d4391898", - "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/paas-foundations-playbooks-AEH_v1.docx", - "service": "Event Hubs", + "guid": "6db55f57-9603-4334-adf9-cc23418db612", + "service": "Microsoft Purview", "services": [ + "RBAC", "WAF" ], "severity": "Medium", - "text": "Leverage FTA Resillency HandBook", - "waf": "Reliability" + "text": "Define roles and responsibilities to manage Microsoft Purview in control plane and data plane", + "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": " This will be turned on automatically for a new EH namespace created from the portal with Premium, Dedicated, or Standard SKUs in a zone-enabled region. Both the EH metadata and the event data itself are replicated across zones", - "guid": "f15bce21-9e4a-40eb-9787-9424d226786d", - "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-premium-overview#high-availability-with-availability-zones", - "service": "Event Hubs", + "description": "Use Azure RBACs for this", + "guid": "8126504b-b47a-4393-a080-427294798b15", + "link": "https://learn.microsoft.com/azure/role-based-access-control/best-practices", + "service": "Microsoft Purview", "services": [ - "EventHubs", - "WAF", - "ACR" + "Subscriptions", + "RBAC", + "WAF" ], - "severity": "High", - "text": "Leverage Availability Zones if regionally applicable", - "waf": "Reliability" + "severity": "Medium", + "text": "Define roles and tasks required to deploy and manage Microsoft Purview inside an Azure subscription (control plane)", + "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "20b56c56-ad58-4519-8f82-735c586bb281", - "link": "https://learn.microsoft.com/azure/event-hubs/compare-tiers", - "service": "Event Hubs", + "description": "Use Microsoft Purview roles for this.", + "guid": "78b219a4-6ceb-4544-9513-5922744293bb", + "link": "https://learn.microsoft.com/purview/classic-data-governance-permissions#roles, https://learn.microsoft.com/azure/role-based-access-control/best-practices", + "service": "Microsoft Purview", "services": [ + "RBAC", "WAF" ], "severity": "Medium", - "text": "Use the Premium or Dedicated SKUs for predicable performance", - "waf": "Reliability" + "text": "Define roles and task needed to perform data management and governance using Microsoft Purview. (Data plane for Data Map and Data Catalog.)", + "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "The built-in geo-disaster recovery feature, when enabled, ensures that the entire configuration of anamespace (Event Hubs, Consumer Groups and settings) is continuously replicated from a primary namespace to a secondary namespace, and it allows a once-only failover move from the primary to the secondary at any time. Active/Passive feature is designed to make it easier to recover from and abandon a failed Azure region without having to change application configurations", - "guid": "dc15a1c0-75ee-49f1-90ac-ccd579376bcd", - "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-geo-dr?tabs=portal", - "service": "Event Hubs", + "guid": "628637a5-5119-4b08-b8f5-854387e9cec1", + "service": "Microsoft Purview", "services": [ - "EventHubs", - "ASR", + "RBAC", + "Entra", "WAF" ], - "severity": "High", - "text": "Plan for Geo Disaster Recovery using Active Passive configuration", - "waf": "Reliability" + "severity": "Medium", + "text": "Assign roles to Microsoft Entra groups instead of assigning roles to individual users.", + "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "description": "Should be used for DR configurations where an outage or loss of event data in the downed region cannot be tolerated. For these cases, follow the replication guidance and do not use the built-in geo-disaster recovery capability (active/passive). With Active/Active, Maintain multiple Event Hubs in different regions and namespaces, and events will be replicated between the hubs", - "guid": "6e31b67d-67ba-4591-89c0-9e805d597c7e", - "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-federation-overview", - "service": "Event Hubs", + "guid": "66cd072a-f9b2-441a-a98a-535e737897e7", + "link": "https://learn.microsoft.com/azure/active-directory/governance/entitlement-management-overview", + "service": "Microsoft Purview", "services": [ - "EventHubs", - "ASR", + "Entra", "WAF" ], "severity": "Medium", - "text": "For Business Critical Applications, use Active Active configuration", - "waf": "Reliability" + "text": "Use Azure�Active Directory Entitlement Management�to map user access to Microsoft Entra groups using Access Packages.", + "waf": "Security" }, { - "arm-service": "microsoft.eventhub/namespaces", "checklist": "WAF checklist", - "guid": "9ced16ad-d186-4f0a-a241-a999a68af77c", - "link": "https://learn.microsoft.com/azure/architecture/serverless/event-hubs-functions/resilient-design", - "service": "Event Hubs", + "guid": "1ca7da8c-faa6-42a1-9949-56da97dc3a23", + "service": "Microsoft Purview", "services": [ - "EventHubs", + "RBAC", "WAF" ], - "severity": "Medium", - "text": "Design Resilient Event Hubs", - "waf": "Reliability" + "severity": "High", + "text": "Enforce multifactor authentication for Microsoft Purview users, especially, for users with privileged roles such as collection admins, data source admins or data curators.", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "bb235c70-5e17-496f-bedf-a8a4c8cdec4c", - "link": "https://learn.microsoft.com/entra/identity-platform/msal-acquire-cache-tokens", - "service": "Entra", + "guid": "267b2258-6f4a-4165-8bdd-dea8a487cdec", + "service": "Microsoft Purview", "services": [ - "WAF", - "Entra" + "Entra", + "WAF" ], - "severity": "Medium", - "text": "Use long-live revocable token, cache your token and acquire your silently using Microsoft Identity Library", - "waf": "Reliability" + "severity": "High", + "text": "Use Microsoft Entra ID to provide authentication and authorization to all users, security groups registered in Entra, service principal and managed identities inside collections in Microsoft Purview", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "503547c1-447e-4c66-828a-71f0f1ce16dd", - "link": "https://learn.microsoft.com/azure/active-directory-b2c/deploy-custom-policies-devops", - "service": "AAD B2C", + "guid": "4861bc3b-c14a-4eb7-b66e-8d9a3bec218e", + "service": "Microsoft Purview", "services": [ "WAF" ], - "severity": "Medium", - "text": "Make sure that your sign-in user flows are backed up and resilient. Make sure that the code that you use to sign-in your users are backed up and recoverable. Resilient interfaces with external processes", - "waf": "Reliability" + "severity": "High", + "text": "Define Least Privilege model and Lower exposure of privileged accounts", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "3e3553a4-c873-4964-ab66-2d6c15f51296", - "link": "https://learn.microsoft.com/entra/architecture/resilient-end-user-experience#use-a-content-delivery-network", - "service": "AAD B2C", + "guid": "6436b173-6db5-45f5-9960-3334bdf9cc23", + "link": "https://learn.microsoft.com/purview/catalog-private-link-end-to-end", + "service": "Microsoft Purview", "services": [ + "PrivateLink", "WAF" ], "severity": "Medium", - "text": "Custom brand assets should be hosted on a CDN", - "waf": "Performance" + "text": "Enable�end-to-end network isolation�using Private Link Service. (Microsoft Purview Data Map)", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "5398e6df-d237-4de1-93b1-6c21d79a9b64", - "link": "https://learn.microsoft.com/entra/identity/monitoring-health/reference-sla-performance", - "service": "AAD B2C", + "guid": "418db612-8126-4504-ab47-a393a0804272", + "link": "https://learn.microsoft.com/purview/catalog-private-link-end-to-end#firewalls-to-restrict-public-access", + "service": "Microsoft Purview", "services": [ "WAF" ], - "severity": "Low", - "text": "Have multiple identiy providers (i.e., login with your microsoft, google, facebook accounts)", - "waf": "Reliability" + "severity": "Medium", + "text": "Use�Microsoft Purview Firewall�to disable Public access. (Microsoft Purview Data Map)", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "604489a8-f42d-478e-98c0-7a73b22a4a57", - "link": "https://azure.microsoft.com/blog/setting-up-active-directory-for-a-disaster-recovery-environment-2/", - "service": "Windows AD", + "guid": "94798b15-78b2-419a-96ce-b54435135922", + "link": "https://learn.microsoft.com/purview/concept-best-practices-security#use-network-security-groups", + "service": "Microsoft Purview", "services": [ + "VNet", "VM", + "PrivateLink", "WAF" ], "severity": "Medium", - "text": "Follow VM rules for high availability on the VM level (premium disks, two or more in a region, in different availability zones)", - "waf": "Reliability" + "text": "Deploy�Network Security Group (NSG) rules�for subnets where Azure data sources private endpoints, Microsoft Purview private endpoints and self-hosted runtime VMs are deployed. (Microsoft Purview Data Map)", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "e7a8dd4a-30e3-47c3-b297-11b2362ceee0", - "link": "https://azure.microsoft.com/blog/setting-up-active-directory-for-a-disaster-recovery-environment-2/", - "service": "Windows AD", + "guid": "744293bb-6286-437a-9511-9b08e8f58543", + "link": "https://learn.microsoft.com/azure/firewall/overview", + "service": "Microsoft Purview", "services": [ + "NVA", + "PrivateLink", + "Firewall", "WAF" ], "severity": "Medium", - "text": "Don't replicate! Replication can create issues with directory synchronization", - "waf": "Reliability" + "text": "Implement Microsoft Purview with private endpoints managed by a Network Virtual Appliance, such as�Azure Firewall�for network inspection and network filtering. (Microsoft Purview Data Map)", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "79b598de-fc59-472c-b4cd-21b078036f5e", - "link": "https://azure.microsoft.com/blog/setting-up-active-directory-for-a-disaster-recovery-environment-2/", - "service": "Windows AD", + "description": "This private endpoint is also a prerequisite for the portal private endpoint. The Microsoft Purview�portal�private endpoint is required to enable connectivity to Microsoft Purview governance portal using a private network. Microsoft Purview can scan data sources in Azure or an on-premises environment by using ingestion private endpoints. Limitations on using private endpoints https://learn.microsoft.com/purview/catalog-private-link-troubleshoot", + "guid": "87e9cec1-66cd-4072-af9b-241a998a535e", + "link": "https://learn.microsoft.com/purview/concept-best-practices-network", + "service": "Microsoft Purview", "services": [ + "VNet", + "PrivateLink", "WAF" ], "severity": "Medium", - "text": "Have active-active for multi-regions", - "waf": "Reliability" + "text": "Deploy private endpoints for Microsoft Purview accounts to add another layer of security, so only client calls that are originated from within the virtual network are allowed to access the Microsoft Purview account", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "6b4bfd3d-5035-447c-8447-ec66128a71f0", - "link": "https://learn.microsoft.com/entra/identity/domain-services/tutorial-perform-disaster-recovery-drill", - "service": "Entra", + "description": "https://learn.microsoft.com/purview/catalog-private-link-end-to-end#firewalls-to-restrict-public-access. Limitation to be reviewed: https://learn.microsoft.com/purview/catalog-private-link-troubleshoot", + "guid": "b7bcdb3b-51eb-42ec-84ed-a6e59d8d9a2e", + "service": "Microsoft Purview", "services": [ - "WAF", - "Entra" + "WAF" ], "severity": "Medium", - "text": "Add Azure AD Domain service stamps to additional regions and locations", - "waf": "Reliability" + "text": "Block public access using Microsoft Purview firewall", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "f1ce16dd-3f1d-45e8-92e4-2e3611cc58b4", - "link": "https://learn.microsoft.com/entra/identity/domain-services/tutorial-perform-disaster-recovery-drill", - "service": "Entra", + "guid": "db217e67-6abf-4669-aa48-e5a96f2223ec", + "link": "https://learn.microsoft.com/azure/private-link/disable-private-endpoint-network-policy, https:/learn.microsoft.com/purview/concept-best-practices-security#use-network-security-groups", + "service": "Microsoft Purview", "services": [ + "VNet", "WAF" ], "severity": "Medium", - "text": "Use Replica Sets for DR", - "waf": "Reliability" + "text": "Use Network Security Groups to filter network traffic to and from Azure resources in an Azure virtual network", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "ac1d6380-f866-4bbd-a9b4-b1ee5d7908b8", - "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#availability-zones", - "service": "IoT", + "description": "https://learn.microsoft.com/purview/concept-best-practices-security#apply-security-best-practices-for-self-hosted-runtime-vms", + "guid": "e8cb1231-8ca5-4017-b158-e3fb3aa3c2de", + "service": "Microsoft Purview", "services": [ + "VNet", + "VM", "WAF" ], "severity": "High", - "text": "Leverage Availability Zones if regionally applicable (this is automatically enabled)", - "waf": "Reliability" + "text": "If you have sensitive data that cannot leave the boundary of your on-prem vnet it is highly recommended to use SHIR VMs inside your corporate vnet to extract your metadata ", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "35f651e8-0124-4ef7-8c57-658e38609e6e", - "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#microsoft-initiated-failover", - "service": "IoT", + "description": "Metadata is extracted and stored in Microsoft Purview Data Map, if you are not using managed storage account for your Purview account they are open to be accessed by all so implement proper RBACs and retrict the access of Data to only intended users. Applicable to Accounts deployed after December 15, 2023 (or deployed using API version 2023-05-01-preview onwards", + "guid": "7f3165c3-a87a-405b-9a20-9949bda47778", + "service": "Microsoft Purview", "services": [ + "Storage", + "RBAC", "WAF" ], "severity": "Medium", - "text": "Be aware of Microsoft-initiated failovers. These are exercised by Microsoft in rare situations to fail over all the IoT hubs from an affected region to the corresponding geo-paired region.", - "waf": "Reliability" + "text": "Use Azure RBACs to restrict the access of your storage account (not managed by MS) only to intended users.", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "4ed3e490-dc06-4a1e-b467-5d0239d85540", - "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#cross-region-dr", - "service": "IoT", + "guid": "f24d1167-85c2-4fa5-9c56-a948008be7d7", + "service": "Microsoft Purview", "services": [ + "AKV", "WAF" ], - "severity": "High", - "text": "Consider a Cross-Region DR strategy for critical workloads", - "waf": "Reliability" + "severity": "Medium", + "text": "Data in rest is encrypted by microsoft managed keys", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "a11ecab0-db47-46f7-9aa7-17764e7e45a1", - "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#microsoft-initiated-failover", - "service": "IoT", + "guid": "27f7b9e9-1be1-4f38-aff3-9812bd463cbb", + "service": "Microsoft Purview", "services": [ "WAF" ], - "severity": "High", - "text": "Learn how to trigger a manual failover.", - "waf": "Reliability" + "severity": "Medium", + "text": "Data in transit is encrypted by TLS 1.3", + "waf": "Security" }, { - "arm-service": "Microsoft.Devices/IotHubs", "checklist": "WAF checklist", - "guid": "f9db8dfb-1194-460b-aedd-34dd6a69db22", - "link": "https://learn.microsoft.com/azure/iot-hub/iot-hub-ha-dr#failback", - "service": "IoT", + "guid": "bc8ac199-ebb9-41a4-9d90-dae2cc881370", + "service": "Microsoft Purview", "services": [ + "AKV", + "Entra", "WAF" ], "severity": "High", - "text": "Learn how to fail back after a failover.", - "waf": "Reliability" + "text": "Always use Azure key vaults to store all credentials if not using managed identities or without password need methods", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "6d37a33b-531c-4a91-871a-b69d8044f04e", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "service": "Key Vault", + "guid": "6f7c0cba-fe61-4465-add4-57e927139b82", + "service": "Microsoft Purview", "services": [ - "AKV", - "WAF", - "Backup" + "WAF" ], - "severity": "High", - "text": "Familiarize yourself with the Key Vault's best practices such as isolation recommendations, access control, data protection, backup, and logging.", - "waf": "Reliability" + "severity": "Medium", + "text": "Prevent accidental deletion of Microsoft Purview accounts by applying resource Locks", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "7ba4d380-7b9e-4a8b-a0c3-2d8e49c11872", - "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance", - "service": "Key Vault", + "description": "https://learn.microsoft.com/purview/concept-best-practices-collections#design-recommendations", + "guid": "1102cac6-eae0-41e6-b842-e52f4722d928", + "link": "https://learn.microsoft.com/entra/identity/role-based-access-control/security-emergency-access", + "service": "Microsoft Purview", "services": [ - "AKV", - "WAF", - "ACR" + "Subscriptions", + "Entra", + "WAF" ], "severity": "Medium", - "text": "Key Vault is a managed service and Microsoft will handle the failover within and across region. Familiarize yourself with the Key Vault's availability and redundancy.", - "waf": "Reliability" + "text": "Plan for a break glass strategy for your Microsoft Entra tenant, Azure subscription and Microsoft Purview accounts to prevent tenant-wide account lockout.", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "17fb86a2-eb45-42a4-9c34-52b92a2a1842", - "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance#data-replication", - "service": "Key Vault", + "guid": "15f51296-5398-4e6d-bd23-7dd142b16c21", + "service": "Microsoft Purview", "services": [ - "AKV", + "Defender", "WAF" ], "severity": "Medium", - "text": "The contents of your key vault are replicated within the region and to a secondary region at least 150 miles away, but within the same geography to maintain high durability of your keys and secrets. Familiarize yourself with the Key Vault's data replication.", - "waf": "Reliability" + "text": "Integrate with Microsoft 365 and Microsoft Defender for Cloud", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "614682ca-6e0c-4f34-9f03-c6d3f2b99a32", - "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance#failover-across-regions", - "service": "Key Vault", + "description": "Separate admin accounts from normal user accounts.", + "guid": "d7999a64-6f43-489a-af42-c78e78c06a73", + "service": "Azure Databricks", "services": [ - "AKV", + "WAF" + ], + "severity": "High", + "text": "Define Least Privilege model and Lower exposure of privileged accounts", + "waf": "Security" + }, + { + "arm-service": "Microsoft.Databricks/workspaces", + "checklist": "WAF checklist", + "description": "Azure Databricks supports Microsoft Entra ID conditional access, which allows administrators to control where and when users are permitted to sign in to Azure Databricks. Conditional access policies can restrict sign-in to your corporate network or can require multi-factor authentication (MFA).", + "guid": "a22a4956-e7a8-4dc4-a20e-27c3e29711b1", + "link": "https://learn.microsoft.com/azure/databricks/security/auth/#single-sign-on", + "service": "Azure Databricks", + "services": [ + "Entra", "AzurePolicy", "WAF" ], - "severity": "Medium", - "text": "During failover, access policy or firewall configurations and settings can't be changed. The key vault will be in read-only mode during failover. Familiarize yourself with the Key Vault's failover guidance.", - "waf": "Reliability" + "severity": "High", + "text": "Configure single sign-on and unified login. Enable multi-factor authentication.", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "9ef2b0d2-3206-4c94-b47a-4f07e6a1c509", - "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#design-considerations", - "service": "Key Vault", + "description": "Customers can use the Token Management API or UI controls to enable or disable personal access tokens (PATs) for REST API authentication, limit the users who are allowed to use PATs, set the maximum lifetime for new tokens, and manage existing tokens. Highly-secure customers typically provision a maximum token lifetime for new tokens for a workspace. This feature requires the Premium pricing tier.", + "guid": "352beee0-79b5-488d-bfc5-972cd4cd21b0", + "link": "https://learn.microsoft.com/azure/databricks/admin/access-control/tokens", + "service": "Azure Databricks", "services": [ - "Storage", - "Backup", - "AKV", - "Subscriptions", "WAF" ], "severity": "Medium", - "text": "When you back up a key vault object, such as a secret, key, or certificate, the backup operation will download the object as an encrypted blob. This blob can't be decrypted outside of Azure. To get usable data from this blob, you must restore the blob into a key vault within the same Azure subscription and Azure geography. Familiarize yourself with the Key Vault's backup and restore guidance.", - "waf": "Reliability" + "text": "Use token management.", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "2df045b1-c0f6-47d3-9a9b-99cf6999684e", - "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", - "service": "Key Vault", + "description": "If you have Databricks administrators who are also normal users of the Databricks platform (for example, there�s a lead data engineer who administers the platform and also does data engineering work), Databricks recommends creating a separate account for administrative tasks. It�s important to note that as part of the Azure RBAC model, users that are given Contributor or above permissions to the Resource Group for a deployed Azure Databricks workspace automatically become administrators when they login to that workspace. Therefore, the same considerations outlined above should be applied to Azure portal users too.", + "guid": "77036e5e-6b4b-4fd3-b503-547c1447dc56", + "service": "Azure Databricks", "services": [ - "AKV", + "RBAC", "WAF" ], "severity": "High", - "text": "If you want protection against accidental or malicious deletion of your secrets, configure soft-delete and purge protection features on your key vault.", - "waf": "Reliability" + "text": "Separate admin accounts from normal user accounts", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "cbfa96b0-5249-4e6f-947c-d0e79509708c", - "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", - "service": "Key Vault", + "description": "SCIM (System for Cross-domain Identity Management) allows you to sync users and groups from Microsoft Entra ID to Azure Databricks. There are three major benefits of this approach: 1. When you remove a user, the user is automatically removed from Databricks. 2. Users can also be disabled temporarily via SCIM. Customers have used this capability for scenarios where customers believe that an account may be compromised and need to investigate 3. Groups are automatically synchronized Please refer to the documentation for detailed instructions on how to configure SCIM for Azure Databricks. This feature requires the Premium pricing tier", + "guid": "028a71ff-f1ce-415d-b3f0-d5e872d42e36", + "link": "https://learn.microsoft.com/azure/databricks/admin/users-groups/scim/", + "service": "Azure Databricks", "services": [ - "AKV", + "Entra", "WAF" ], - "severity": "Low", - "text": "Key Vault's soft-deleted resources are retained for a set period of 90 calendar days. Familiarize yourself with the Key Vault's soft-delete guidance.", - "waf": "Reliability" + "severity": "Medium", + "text": "SCIM synchronization of users and groups.", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "e8659d11-7e02-4db0-848c-c6541dbab68c", - "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#limitations", - "service": "Key Vault", + "description": "Using either cluster policies or the older cluster ACLs, admins can define what users or groups within the organization are able to create clusters. Cluster ACLs allow you to specify which users can attach a notebook to a given cluster. Note that if a user shares a notebook already attached to a standard mode cluster, the recipient will also be able to execute code on that cluster. This does not apply to clusters that enforce user isolation: SQL Warehouses, high concurrency with table ACLs clusters, and high concurrency with credential passthrough clusters. Customers who use Unity Catalog can also enable single-user clusters to enforce isolation clusters.", + "guid": "11cc57b4-a4b1-4410-b43a-58a9c2289b3d", + "service": "Azure Databricks", "services": [ - "AKV", + "EventHubs", + "Storage", + "SQL", "WAF", - "Backup" + "AzurePolicy" ], - "severity": "Low", - "text": "Understand Key Vault's backup limitations. Key Vault does not support the ability to backup more than 500 past versions of a key, secret, or certificate object. Attempting to backup a key, secret, or certificate object may result in an error. It is not possible to delete previous versions of a key, secret, or certificate.", - "waf": "Reliability" + "severity": "Medium", + "text": "Limit cluster creation rights.", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "45c25e29-d0ef-4f07-aa04-0f8c64cbcc04", - "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#limitations", - "service": "Key Vault", + "description": "It�s important to note that even if customers use Azure Key Vault to store their secrets, access controls still need to be defined within Azure Databricks. This is because the same service identity is used to retrieve the secret for all users of an Azure Databricks workspace.", + "guid": "8b662d6c-15f5-4129-9539-8e6ded237dd1", + "service": "Azure Databricks", "services": [ "AKV", - "WAF", - "Backup" + "Entra", + "WAF" ], - "severity": "Low", - "text": "Key Vault doesn't currently provide a way to back up an entire key vault in a single operation and keys, secrets and certitificates must be backup indvidually. Familiarize yourself with the Key Vault's backup and restore guidance.", - "waf": "Reliability" + "severity": "High", + "text": "Store passwords, secrets in Azure Key Vault", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "0f15640b-31e5-4de6-85a7-d2c652fa09d3", - "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview#purge-protection", - "service": "Key Vault", + "description": "Clusters with user isolation include enforcement such that each user runs as a different non-privileged user account on the cluster host. Languages are also limited to those that can be implemented in an isolated manner (SQL and Python), and Spark APIs must be on an allowlist of those we believe to be isolation-safe.", + "guid": "78c06a73-a22a-4495-9e7a-8dc4a20e27c3", + "service": "Azure Databricks", "services": [ - "AKV", - "EventHubs", + "SQL", "WAF" ], "severity": "Medium", - "text": "Purge protection is recommended when using keys for encryption to prevent data loss. Purge protection is an optional Key Vault behavior and is not enabled by default. Purge protection can only be enabled once soft-delete is enabled. It can be turned on via CLI, PowerShell or Portal.", - "waf": "Reliability" + "text": "Use clusters that support user isolation.", + "waf": "Security" }, { - "arm-service": "Microsoft.KeyVault/vaults", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "graph": "resources| where type =~ 'microsoft.keyvault/vaults' | extend compliant = (properties.enableRbacAuthorization == true) | distinct id, compliant", - "guid": "d0642c1c-312b-4116-94ab-439e1c836819", - "link": "https://learn.microsoft.com/azure/key-vault/general/rbac-guide?tabs=azure-cli", - "service": "Key Vault", + "description": "It is against security best practices to tie production workloads to individual user accounts, and so we recommend configuring Service Principals within Databricks. Service Principles separate administrator and user actions from the workload and prevent workloads from being impacted if a user leaves an organization. With Databricks, you can configure jobs to run as service principals and generate Personal Access Tokens for Service Principals.", + "guid": "e29711b1-352b-4eee-879b-588defc5972c", + "link": "https://learn.microsoft.com/azure/databricks/security/auth/access-control/", + "service": "Azure Databricks", "services": [ - "AKV", "RBAC", "WAF" ], "severity": "Medium", - "text": "RBAC is recommended to control access to your key vault. Familiarize yourself with the Key Vault's access control guidance.", + "text": "Use service principals to run production jobs. Use proper access control for workspace level (ACLs), account level (RBACs) and data level (Unity catalog) security controls", "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "3b7a56de-5020-4642-b3cb-c976e80b6d6d", - "link": "https://learn.microsoft.com/azure/logic-apps/single-tenant-overview-compare", - "service": "Logic Apps", + "description": "By default, DBFS is a filesystem that is accessible to all users of the given workspace and can be accessed via API. This is not necessarily a major data exfiltration concern as you can limit access to accessing data via the DBFS API or Databricks cli using IP access lists or private network access. However, as use of Azure Databricks grows and more users join a workspace, those users would have access to any data stored in DBFS, creating the potential for undesired information sharing. Databricks recommends that our customers do not store production data in DBFS.", + "guid": "d4cd21b0-7703-46e5-b6b4-bfd3d503547c", + "service": "Azure Databricks", "services": [ + "Storage", "WAF" ], "severity": "High", - "text": "Select the right Logic App hosting plan based on your business & SLO requirements", - "waf": "Reliability" + "text": "Avoid storing production data in DBFS.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "3d7008bd-6bc1-4b03-8aa8-ec2a3b55786a", - "link": "https://learn.microsoft.com/azure/logic-apps/set-up-zone-redundancy-availability-zones?tabs=standard#next-steps", - "service": "Logic Apps", + "description": "For the storage accounts that you manage, it is your responsibility to ensure that the storage accounts are protected according to your requirements. Examples might include: Encryption with your customer-managed key, Restrict access to trusted networks with a storage firewall, Anonymous public access is not allowed", + "guid": "1447dc56-028a-471f-bf1c-e15dd3f0d5e8", + "link": "https://learn.microsoft.com/azure/databricks/security/keys/customer-managed-keys", + "service": "Azure Databricks", "services": [ + "Storage", "WAF" ], - "severity": "High", - "text": "Protect logic apps from region failures with zone redundancy and availability zones", - "waf": "Reliability" + "severity": "Medium", + "text": "Encrypt storage and restrict access.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "1cda768f-a206-445d-8234-56f6a6e7286e", - "link": "https://learn.microsoft.com/azure/logic-apps/business-continuity-disaster-recovery-guidance?toc=%2Fazure%2Freliability%2Ftoc.json&bc=%2Fazure%2Freliability%2Fbreadcrumb%2Ftoc.json", - "service": "Logic Apps", + "description": "Add a customer-managed key for select data stored within the Azure Databricks control plane, such as notebooks, secrets, Databricks SQL queries, and Databricks SQL query history and for the root storage account used for DBFS. Azure Databricks requires access to this key for ongoing operations. You can revoke access to the key to prevent Azure Databricks from accessing encrypted data within the control plane (or in our backups). This is like a �nuclear option� where the workspace ceases to function, but it provides an emergency control for extreme situations. This feature requires the Premium pricing tier.", + "guid": "72d42e36-11cc-457b-9a4b-1410e43a58a9", + "link": "https://learn.microsoft.com/azure/databricks/security/keys/customer-managed-keys", + "service": "Azure Databricks", "services": [ + "AKV", + "Backup", + "Storage", + "SQL", "WAF" ], - "severity": "High", - "text": "Consider a Cross-Region DR strategy for critical workloads", - "waf": "Reliability" + "severity": "Medium", + "text": "Add a customer-managed key for managed services and workspace storage", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "82118ec5-ed6f-4c68-9471-eb0da98a1b34", - "link": "https://learn.microsoft.com/azure/app-service/environment/intro", - "service": "Logic Apps", + "description": "Configure IP access lists that restrict the IP addresses that can authenticate to Databricks at account console and workspace level by checking if the user or API client is coming from a known good IP address range such as a VPN or office network. Established user sessions do not work if the user moves to a bad IP address, such as when disconnecting from the VPN. ", + "guid": "277de183-b1ac-4252-a9a9-b64608489a8f", + "link": "https://learn.microsoft.com/azure/databricks/security/network/front-end/ip-access-list", + "service": "Azure Databricks", "services": [ - "AppSvc", + "VPN", "WAF" ], - "severity": "High", - "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", - "waf": "Reliability" + "severity": "Medium", + "text": "Enable IP access lists to restrict access to certain IP addresses.", + "waf": "Security" }, { - "arm-service": "Microsoft.Web/sites", + "arm-service": "Microsoft.Databricks/workspaces", "checklist": "WAF checklist", - "guid": "74275fa5-9e08-4c7e-b096-13b538fe1501", - "link": "https://learn.microsoft.com/training/modules/deploy-azure-functions/", - "service": "Logic Apps", + "description": "Azure Private Link provides a private network route from one Azure environment to another. Private Link can be configured both between Azure Databricks users and the control plane, and also between the control plane and the data plane. Between Databricks users and the control plane, Private Link provides strong controls that limit the source for inbound requests. If a company already routes traffic through an Azure environment, they can use Private Link so that the communication between users and the Azure Databricks control plane does not traverse public IP addresses. This feature requires the Premium pricing tier. Use Azure Private Link to connect from Azure Databricks to your Azure resources. Not only does Private Link ensure", + "guid": "82db8eb9-d1ba-473b-86a5-a57eba8dd4b3", + "link": "https://learn.microsoft.com/azure/databricks/security/network/classic/private-link", + "service": "Azure Databricks", "services": [ + "PrivateLink", "WAF" ], "severity": "Medium", - "text": "Leverage Azure DevOps or GitHub to streamline CI/CD and safeguard your Logic App code", - "waf": "Operations" + "text": "Configure and use Azure Private Link to access Azure resources.", + "waf": "Security" }, { "arm-service": "Microsoft.DBforMySQL/servers", @@ -28631,8 +28902,8 @@ "link": "https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet", "service": "App Gateway", "services": [ - "AppGW", "VNet", + "AppGW", "WAF" ], "severity": "Medium", @@ -28648,12 +28919,12 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "App Gateway", "services": [ - "AppGW", - "Entra", "NVA", - "VNet", + "WAF", "Subscriptions", - "WAF" + "AppGW", + "VNet", + "Entra" ], "severity": "Medium", "text": "Deploy Azure Application Gateway v2 or partner NVAs used for proxying inbound HTTP(S) connections within the landing-zone virtual network and with the apps that they're securing.", @@ -28698,9 +28969,9 @@ "link": "https://learn.microsoft.com/azure/reliability/migrate-app-gateway-v2", "service": "App Gateway", "services": [ + "ACR", "AppGW", - "WAF", - "ACR" + "WAF" ], "severity": "Medium", "text": "Deploy Application Gateway across Availability Zones", @@ -28715,9 +28986,9 @@ "service": "Front Door", "services": [ "AppGW", + "FrontDoor", "AzurePolicy", - "WAF", - "FrontDoor" + "WAF" ], "severity": "Medium", "text": "When using Front Door and Application Gateway to help protect HTTP/S apps, use WAF policies in Front Door. Lock down Application Gateway to receive traffic only from Front Door.", @@ -28747,8 +29018,8 @@ "service": "Entra", "services": [ "AVD", - "WAF", - "Entra" + "Entra", + "WAF" ], "severity": "Low", "text": "If users only need access to internal applications, has Microsoft Entra ID Application Proxy been considered as an alternative to Azure Virtual Desktop (AVD)?", @@ -28761,8 +29032,8 @@ "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy#how-application-proxy-works", "service": "Entra", "services": [ - "WAF", - "Entra" + "Entra", + "WAF" ], "severity": "Medium", "text": "To reduce the number of firewall ports open for incoming connections in your network, consider using Microsoft Entra ID Application Proxy to give remote users secure and authenticated access to internal applications.", @@ -28939,8 +29210,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/best-practices#send-logs-to-microsoft-sentinel", "service": "App Gateway", "services": [ - "AppGW", "Sentinel", + "AppGW", "WAF" ], "severity": "Medium", @@ -28982,11 +29253,11 @@ "link": "https://learn.microsoft.com/azure/virtual-wan/scenario-secured-hub-app-gateway", "service": "App Gateway", "services": [ + "ExpressRoute", + "WAF", "AppGW", "VPN", - "ExpressRoute", - "VNet", - "WAF" + "VNet" ], "severity": "Medium", "text": "Filter inbound traffic in the backends so that they only accept connections from the Application Gateway subnet, for example with NSGs.", @@ -29059,3446 +29330,4037 @@ "waf": "Security" }, { - "arm-service": "microsoft.network/applicationGateways", + "arm-service": "microsoft.network/applicationGateways", + "checklist": "WAF checklist", + "guid": "c8741f03-45a4-4183-a6b8-139e0773b8b5", + "link": "https://learn.microsoft.com/azure/application-gateway/custom-error", + "service": "App Gateway", + "services": [ + "WAF" + ], + "severity": "Low", + "text": "Create custom error pages to display a personalized user experience", + "waf": "Operations" + }, + { + "arm-service": "microsoft.network/applicationGateways", + "checklist": "WAF checklist", + "guid": "f850d46f-f5d7-4b17-b48c-a780741402e1", + "link": "https://learn.microsoft.com/azure/application-gateway/rewrite-http-headers-url", + "service": "App Gateway", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Edit HTTP requests and response headers for easier routing and information exchange between the client and server", + "waf": "Security" + }, + { + "arm-service": "microsoft.network/applicationGateways", + "checklist": "WAF checklist", + "guid": "eadc3164-4a0f-461c-85f1-1a372c04dfd1", + "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", + "service": "App Gateway", + "services": [ + "FrontDoor", + "WAF" + ], + "severity": "Medium", + "text": "Configure Front Door to optimize global web traffic routing and top-tier end-user performance, and reliability through quick global failover", + "waf": "Performance" + }, + { + "arm-service": "microsoft.network/applicationGateways", + "checklist": "WAF checklist", + "guid": "29dcc19f-a8fa-4c35-8281-290577538793", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", + "service": "App Gateway", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Use transport layer load balancing", + "waf": "Performance" + }, + { + "arm-service": "microsoft.network/applicationGateways", + "checklist": "WAF checklist", + "guid": "276898c1-af5e-4819-9e8e-049c7801ab9d", + "link": "https://learn.microsoft.com/azure/application-gateway/multiple-site-overview", + "service": "App Gateway", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Configure routing based on host or domain name for multiple web applications on a single gateway", + "waf": "Security" + }, + { + "arm-service": "microsoft.network/applicationGateways", + "checklist": "WAF checklist", + "guid": "5fe365b6-58e8-47ed-a8cf-5163850380a2", + "link": "https://learn.microsoft.com/azure/application-gateway/create-ssl-portal", + "service": "App Gateway", + "services": [ + "Entra", + "WAF" + ], + "severity": "Medium", + "text": "Centralize SSL certificate management to reduce encryption and decryption overhead from a backend server farm", + "waf": "Security" + }, + { + "arm-service": "microsoft.network/applicationGateways", + "checklist": "WAF checklist", + "guid": "fa64b4dd-35c2-4047-ac5c-45dfbf8b0db9", + "link": "https://learn.microsoft.com/azure/application-gateway/application-gateway-websocket", + "service": "App Gateway", + "services": [ + "AppGW", + "WAF" + ], + "severity": "Low", + "text": "Use Application Gateway for native support for WebSocket and HTTP/2 protocols", + "waf": "Security" + }, + { + "arm-service": "Microsoft.Devices/provisioningServices", + "checklist": "WAF checklist", + "guid": "cb26b2ba-a9db-45d1-8260-d9c6ec1447d9", + "link": "https://learn.microsoft.com/en-us/azure/logic-apps/single-tenant-overview-compare", + "service": "IoT Hub DPS", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Select the right Logic App hosting plan based on your business & SLO requirements", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.Devices/provisioningServices", + "checklist": "WAF checklist", + "guid": "f6dd7977-1123-4f39-b488-f91415a8430a", + "link": "https://learn.microsoft.com/en-us/azure/logic-apps/set-up-zone-redundancy-availability-zones?tabs=standard#next-steps", + "service": "IoT Hub DPS", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Protect logic apps from region failures with zone redundancy and availability zones", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.Devices/provisioningServices", + "checklist": "WAF checklist", + "guid": "8aed4fbf-0830-4883-899d-222a154af478", + "link": "https://learn.microsoft.com/en-us/azure/logic-apps/business-continuity-disaster-recovery-guidance?toc=%2Fazure%2Freliability%2Ftoc.json&bc=%2Fazure%2Freliability%2Fbreadcrumb%2Ftoc.json", + "service": "IoT Hub DPS", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Consider a Cross-Region DR strategy for critical workloads", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.Devices/provisioningServices", + "checklist": "WAF checklist", + "guid": "da0f033e-d180-4f36-9aa4-c468dba14203", + "link": "https://learn.microsoft.com/en-us/azure/app-service/environment/intro", + "service": "IoT Hub DPS", + "services": [ + "AppSvc", + "WAF" + ], + "severity": "High", + "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.Devices/provisioningServices", + "checklist": "WAF checklist", + "guid": "62711604-c9d1-4b0a-bdb7-5fda54a4f6c1", + "link": "https://learn.microsoft.com/en-us/training/modules/deploy-azure-functions/", + "service": "IoT Hub DPS", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Leverage Azure DevOps or GitHub to streamline CI/CD and safeguard your Logic App code", + "waf": "Operations" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "6d37a33b-531c-4a91-871a-b69d8044f04e", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", + "services": [ + "AKV", + "Backup", + "WAF" + ], + "severity": "High", + "text": "Familiarize yourself with the Key Vault's best practices such as isolation recommendations, access control, data protection, backup, and logging.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "7ba4d380-7b9e-4a8b-a0c3-2d8e49c11872", + "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance", + "service": "Key Vault", + "services": [ + "ACR", + "AKV", + "WAF" + ], + "severity": "Medium", + "text": "Key Vault is a managed service and Microsoft will handle the failover within and across region. Familiarize yourself with the Key Vault's availability and redundancy.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "17fb86a2-eb45-42a4-9c34-52b92a2a1842", + "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance#data-replication", + "service": "Key Vault", + "services": [ + "AKV", + "WAF" + ], + "severity": "Medium", + "text": "The contents of your key vault are replicated within the region and to a secondary region at least 150 miles away, but within the same geography to maintain high durability of your keys and secrets. Familiarize yourself with the Key Vault's data replication.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "614682ca-6e0c-4f34-9f03-c6d3f2b99a32", + "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance#failover-across-regions", + "service": "Key Vault", + "services": [ + "AKV", + "AzurePolicy", + "WAF" + ], + "severity": "Medium", + "text": "During failover, access policy or firewall configurations and settings can't be changed. The key vault will be in read-only mode during failover. Familiarize yourself with the Key Vault's failover guidance.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "9ef2b0d2-3206-4c94-b47a-4f07e6a1c509", + "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#design-considerations", + "service": "Key Vault", + "services": [ + "WAF", + "AKV", + "Backup", + "Storage", + "Subscriptions" + ], + "severity": "Medium", + "text": "When you back up a key vault object, such as a secret, key, or certificate, the backup operation will download the object as an encrypted blob. This blob can't be decrypted outside of Azure. To get usable data from this blob, you must restore the blob into a key vault within the same Azure subscription and Azure geography. Familiarize yourself with the Key Vault's backup and restore guidance.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "2df045b1-c0f6-47d3-9a9b-99cf6999684e", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", + "service": "Key Vault", + "services": [ + "AKV", + "WAF" + ], + "severity": "High", + "text": "If you want protection against accidental or malicious deletion of your secrets, configure soft-delete and purge protection features on your key vault.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "cbfa96b0-5249-4e6f-947c-d0e79509708c", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", + "service": "Key Vault", + "services": [ + "AKV", + "WAF" + ], + "severity": "Low", + "text": "Key Vault's soft-deleted resources are retained for a set period of 90 calendar days. Familiarize yourself with the Key Vault's soft-delete guidance.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "e8659d11-7e02-4db0-848c-c6541dbab68c", + "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#limitations", + "service": "Key Vault", + "services": [ + "AKV", + "Backup", + "WAF" + ], + "severity": "Low", + "text": "Understand Key Vault's backup limitations. Key Vault does not support the ability to backup more than 500 past versions of a key, secret, or certificate object. Attempting to backup a key, secret, or certificate object may result in an error. It is not possible to delete previous versions of a key, secret, or certificate.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "45c25e29-d0ef-4f07-aa04-0f8c64cbcc04", + "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#limitations", + "service": "Key Vault", + "services": [ + "AKV", + "Backup", + "WAF" + ], + "severity": "Low", + "text": "Key Vault doesn't currently provide a way to back up an entire key vault in a single operation and keys, secrets and certitificates must be backup indvidually. Familiarize yourself with the Key Vault's backup and restore guidance.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "guid": "0f15640b-31e5-4de6-85a7-d2c652fa09d3", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview#purge-protection", + "service": "Key Vault", + "services": [ + "AKV", + "EventHubs", + "WAF" + ], + "severity": "Medium", + "text": "Purge protection is recommended when using keys for encryption to prevent data loss. Purge protection is an optional Key Vault behavior and is not enabled by default. Purge protection can only be enabled once soft-delete is enabled. It can be turned on via CLI, PowerShell or Portal.", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.KeyVault/vaults", + "checklist": "WAF checklist", + "graph": "resources| where type =~ 'microsoft.keyvault/vaults' | extend compliant = (properties.enableRbacAuthorization == true) | distinct id, compliant", + "guid": "d0642c1c-312b-4116-94ab-439e1c836819", + "link": "https://learn.microsoft.com/azure/key-vault/general/rbac-guide?tabs=azure-cli", + "service": "Key Vault", + "services": [ + "AKV", + "RBAC", + "WAF" + ], + "severity": "Medium", + "text": "RBAC is recommended to control access to your key vault. Familiarize yourself with the Key Vault's access control guidance.", + "waf": "Security" + }, + { + "arm-service": "Microsoft.Network/virtualNetworks", + "checklist": "WAF checklist", + "guid": "7bc1c396-2461-4698-b57f-30ca69525252", + "link": "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/considerations/regions", + "service": "VNet", + "services": [ + "ASR", + "WAF" + ], + "severity": "Medium", + "text": "Deploy your Azure landing zone connectivity resources in multiple regions, so that you can quickly support multi-region application landing zones and disaster recovery scenarios.", + "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", + "waf": "Reliability" + }, + { + "checklist": "WAF checklist", + "guid": "70c15989-c726-42c7-b0d3-24b7375b9201", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/considerations-recommendations", + "service": "Entra", + "services": [ + "Entra", + "WAF" + ], + "severity": "Medium", + "text": "Use one Entra tenant for managing your Azure resources, unless you have a clear regulatory or business requirement for multi-tenants.", + "training": "https://learn.microsoft.com/training/modules/deploy-resources-scopes-bicep/2-understand-deployment-scopes", + "waf": "Operations" + }, + { + "checklist": "WAF checklist", + "guid": "6309957b-821a-43d1-b9d9-7fcf1802b747", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/automation", + "service": "Entra", + "services": [ + "Entra", + "WAF" + ], + "severity": "Low", + "text": "Use Multi-Tenant Automation approach to managing your Microsoft Entra ID Tenants.", + "training": "https://learn.microsoft.com/entra/architecture/multi-tenant-user-management-introduction/", + "waf": "Operations" + }, + { + "checklist": "WAF checklist", + "guid": "78e11934-499a-45ed-8ef7-aae5578f0ecf", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/multi-tenant/lighthouse", + "service": "Entra", + "services": [ + "WAF" + ], + "severity": "High", + "text": "Use Azure Lighthouse for Multi-Tenant Management with the same IDs.", + "training": "https://learn.microsoft.com/azure/lighthouse/concepts/cross-tenant-management-experience", + "waf": "Operations" + }, + { + "checklist": "WAF checklist", + "guid": "5d82e6df-6f61-42f2-82e2-3132d293be3d", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", + "service": "Entra", + "services": [ + "WAF" + ], + "severity": "High", + "text": "If you give a partner access to administer your tenant, use Azure Lighthouse.", + "training": "https://learn.microsoft.com/azure/lighthouse/how-to/onboard-customer", + "waf": "Cost" + }, + { + "checklist": "WAF checklist", + "guid": "348ef254-c27d-442e-abba-c7571559ab91", + "link": "https://learn.microsoft.com/azure/role-based-access-control/overview", + "service": "Entra", + "services": [ + "ACR", + "Subscriptions", + "RBAC", + "WAF" + ], + "severity": "High", + "text": "Enforce a RBAC model that aligns to your cloud operating model. Scope and Assign across Management Groups and Subscriptions.", + "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", + "waf": "Security" + }, + { + "checklist": "WAF checklist", + "guid": "12e7f983-f630-4472-8dd6-9c5b5c2622f5", + "link": "https://learn.microsoft.com/azure/active-directory/roles/security-planning#identify-microsoft-accounts-in-administrative-roles-that-need-to-be-switched-to-work-or-school-accounts", + "service": "Entra", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Only use the authentication type Work or school account for all account types. Avoid using the Microsoft account", + "training": "https://learn.microsoft.com/learn/modules/explore-basic-services-identity-types/", + "waf": "Security" + }, + { + "checklist": "WAF checklist", + "guid": "4b69bad3-3aad-45e8-a68e-1d76667313b4", + "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-groups-create-azure-portal", + "service": "Entra", + "services": [ + "Entra", + "WAF" + ], + "severity": "Medium", + "text": "Only use groups to assign permissions. Add on-premises groups to the Entra ID only group if a group management system is already in place.", + "training": "https://learn.microsoft.com/learn/paths/manage-identity-and-access/", + "waf": "Security" + }, + { "checklist": "WAF checklist", - "guid": "c8741f03-45a4-4183-a6b8-139e0773b8b5", - "link": "https://learn.microsoft.com/azure/application-gateway/custom-error", - "service": "App Gateway", + "guid": "53e8908a-e28c-484c-93b6-b7808b9fe5c4", + "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/overview", + "service": "Entra", "services": [ + "Entra", + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "Create custom error pages to display a personalized user experience", - "waf": "Operations" + "severity": "High", + "text": "Enforce Microsoft Entra ID Conditional Access policies for any user with rights to Azure environments.", + "training": "https://learn.microsoft.com/learn/modules/plan-implement-administer-conditional-access/", + "waf": "Security" }, { - "arm-service": "microsoft.network/applicationGateways", "checklist": "WAF checklist", - "guid": "f850d46f-f5d7-4b17-b48c-a780741402e1", - "link": "https://learn.microsoft.com/azure/application-gateway/rewrite-http-headers-url", - "service": "App Gateway", + "guid": "1049d403-a923-4c34-94d0-0018ac6a9e01", + "link": "https://learn.microsoft.com/azure/active-directory/authentication/concept-mfa-howitworks", + "service": "Entra", "services": [ "WAF" ], - "severity": "Medium", - "text": "Edit HTTP requests and response headers for easier routing and information exchange between the client and server", + "severity": "High", + "text": "Enforce multi-factor authentication for any user with rights to the Azure environments.", + "training": "https://learn.microsoft.com/entra/identity/authentication/concept-mandatory-multifactor-authentication", "waf": "Security" }, { - "arm-service": "microsoft.network/applicationGateways", "checklist": "WAF checklist", - "guid": "eadc3164-4a0f-461c-85f1-1a372c04dfd1", - "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", - "service": "App Gateway", + "guid": "14658d35-58fd-4772-99b8-21112df27ee4", + "link": "https://learn.microsoft.com/azure/active-directory/privileged-identity-management/pim-configure", + "service": "Entra", "services": [ - "WAF", - "FrontDoor" + "Entra", + "WAF" ], "severity": "Medium", - "text": "Configure Front Door to optimize global web traffic routing and top-tier end-user performance, and reliability through quick global failover", - "waf": "Performance" + "text": "Enforce Microsoft Entra ID Privileged Identity Management (PIM) to establish zero standing access and least privilege.", + "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", + "waf": "Security" }, { - "arm-service": "microsoft.network/applicationGateways", "checklist": "WAF checklist", - "guid": "29dcc19f-a8fa-4c35-8281-290577538793", - "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", - "service": "App Gateway", + "guid": "8b9fe5c4-1049-4d40-9a92-3c3474d00018", + "link": "https://learn.microsoft.com/entra/identity/domain-services/overview", + "service": "Entra", "services": [ + "Entra", "WAF" ], "severity": "Medium", - "text": "Use transport layer load balancing", - "waf": "Performance" + "text": "If planning to switch from Active Directory Domain Services to Entra domain services, evaluate the compatibility of all workloads.", + "training": "https://learn.microsoft.com/learn/modules/implement-hybrid-identity-windows-server/", + "waf": "Security" }, { - "arm-service": "microsoft.network/applicationGateways", "checklist": "WAF checklist", - "guid": "276898c1-af5e-4819-9e8e-049c7801ab9d", - "link": "https://learn.microsoft.com/azure/application-gateway/multiple-site-overview", - "service": "App Gateway", + "graph": "resources | where type == 'microsoft.aad/domainservices' | extend replicaSets = properties.replicaSets | where array_length(replicaSets) < 2 | project name=name, id=id, tags=tags, param1=strcat('replicaSetLocation:', replicaSets[0].location)", + "guid": "0dd4e625-9c4b-4a56-b54a-4357bac12761", + "link": "https://learn.microsoft.com/entra/identity/domain-services/overview", + "service": "Entra", "services": [ + "Entra", "WAF" ], "severity": "Medium", - "text": "Configure routing based on host or domain name for multiple web applications on a single gateway", - "waf": "Security" + "text": "When using Microsoft Entra Domain Services use replica sets. Replica sets will improve the resiliency of your managed domain and allow you to deploy to additional regions. ", + "training": "https://learn.microsoft.com/training/modules/understand-azure-active-directory/6-examine-azure-domain-services", + "waf": "Reliability" }, { - "arm-service": "microsoft.network/applicationGateways", "checklist": "WAF checklist", - "guid": "5fe365b6-58e8-47ed-a8cf-5163850380a2", - "link": "https://learn.microsoft.com/azure/application-gateway/create-ssl-portal", - "service": "App Gateway", + "guid": "1cf0b8da-70bd-44d0-94af-8d99cfc89ae1", + "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/concept-activity-logs-azure-monitor", + "service": "Entra", "services": [ - "WAF", - "Entra" + "Monitor", + "Entra", + "WAF" ], "severity": "Medium", - "text": "Centralize SSL certificate management to reduce encryption and decryption overhead from a backend server farm", + "text": "Integrate Microsoft Entra ID logs with the platform-central Azure Monitor. Azure Monitor allows for a single source of truth around log and monitoring data in Azure, giving organizations a cloud native options to meet requirements around log collection and retention.", + "training": "https://learn.microsoft.com/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs", "waf": "Security" }, { - "arm-service": "microsoft.network/applicationGateways", + "ammp": true, "checklist": "WAF checklist", - "guid": "fa64b4dd-35c2-4047-ac5c-45dfbf8b0db9", - "link": "https://learn.microsoft.com/azure/application-gateway/application-gateway-websocket", - "service": "App Gateway", + "guid": "984a859c-773e-47d2-9162-3a765a917e1f", + "link": "https://learn.microsoft.com/azure/active-directory/roles/security-emergency-access", + "service": "Entra", "services": [ - "AppGW", + "Entra", "WAF" ], - "severity": "Low", - "text": "Use Application Gateway for native support for WebSocket and HTTP/2 protocols", + "severity": "High", + "text": "Implement an emergency access or break-glass accounts to prevent tenant-wide account lockout. MFA will be turned on by default for all users in Oct 2024. We recommend updating these accounts to use passkey (FIDO2) or configure certificate-based authentication for MFA. ", + "training": "https://learn.microsoft.com/entra/identity/role-based-access-control/security-emergency-access#exclude-at-least-one-account-from-conditional-access-policies", "waf": "Security" }, { - "arm-service": "Microsoft.DBforPostgreSQL/servers", "checklist": "WAF checklist", - "guid": "65285269-441c-44bf-9d3e-0844276d4bdc", - "link": "https://learn.microsoft.com/azure/postgresql/flexible-server/overview", - "service": "PostgreSQL", + "guid": "35037e68-9349-4c15-b371-228514f4cdff", + "link": "https://learn.microsoft.com/azure/active-directory/roles/best-practices", + "service": "Entra", "services": [ + "RBAC", + "Entra", "WAF" ], "severity": "Medium", - "text": "Leverage Flexible Server", - "waf": "Reliability" + "text": "Do not use on-premises synced accounts for Microsoft Entra ID role assignments, unless you have a scenario that specifically requires it.", + "training": "https://learn.microsoft.com/learn/modules/design-identity-security-strategy/", + "waf": "Security" }, { - "arm-service": "Microsoft.DBforPostgreSQL/servers", "checklist": "WAF checklist", - "guid": "016ccf31-ae5a-41eb-9888-9535e227896d", - "link": "https://learn.microsoft.com/azure/postgresql/flexible-server/overview#architecture-and-high-availability", - "service": "PostgreSQL", + "guid": "d5d1e4e6-1465-48d3-958f-d77249b82111", + "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy", + "service": "Entra", "services": [ + "Entra", "WAF" ], - "severity": "High", - "text": "Leverage Availability Zones where regionally applicable", - "waf": "Reliability" + "severity": "Medium", + "text": "When using Microsoft Entra ID Application Proxy to give remote users access to applications, manage it as a Platform resource as you can only have one instance per tenant.", + "training": "https://learn.microsoft.com/learn/paths/implement-applications-external-access-azure-ad/", + "waf": "Security" }, { - "arm-service": "Microsoft.DBforPostgreSQL/servers", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "31b67c67-be59-4519-8083-845d587cb391", - "link": "https://learn.microsoft.com/azure/postgresql/single-server/concepts-business-continuity#cross-region-read-replicas", - "service": "PostgreSQL", + "guid": "e8bbac75-7155-49ab-a153-e8908ae28c84", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/enterprise-scale/network-topology-and-connectivity", + "service": "VNet", "services": [ + "VNet", "WAF" ], "severity": "Medium", - "text": "Leverage cross-region read replicas for BCDR", - "waf": "Reliability" + "text": "Use a hub-and-spoke network topology for network scenarios that require maximum flexibility.", + "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "1fc2fc14-eea6-4e69-b8d9-a3edc218e687", - "link": "https://polite-sea-0995b240f.2.azurestaticapps.net/technical-delivery-playbook/azure-services/analytics/purview/", - "service": "Purview", + "guid": "7dd61623-a364-4a90-9eca-e48ebd54cd7d", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/traditional-azure-networking-topology", + "service": "VNet", "services": [ - "WAF" + "VNet", + "ExpressRoute", + "NVA", + "Firewall", + "VPN", + "WAF", + "DNS", + "Entra" ], - "severity": "Medium", - "text": "Leverage FTA Resillency Handbook", - "waf": "Reliability" + "severity": "High", + "text": "Deploy shared networking services, including ExpressRoute gateways, VPN gateways, and Azure Firewall or partner NVAs in the central-hub virtual network. If necessary, also deploy DNS services.", + "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", + "waf": "Cost" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "ab067acb-49e5-4b96-8332-4ecf8cc13318", - "link": "https://learn.microsoft.com/purview/disaster-recovery", - "service": "Purview", + "guid": "143b16c3-1d7a-4a9b-9470-4489a8042d88", + "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", + "service": "VNet", "services": [ + "DDoS", "WAF" ], "severity": "High", - "text": "Plan for Data Center level outage", - "waf": "Reliability" + "text": "Use a DDoS Network or IP protection plan for all public IP addresses in application landing zones.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "description": "1. Create the new account 2. Migrate configuration items 3. Run scans 4. Migrate custom typedefs and custom assets 5. Migrate relationships 6. Migrate glossary terms 7. Assign classifications to assets 8. Assign contacts to assets", - "guid": "da611702-69f4-4fb4-aa3d-3ef7f3176c4b", - "link": "https://learn.microsoft.com/purview/disaster-recovery", - "service": "Purview", + "guid": "e2e8abac-3571-4559-ab91-53e89f89dc7b", + "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/nva-ha", + "service": "NVA", "services": [ + "NVA", "WAF" ], "severity": "Medium", - "text": "Practice Failover for BCDR", + "text": "When deploying partner networking technologies or NVAs, follow the partner vendor's guidance.", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "97b15b8a-219a-44ab-bb57-879024d22678", - "link": "https://learn.microsoft.com/purview/disaster-recovery", - "service": "Purview", + "guid": "ce463dbb-bc8a-4c2a-aebc-92a43da1dae2", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-coexist-resource-manager#to-enable-transit-routing-between-expressroute-and-azure-vpn", + "service": "ExpressRoute", "services": [ - "WAF", - "Backup" + "ExpressRoute", + "ARS", + "VPN", + "WAF" ], - "severity": "High", - "text": "Plan a backup strategy and take regular backups", - "waf": "Reliability" + "severity": "Low", + "text": "If you need transit between ExpressRoute and VPN gateways in hub and spoke scenarios, use Azure Route Server.", + "training": "https://learn.microsoft.com/training/modules/intro-to-azure-route-server/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualHubs", "checklist": "WAF checklist", - "guid": "6d20b56c-56a9-4581-89bf-8d8e5c586b7d", - "link": "https://learn.microsoft.com/purview/manage-kafka-dotnet", - "service": "Purview", + "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant", + "guid": "91b9d7d5-91e1-4dcb-8f1f-fa7e465646cc", + "link": "https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1", + "service": "ARS", "services": [ - "EventHubs", + "VNet", + "ARS", "WAF" ], "severity": "Low", - "text": "Use Microsoft Purview's Event Hubs to subscribe and create entities to another account", - "waf": "Reliability" + "text": "If using Route Server, use a /27 prefix for the Route Server subnet.", + "training": "https://learn.microsoft.com/training/modules/intro-to-azure-route-server/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "8cdc15ac-c075-4ee9-a130-a8889579e76b", - "link": "https://learn.microsoft.com/purview/deployment-best-practices", - "service": "Purview", + "guid": "cc881471-607c-41cc-a0e6-14658dd558f9", + "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-faq#can-i-create-a-peering-connection-to-a-vnet-in-a-different-region", + "service": "VNet", "services": [ + "ACR", + "VNet", "WAF" ], "severity": "Medium", - "text": "Follow Purview accounts architectures and deployment best practices", - "waf": "Reliability" + "text": "For network architectures with multiple hub-and-spoke topologies across Azure regions, use global virtual network peerings between the hub VNets to connect the regions to each other.", + "training": "https://learn.microsoft.com/learn/paths/azure-administrator-manage-virtual-networks/", + "waf": "Performance" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "896e710a-7da7-4be9-a56d-14d3c49d997c", - "link": "https://learn.microsoft.com/purview/concept-best-practices-collections", - "service": "Purview", + "guid": "4722d929-c1b1-4cd6-81f5-4b29bade39ad", + "link": "https://learn.microsoft.com/azure/azure-monitor/insights/network-insights-overview", + "service": "VNet", "services": [ + "Monitor", "WAF" ], "severity": "Medium", - "text": "Follow Collection Architectures and best practices", - "waf": "Reliability" + "text": "Use Azure Monitor for Networks to monitor the end-to-end state of the networks on Azure.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/", + "waf": "Operations" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "b3d1325a-a225-4c6f-9e06-85edddea8a4b", - "link": "https://learn.microsoft.com/purview/concept-best-practices-asset-lifecycle", - "service": "Purview", + "graph": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant", + "guid": "0e7c28ec-9366-4572-83b0-f4664b1d944a", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits", + "service": "VNet", "services": [ + "VNet", + "ExpressRoute", "WAF" ], "severity": "Medium", - "text": "Follow Assest lifecycle best practices", + "text": "If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000).", + "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "7cdeb3c6-1fc2-4fc1-9eea-6e69d8d9a3ed", - "link": "https://learn.microsoft.com/purview/concept-best-practices-automation", - "service": "Purview", + "graph": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant", + "guid": "3d457936-e9b7-41eb-bdff-314b26450b12", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits", + "service": "VNet", "services": [ + "Storage", "WAF" ], "severity": "Medium", - "text": "Follow automation best practices", + "text": "Limit the number of routes per route table to 400.", + "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "c218e687-ab06-47ac-a49e-5b9603324ecf", - "link": "https://learn.microsoft.com/purview/disaster-recovery", - "service": "Purview", + "graph": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)", + "guid": "c76cb5a2-abe2-11ed-afa1-0242ac120002", + "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering", + "service": "VNet", "services": [ - "WAF", - "Backup" + "VNet", + "WAF" ], - "severity": "Medium", - "text": "Follow Backup and Migration Best practices", + "severity": "High", + "text": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings.", + "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "8cc13318-da61-4170-869f-4fb4aa3d3ef7", - "link": "https://learn.microsoft.com/purview/concept-best-practices-glossary", - "service": "Purview", + "graph": "resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName)", + "guid": "9dcd6250-9c4a-4382-aa9b-5b84c64fc1fe", + "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant", + "service": "Load Balancers", "services": [ + "LoadBalancer", "WAF" ], - "severity": "Medium", - "text": "Follow Purview Glossary Best Practices", + "severity": "High", + "text": "Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA.", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "f3176c4b-97b1-45b8-a219-a4abeb578790", - "link": "https://learn.microsoft.com/purview/concept-workflow", - "service": "Purview", + "graph": "resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses))", + "guid": "48682fb1-1e86-4458-a686-518ebd47393d", + "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant", + "service": "Load Balancers", "services": [ + "LoadBalancer", "WAF" ], - "severity": "Low", - "text": "Leverage Workflows ", + "severity": "High", + "text": "Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability.", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "24d22678-6d20-4b56-a56a-958119bf8d8e", - "link": "https://learn.microsoft.com/purview/concept-best-practices-security", - "service": "Purview", + "guid": "de0d5973-cd4c-4d21-a088-137f5e6c4cfd", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-macsec", + "service": "ExpressRoute", "services": [ + "ExpressRoute", "WAF" ], "severity": "Medium", - "text": "Follow Purview Security Best Practices", - "waf": "Reliability" + "text": "When you're using ExpressRoute Direct, configure MACsec in order to encrypt traffic at the layer-two level between the organization's routers and MSEE. The diagram shows this encryption in flow.", + "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "5c586b7d-8cdc-415a-ac07-5ee9b130a888", - "link": "https://learn.microsoft.com/purview/concept-best-practices-lineage-azure-data-factory", - "service": "Purview", + "guid": "ed301d6e-872e-452e-9611-cc58b5a4b151", + "link": "https://learn.microsoft.com/azure/vpn-gateway/site-to-site-vpn-private-peering", + "service": "ExpressRoute", "services": [ + "ExpressRoute", + "VPN", "WAF" ], "severity": "Medium", - "text": "Follow Purview Data Lineage Best Practices", - "waf": "Reliability" + "text": "For scenarios where MACsec isn't an option (for example, not using ExpressRoute Direct), use a VPN gateway to establish IPsec tunnels over ExpressRoute private peering.", + "training": "https://learn.microsoft.com/learn/paths/implement-network-security/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "9579e76b-896e-4710-a7da-7be9956d14d3", - "link": "https://learn.microsoft.com/purview/concept-best-practices-scanning", - "service": "Purview", + "guid": "558fd772-49b8-4211-82df-27ee412e7f98", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", + "service": "ExpressRoute", "services": [ + "ACR", "WAF" ], - "severity": "Medium", - "text": "Follow Best Practices for Scanning Registered Sources", - "waf": "Reliability" + "severity": "High", + "text": "Ensure no overlapping IP address spaces across Azure regions and on-premises locations are used.", + "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "c49d997c-b3d1-4325-aa22-5c6f4e0685ed", - "link": "https://learn.microsoft.com/purview/concept-best-practices-classification", - "service": "Purview", + "graph": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr", + "guid": "3f630472-2dd6-49c5-a5c2-622f54b69bad", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", + "service": "VNet", "services": [ "WAF" ], "severity": "Medium", - "text": "Follow Classification Best Practices in Governance Portal", - "waf": "Reliability" + "text": "Use IP addresses from the address allocation ranges for private internets (RFC 1918).", + "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "ddea8a4b-7cde-4b3c-91fc-2fc14eea6e69", - "link": "https://learn.microsoft.com/purview/sensitivity-labels-frequently-asked-questions", - "service": "Purview", + "graph": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant", + "guid": "33aad5e8-c68e-41d7-9667-313b4f5664b5", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", + "service": "VNet", "services": [ + "VNet", "WAF" ], - "severity": "Medium", - "text": "Perform Sensitivity Labelling in the Purview Data Map", - "waf": "Reliability" + "severity": "High", + "text": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16).", + "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", + "waf": "Performance" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "d8d9a3ed-c218-4e68-9ab0-67acb49e5b96", - "link": "https://learn.microsoft.com/purview/concept-data-share", - "service": "Purview", + "guid": "f348ef25-4c27-4d42-b8bb-ac7571559ab9", + "link": "https://learn.microsoft.com/azure/site-recovery/concepts-on-premises-to-azure-networking#retain-ip-addresses", + "service": "VNet", "services": [ - "Storage", + "ASR", "WAF" ], - "severity": "Low", - "text": "Leverage Azure Storage in-place data sharing with Microsoft Purview", + "severity": "High", + "text": "Do not use overlapping IP address ranges for production and disaster recovery sites.", + "training": "https://learn.microsoft.com/learn/paths/az-104-manage-virtual-networks/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", "checklist": "WAF checklist", - "guid": "03324ecf-8cc1-4331-ada6-1170269f4fb4", - "link": "https://learn.microsoft.com/purview/concept-insights", - "service": "Purview", + "graph": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)", + "guid": "0c47f486-656d-4699-8c30-edef5b8a93c4", + "link": "https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone", + "service": "Public IP Addresses", "services": [ + "ACR", "WAF" ], - "severity": "Low", - "text": "Leverage Data Estate Insights", + "severity": "High", + "text": "Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. ", + "training": "https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "aa3d3ef7-f317-46c4-a97b-15b8a219a4ab", - "link": "https://learn.microsoft.com/purview/catalog-adoption-insights", - "service": "Purview", + "guid": "153e8908-ae28-4c84-a33b-6b7808b9fe5c", + "link": "https://learn.microsoft.com/azure/dns/private-dns-getstarted-portal", + "service": "DNS", "services": [ + "DNS", "WAF" ], - "severity": "Low", - "text": "Use Data stewardship and Catalog adoption", - "waf": "Reliability" + "severity": "Medium", + "text": "For environments where name resolution in Azure is all that's required, use Azure Private DNS for resolution with a delegated zone for name resolution (such as 'azure.contoso.com').", + "training": "https://learn.microsoft.com/learn/paths/az-104-manage-virtual-networks/", + "waf": "Operations" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "eb578790-24d2-4267-a6d2-0b56c56a9581", - "link": "https://learn.microsoft.com/purview/concept-insights", - "service": "Purview", + "guid": "41049d40-3a92-43c3-974d-00018ac6a9e0", + "link": "https://learn.microsoft.com/azure/dns/dns-private-resolver-overview", + "service": "DNS", "services": [ + "ACR", + "DNS", "WAF" ], - "severity": "Low", - "text": "Use Inventory and Ownership", - "waf": "Reliability" + "severity": "Medium", + "text": "For environments where name resolution across Azure and on-premises is required and there is no existing enterprise DNS service like Active Directory, use Azure DNS Private Resolver to route DNS requests to Azure or to on-premises DNS servers.", + "training": "https://learn.microsoft.com/training/modules/intro-to-azure-dns-private-resolver/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "19bf8d8e-5c58-46b7-b8cd-c15acc075ee9", - "link": "https://learn.microsoft.com/purview/glossary-insights", - "service": "Purview", + "guid": "1e6a83de-5de3-42c1-a924-81607d5d1e4e", + "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-name-resolution-for-vms-and-role-instances", + "service": "DNS", "services": [ + "DNS", "WAF" ], "severity": "Low", - "text": "Leverage Insights for Glossary, Classifications, Sensitivity Labels", - "waf": "Reliability" + "text": "Special workloads that require and deploy their own DNS (such as Red Hat OpenShift) should use their preferred DNS solution.", + "training": "https://learn.microsoft.com/training/courses/az-700t00", + "waf": "Operations" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "Microsoft.Network/dnsZones", "checklist": "WAF checklist", - "guid": "b130a888-9579-4e76-a896-e710a7da7be9", - "link": "https://learn.microsoft.com/purview/compliance-manager", - "service": "Purview", + "guid": "614658d3-558f-4d77-849b-821112df27ee", + "link": "https://learn.microsoft.com/azure/dns/private-dns-autoregistration", + "service": "DNS", + "services": [ + "VNet", + "VM", + "DNS", + "WAF" + ], + "severity": "High", + "text": "Enable auto-registration for Azure DNS to automatically manage the lifecycle of the DNS records for the virtual machines deployed within a virtual network.", + "training": "https://learn.microsoft.com/learn/paths/az-104-manage-virtual-networks/", + "waf": "Operations" + }, + { + "arm-service": "Microsoft.Network/dnsZones", + "checklist": "WAF checklist", + "guid": "18c80eb0-582a-4198-bf5c-d8800b2d263b", + "link": "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/private-link-and-dns-integration-at-scale#private-link-and-dns-integration-in-hub-and-spoke-network-architectures", + "service": "DNS", "services": [ + "DNS", "WAF" ], "severity": "Medium", - "text": "Generate assessment scores", + "text": "Implement a plan for managing DNS resolution between multiple Azure regions and when services fail over to another region", + "training": "https://learn.microsoft.com/learn/paths/az-104-manage-virtual-networks/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "microsoft.network/bastionHosts", "checklist": "WAF checklist", - "guid": "956d14d3-c49d-4997-ab3d-1325aa225c6f", - "link": "https://learn.microsoft.com/purview/compliance-manager-scoring", - "service": "Purview", + "guid": "ee1ac551-c4d5-46cf-b035-d0a3c50d87ad", + "link": "https://learn.microsoft.com/azure/bastion/bastion-overview", + "service": "Bastion", "services": [ + "Bastion", "WAF" ], "severity": "Medium", - "text": "Profiling- get summaries of data content", - "waf": "Reliability" + "text": "Use Azure Bastion to securely connect to your network.", + "training": "https://learn.microsoft.com/training/modules/intro-to-azure-bastion/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "microsoft.network/bastionHosts", "checklist": "WAF checklist", - "guid": "4e0685ed-ddea-48a4-a7cd-eb3c61fc2fc1", - "link": "https://learn.microsoft.com/purview/concept-policies-data-owner#microsoft-purview-policy-concepts", - "service": "Purview", + "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant", + "guid": "6eab9eb6-762b-485e-8ea8-15aa5dba0bd0", + "link": "https://learn.microsoft.com/azure/bastion/bastion-faq#subnet", + "service": "Bastion", "services": [ - "AzurePolicy", + "VNet", + "Bastion", "WAF" ], - "severity": "Low", - "text": "Follow Microsoft Purview Data Owner access policies", - "waf": "Reliability" + "severity": "Medium", + "text": "Use Azure Bastion in a subnet /26 or larger.", + "training": "https://learn.microsoft.com/training/modules/intro-to-azure-bastion/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", "checklist": "WAF checklist", - "guid": "4eea6e69-d8d9-4a3e-bc21-8e687ab067ac", - "link": "https://learn.microsoft.com/purview/concept-self-service-data-access-policy", - "service": "Purview", + "guid": "1d7aa9b6-4704-4489-a804-2d88e79d17b7", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", + "service": "WAF", "services": [ + "ACR", + "FrontDoor", "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "Follow Self-service access policies", - "waf": "Reliability" + "severity": "Medium", + "text": "Use Azure Front Door and WAF policies to provide global protection across Azure regions for inbound HTTP/S connections to a landing zone.", + "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", + "waf": "Security" }, { - "arm-service": "Microsoft.Purview/accounts", + "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", "checklist": "WAF checklist", - "guid": "b49e5b96-0332-44ec-b8cc-13318da61170", - "link": "https://learn.microsoft.com/purview/concept-policies-devops", - "service": "Purview", + "guid": "3b22a5a6-7e7a-48ed-9b30-e38c3f29812b", + "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", + "service": "WAF", "services": [ + "AppGW", + "FrontDoor", "AzurePolicy", "WAF" ], "severity": "Low", - "text": "Follow DevOps policies", - "waf": "Reliability" + "text": "When using Azure Front Door and Azure Application Gateway to help protect HTTP/S apps, use WAF policies in Azure Front Door. Lock down Azure Application Gateway to receive traffic only from Azure Front Door.", + "training": "https://learn.microsoft.com/learn/paths/secure-application-delivery/", + "waf": "Security" }, { - "arm-service": "microsoft.cache/redis", + "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", "checklist": "WAF checklist", - "guid": "65285269-440b-44be-9d3e-0844276d4bdc", - "link": "https://learn.microsoft.com/azure/azure-cache-for-redis/cache-how-to-zone-redundancy", - "service": "Redis", + "guid": "2363cefe-179b-4599-be0d-5973cd4cd21b", + "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", + "service": "WAF", "services": [ - "WAF", - "ACR" + "VNet", + "WAF" ], "severity": "High", - "text": "Enable zone redundancy for Azure Cache for Redis. Azure Cache for Redis supports zone redundant configurations in the Premium and Enterprise tiers. A zone redundant cache can place its nodes across different Azure Availability Zones in the same region. It eliminates data center or AZ outage as a single point of failure and increases the overall availability of your cache.", - "waf": "Reliability" + "text": "When WAFs and other reverse proxies are required for inbound HTTP/S connections, deploy them within a landing-zone virtual network and together with the apps that they're protecting and exposing to the internet.", + "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", + "waf": "Security" }, { - "arm-service": "microsoft.cache/redis", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "bc178bdc-5a06-4ca7-8443-51e19dd34429", - "link": "https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-high-availability#persistence", - "service": "Redis", + "guid": "088137f5-e6c4-4cfd-9e50-4547c2447ec6", + "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-reference-architectures", + "service": "VNet", "services": [ - "Storage", + "VNet", + "DDoS", "WAF" ], - "severity": "Medium", - "text": "Configure data persistence for an Azure Cache for Redis instance. Because your cache data is stored in memory, a rare and unplanned failure of multiple nodes can cause all the data to be dropped. To avoid losing data completely, Redis persistence allows you to take periodic snapshots of in-memory data, and store it to your storage account.", - "waf": "Reliability" + "severity": "High", + "text": "Use Azure DDoS Network or IP Protection plans to help protect Public IP Addresses endpoints within the virtual networks.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { - "arm-service": "microsoft.cache/redis", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "eb722823-7a15-41c5-ab4e-4f1814387e5c", - "link": "https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-high-availability#storage-account-for-persistence", - "service": "Redis", + "guid": "b034c01e-110b-463a-b36e-e3346e57f225", + "link": "https://learn.microsoft.com/azure/virtual-network/ip-services/default-outbound-access", + "service": "VNet", "services": [ - "Storage", "WAF" ], - "severity": "Medium", - "text": "Use Geo-redundant storage account to persist Azure Cache for Redis data, or zonally redundant where geo-redundancy is not available", + "severity": "High", + "text": "Plan for how to manage your network outbound traffic configuration and strategy before the upcoming breaking change. On September 30, 2025, default outbound access for new deployments will be retired and only explicit access configurations will be allowed.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-networks/", "waf": "Reliability" }, { - "arm-service": "microsoft.cache/redis", + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "guid": "a8c26c9b-32ab-45bd-bc69-98a135e33789", - "link": "https://learn.microsoft.com/azure/azure-cache-for-redis/cache-how-to-geo-replication", - "service": "Redis", + "guid": "b1c82a3f-2320-4dfa-8972-7ae4823c8930", + "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-reference-architectures", + "service": "VNet", "services": [ - "ASR", + "DDoS", "WAF" ], - "severity": "Medium", - "text": "Configure passive geo-replication for Premium Azure Cache for Redis instances. Geo-replication is a mechanism for linking two or more Azure Cache for Redis instances, typically spanning two Azure regions. Geo-replication is designed mainly for cross-region disaster recovery. Two Premium tier cache instances are connected through geo-replication in a way that provides reads and writes to your primary cache, and that data is replicated to the secondary cache.", - "waf": "Reliability" + "severity": "High", + "text": "Add diagnostic settings to save DDoS related logs for all the protected public IP addresses (DDoS IP or Network Protection).", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachineScaleSets", + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "description": "Automatic instance repairs ensure that unhealthy instances are promptly identified and replaced, maintaining a set of healthy instances within your scale set.", - "guid": "7e13c105-675c-41e9-95b4-59837ff7ae7c", - "link": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-automatic-instance-repairs", - "service": "VMSS", + "guid": "3c5a808d-c695-4c14-a63c-c7ab7a510e41", + "link": "https://github.com/Azure/Enterprise-Scale/wiki/ALZ-Policies#corp", + "service": "Policy", "services": [ "VM", + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "Enable automatic instance repairs for enhanced VM Scale Sets resiliency", - "waf": "Reliability" - }, - { - "arm-service": "Microsoft.Compute/virtualMachines", - "checklist": "WAF checklist", - "description": "Ensure that Azure Backup is utilized appropriately to meet your organization's resiliency requirements for Azure virtual machines (VMs).", - "guid": "4d874a74-8b66-42d6-b150-512a66498f6d", - "link": "https://learn.microsoft.com/azure/backup/backup-azure-vms-introduction", - "service": "VM", - "services": [ - "VM", - "WAF", - "Backup" - ], "severity": "High", - "text": "Consider Azure Backup to meet your resiliency requirements for Azure VMs", - "waf": "Reliability" + "text": "Ensure there is a policy assignment to deny Public IP addresses directly tied to Virtual Machines. Use exclusions if public IPs are needed on specific VMs.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", + "waf": "Security" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Single Instance VMs using Premium SSD or Ultra Disk for all Operating System Disks and Data Disks are guaranteed to have Virtual Machine Connectivity of at least 99.9%", - "guid": "8052d88e-79d1-47b7-9b22-a5a67e7a8ed4", - "link": "https://learn.microsoft.com/azure/virtual-machines/disks-types", - "service": "VM", + "guid": "359c373e-7dd6-4162-9a36-4a907ecae48e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/connectivity-to-azure", + "service": "ExpressRoute", "services": [ - "VM", + "Backup", + "ExpressRoute", + "VPN", "WAF" ], - "severity": "High", - "text": "Use Premium or Ultra disks for production VMs", - "waf": "Reliability" + "severity": "Medium", + "text": "Use ExpressRoute as the primary connection to Azure. Use VPNs as a source of backup connectivity.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Performance" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Azure automatically replicates managed disks within a region to ensure data durability and protect against single-point failures.", - "guid": "b31e38c3-f298-412b-8363-cffe179b599d", - "link": "https://learn.microsoft.com/azure/virtual-machines/managed-disks-overview", - "service": "VM", + "description": "You can use AS-path prepending and connection weights to influence traffic from Azure to on-premises, and the full range of BGP attributes in your own routers to influence traffic from on-premises to Azure.", + "guid": "f29812b2-363c-4efe-879b-599de0d5973c", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-routing", + "service": "ExpressRoute", "services": [ - "VM", + "ExpressRoute", "WAF" ], - "severity": "High", - "text": "Ensure Managed Disks are used for all VMs", + "severity": "Medium", + "text": "When you use multiple ExpressRoute circuits or multiple on-prem locations, use BGP attributes to optimize routing.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Temporary disks are intended for short-term storage of non-persistent data such as page files, swap files, or SQL Server tempdb. Storing persistent data on temporary disks can lead to data loss during maintenance events or VM redeployment.", - "guid": "e0d5973c-d4ce-432c-8881-37f6f7c4c0d4", - "link": "https://learn.microsoft.com/azure/virtual-machines/managed-disks-overview#temporary-disk", - "service": "VM", + "graph": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant", + "guid": "d4cd21b0-8813-47f5-b6c4-cfd3e504547c", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku", + "service": "ExpressRoute", "services": [ - "VM", - "Storage", - "SQL", + "ExpressRoute", + "VPN", "WAF" ], "severity": "Medium", - "text": "Do not use the Temp disk for anything that is not acceptable to be lost", - "waf": "Reliability" + "text": "Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Performance" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Co-locate your compute, storage, networking, and data resources across an availability zone, and replicate this arrangement in other availability zones.", - "guid": "e514548d-2447-4ec6-9138-b8200f1ce16e", - "link": "https://learn.microsoft.com/azure/reliability/availability-zones-overview", - "service": "VM", + "graph": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant", + "guid": "7025b442-f6e9-4af6-b11f-c9574916016f", + "link": "https://learn.microsoft.com/azure/expressroute/plan-manage-cost", + "service": "ExpressRoute", "services": [ - "Storage", - "VM", - "WAF", - "ACR" + "Cost", + "ExpressRoute", + "WAF" ], - "severity": "Medium", - "text": "Leverage Availability Zones for your VMs in regions where they are supported", - "waf": "Reliability" + "severity": "High", + "text": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost.", + "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", + "waf": "Cost" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Use at least two VMs in Availability Sets to isolate VMs on different fault and update domains.", - "guid": "5a785d6f-e96c-496a-b884-4cf3b2b38c88", - "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", - "service": "VM", + "graph": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id", + "guid": "f4e7926a-ec35-476e-a412-5dd17136bd62", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local", + "service": "ExpressRoute", "services": [ - "VM", + "Cost", + "ExpressRoute", "WAF" ], - "severity": "Medium", - "text": "For regions that do not support Availability Zones deploy VMs into Availability Sets", - "waf": "Reliability" + "severity": "High", + "text": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU.", + "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", + "waf": "Cost" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Azure provides multiple options for VM redundancy to meet different requirements (Availability Zones, Virtual Machine Scale Sets, Availability Sets, Azure Site Recovery)", - "guid": "6ba2c021-4991-414a-9d3c-e574dccbd979", - "link": "https://learn.microsoft.com/azure/virtual-machines/availability", - "service": "VM", + "graph": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant", + "guid": "2447ec66-138a-4720-8f1c-e16ed301d6e8", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways", + "service": "ExpressRoute", "services": [ - "VM", - "ASR", + "ExpressRoute", "WAF" ], - "severity": "High", - "text": "Avoid running a production workload on a single VM", + "severity": "Medium", + "text": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Azure Site Recovery enables you to achieve low RTO (Recovery Time Objective) for your Azure and hybrid VMs by providing continuous replication and failover capabilities.", - "guid": "2a6bcca2-b5fe-4a1e-af3d-d95d48c7c891", - "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", - "service": "VM", + "guid": "72e52e36-11cc-458b-9a4b-1511e43a58a9", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/connectivity-to-azure", + "service": "ExpressRoute", "services": [ - "VM", - "ASR", - "AVS", + "ExpressRoute", "WAF" ], - "severity": "High", - "text": "For Azure and on-premises VMs (Hyper-V/Phyiscal/VMware) with low RTO requirements use Azure Site Recovery", - "waf": "Reliability" + "severity": "Medium", + "text": "For scenarios that require bandwidth higher than 10 Gbps or dedicated 10/100-Gbps ports, use ExpressRoute Direct.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Performance" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "By using Capacity Reservations, you can effectively manage capacity for critical workloads, ensuring resource availability in specified regions.", - "guid": "bd7bb012-f7b9-45e0-9e15-8e3ea3992c2d", - "link": "https://learn.microsoft.com/azure/virtual-machines/capacity-reservation-overview", - "service": "VM", + "guid": "c2299c4d-7b57-4d0c-9555-62f2b3e4563a", + "link": "https://learn.microsoft.com/azure/expressroute/about-fastpath", + "service": "ExpressRoute", "services": [ + "ExpressRoute", "WAF" ], - "severity": "Low", - "text": "Use Capacity Reservations for critical workloads that require guaranteed capacity", - "waf": "Reliability" + "severity": "Medium", + "text": "When low latency is required, or throughput from on-premises to Azure must be greater than 10 Gbps, enable FastPath to bypass the ExpressRoute gateway from the data path.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Performance" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/virtualNetworkGateways", "checklist": "WAF checklist", - "description": "By ensuring that the necessary quotas are increased in your DR region before testing failover with ASR, you can avoid any potential resource constraints during the recovery process for failed over VMs.", - "guid": "e6e2065b-3a76-4af4-a691-e8939ada4666", - "link": "https://learn.microsoft.com/azure/quotas/per-vm-quota-requests", - "service": "VM", + "graph": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant", + "guid": "4d873974-8b66-42d6-b15f-512a65498f6d", + "link": "https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway", + "service": "VPN", "services": [ - "VM", - "ASR", + "VPN", "WAF" ], "severity": "Medium", - "text": "Increase quotas in DR region before testing failover with ASR", + "text": "Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available).", + "training": "https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/virtualNetworkGateways", "checklist": "WAF checklist", - "description": "Scheduled Events is an Azure Metadata Service that provides information about upcoming maintenance events for virtual machines (VMs). By leveraging Scheduled Events, you can proactively prepare your applications for VM maintenance, minimizing disruption and improving the availability of your VMs.", - "guid": "6d3b475a-5c7a-4cbe-99bb-e64dd8902e87", - "link": "https://learn.microsoft.com/azure/virtual-machines/windows/scheduled-events", - "service": "VM", + "guid": "45866df8-cf85-4ca9-bbe2-65ec1478919e", + "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-highlyavailable", + "service": "VPN", "services": [ - "VM", + "VPN", "WAF" ], - "severity": "Low", - "text": "Utilize Scheduled Events to prepare for VM maintenance", + "severity": "Medium", + "text": "Use redundant VPN appliances on-premises (active/active or active/passive).", + "training": "https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Use Zone-redundant Storage (ZRS) in the primary region for scenarios that require high availability and for restricting replication to a particular country or region. For protection against regional disasters, use Geo-zone-redundant Storage (GZRS), which combines ZRS in the primary region with geo-replication to a secondary region?.", - "guid": "48c7c891-dcb1-4f7d-9769-ae568ba38d4a", - "link": "https://learn.microsoft.com/azure/storage/common/storage-redundancy", - "service": "Azure Storage", + "guid": "718cb437-b060-2589-8856-2e93a5c6633b", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-erdirect-about", + "service": "ExpressRoute", "services": [ - "Storage", + "Cost", + "ExpressRoute", "WAF" ], - "severity": "Medium", - "text": "Choose the most appropriate data redundancy option for Azure Storage based on your requirements", - "waf": "Reliability" + "severity": "High", + "text": "If using ExpressRoute Direct, consider using ExpressRoute Local circuits to the local Azure regions to save costs.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Cost" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Assigning a Delete lock to your storage account helps protect the availability of your data, minimizing the risk of disruptions to your business operations.", - "guid": "85e2213d-bd7b-4b01-8f7b-95e06e158e3e", - "link": "https://learn.microsoft.com/azure/storage/common/lock-account-resource", - "service": "Azure Storage", + "guid": "8042d88e-79d1-47b7-9b22-a5a67e7a8ed4", + "link": "https://learn.microsoft.com/azure/architecture/framework/services/networking/expressroute/reliability", + "service": "ExpressRoute", "services": [ - "Storage", + "ExpressRoute", "WAF" ], - "severity": "Low", - "text": "Apply a Delete lock to prevent accidental or malicious deletion of storage accounts", - "waf": "Reliability" + "severity": "Medium", + "text": "When traffic isolation or dedicated bandwidth is required, such as for separating production and nonproduction environments, use different ExpressRoute circuits. It will help you ensure isolated routing domains and alleviate noisy-neighbor risks.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Security" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Container soft delete protects your data from being accidentally deleted by maintaining the deleted data in the system for a specified period of time.", - "guid": "a3992c2d-e6e2-4065-a3a7-6af4a691e893", - "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-container-enable", - "service": "Azure Storage", + "guid": "b30e38c3-f298-412b-8363-cefe179b599d", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-monitoring-metrics-alerts", + "service": "ExpressRoute", "services": [ - "Storage", + "ExpressRoute", + "Monitor", "WAF" ], - "severity": "Low", - "text": "Enable soft delete for Storage Account Containers", - "waf": "Reliability" + "severity": "Medium", + "text": "Monitor ExpressRoute availability and utilization using built-in Express Route Insights.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Operations" }, { - "arm-service": "Microsoft.Storage/storageAccounts", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Blob soft delete protects an individual blob and its versions, snapshots, and metadata from accidental deletes or overwrites by maintaining the deleted data in the system for a specified period of time.", - "guid": "9ada4666-7e13-4c10-96b9-153d89f89dc7", - "link": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-enable", - "service": "Azure Storage", + "guid": "5bf68dc9-325e-4873-bf88-f8214ef2e5d2", + "link": "https://learn.microsoft.com/azure/expressroute/how-to-configure-connection-monitor", + "service": "ExpressRoute", "services": [ - "Storage", + "ACR", + "Monitor", + "NetworkWatcher", "WAF" ], - "severity": "Low", - "text": "Enable soft delete for blobs", - "waf": "Reliability" + "severity": "Medium", + "text": "Use Connection Monitor for connectivity monitoring across the network, especially between on-premises and Azure.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Operations" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Azure Backup enhanced soft delete provides critical protection against ransomware attacks by retaining deleted backups, enabling recovery from potential ransomware encryption or deletion.", - "guid": "b44be3b1-a27f-48b9-b91b-e1038df03a82", - "link": "https://learn.microsoft.com/azure/backup/backup-azure-enhanced-soft-delete-about", - "service": "Azure Backup", + "graph": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2)", + "guid": "e0d5973c-d4cd-421b-8881-37f5e6c4cfd3", + "link": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution", + "service": "ExpressRoute", "services": [ - "WAF", - "Backup" + "ExpressRoute", + "WAF" ], "severity": "Medium", - "text": "Enable Azure Backup enhanced soft delete for improved data protection and recovery", + "text": "Use ExpressRoute circuits from different peering locations for redundancy.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", "waf": "Reliability" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Azure Backup's multi-user authorization enables fine-grained control over user access to backup resources, allowing you to restrict privileges and ensure proper authentication and authorization for backup operations.", - "guid": "2cd463cb-bbc8-4ac2-a9eb-c92a43da1dae", - "link": "https://learn.microsoft.com/azure/backup/multi-user-authorization-concept", - "service": "Azure Backup", + "guid": "cf3fe65c-fec0-495a-8edc-9675200f2add", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-coexist-resource-manager", + "service": "ExpressRoute", "services": [ - "WAF", - "Backup" + "ExpressRoute", + "VPN", + "WAF" ], - "severity": "Low", - "text": "Implement multi-user authorization for Azure Backup to ensure secure and controlled access to backup resources", + "severity": "Medium", + "text": "Use site-to-site VPN as failover of ExpressRoute, if only using a single ExpressRoute circuit.", + "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", "waf": "Reliability" }, { - "arm-service": "Microsoft.RecoveryServices/vaults", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Azure Immutable Storage provides an additional layer of security by ensuring that backup data stored in the vault cannot be modified or deleted for a specified retention period. This helps safeguard your backups from ransomware attacks that may attempt to compromise or manipulate your backup data.", - "guid": "2cc88147-0607-4c1c-aa0e-614658dd458e", - "link": "https://learn.microsoft.com/azure/backup/backup-azure-immutable-vault-concept?source=recommendations&tabs=recovery-services-vault", - "service": "Azure Backup", + "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation))", + "guid": "72105cc8-aaea-4ee1-8c7a-ad25977afcaf", + "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub", + "service": "ExpressRoute", "services": [ "Storage", - "WAF", - "Backup" + "VNet", + "WAF" ], - "severity": "Low", - "text": "Implement Immutable Storage for your vaults to protect against ransomware and prevent unauthorized modifications to backups", + "severity": "High", + "text": "If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated.", "waf": "Reliability" }, { - "arm-service": "Microsoft.Network/dnsZones", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "To eliminate a single point of failure in your on-premises DNS services and ensure reliable DNS resolution during business continuity and disaster recovery scenarios, it is recommended to utilize Azure DNS Private Resolvers in multiple regions. By deploying two or more Azure DNS private resolvers across different regions, you can enable DNS failover and achieve resiliency in your DNS infrastructure.", - "guid": "43da1dae-2cc8-4814-9060-7c1cca0e6146", - "link": "https://learn.microsoft.com/azure/dns/tutorial-dns-private-resolver-failover", - "service": "DNS", + "guid": "d581a947-69a2-4783-942e-9df3664324c8", + "link": "https://learn.microsoft.com/azure/expressroute/designing-for-high-availability-with-expressroute#active-active-connections", + "service": "ExpressRoute", "services": [ - "DNS", - "ASR", - "WAF", - "ACR" + "ACR", + "ExpressRoute", + "WAF" ], - "severity": "Low", - "text": "Implement DNS Failover using Azure DNS Private Resolvers", + "severity": "High", + "text": "If using ExpressRoute, your on-premises routing should be dynamic: in the event of a connection failure it should converge to the remaining connection of the circuit. Load should be shared across both connections ideally as active/active, although active/passive is supported too.", + "training": "https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/", "waf": "Reliability" }, { - "arm-service": "Microsoft.PowerBI/gateways", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "Use an on-premises data gateway cluster to avoid single points of failure and to load balance traffic across gateways.", - "guid": "89f89dc7-b44b-4e3b-8a27-f8b9e91be103", - "link": "https://learn.microsoft.com/data-integration/gateway/service-gateway-high-availability-clusters", - "service": "Data Gateways", + "guid": "b258f058-b9f6-46cd-b28d-990106f0c3f8", + "link": "https://learn.microsoft.com/azure/expressroute/designing-for-high-availability-with-expressroute", + "service": "ExpressRoute", "services": [ - "WAF", - "ACR" + "ExpressRoute", + "WAF" ], "severity": "Medium", - "text": "Use on-premises data gateway clusters to ensure high availability for business-critical data", + "text": "Ensure the two physical links of your ExpressRoute circuit are connected to two distinct edge devices in your network.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", "waf": "Reliability" }, { - "arm-service": "Microsoft.Compute/virtualMachines", + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "description": "When choosing the best option for deploying NVAs in Azure, it is crucial to consider the vendor's recommendations and validate that the specific design has been vetted and validated by the NVA vendor. The vendor should also provide the necessary NVA configuration for seamless integration in Azure.", - "guid": "8b1188b3-c6a4-46ce-a544-451e192d3442", - "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/nva-ha", - "service": "NVA", + "guid": "fe2a1b53-6fbd-4c67-b58a-85d7c7a0afcb", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-bfd", + "service": "ExpressRoute", "services": [ - "NVA", "WAF" ], - "severity": "High", - "text": "Deploy Network Virtual Appliances (NVAs) in a vendor supported configuration for High Availability", + "severity": "Medium", + "text": "Ensure Bidirectional Forwarding Detection (BFD) is enabled and configured on customer or provider edge routing devices.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", "waf": "Reliability" }, { + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "4620dc87-e948-4ce8-8426-f3e6e5d7bd85", - "link": "https://learn.microsoft.com/azure/sap/center-sap-solutions/overview", - "service": "SAP", + "guid": "669b215a-ce43-4371-8f6f-11047f6490f1", + "link": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering", + "service": "ExpressRoute", "services": [ - "WAF", - "SAP" + "ExpressRoute", + "WAF" ], - "severity": "Medium", - "text": "Azure Center for SAP solutions (ACSS) is an Azure offering that makes SAP a top-level workload on Azure. ACSS is an end-to-end solution that enables you to create and run SAP systems as a unified workload on Azure and provides a more seamless foundation for innovation. You can take advantage of the management capabilities for both new and existing Azure-based SAP systems.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-center-sap-solutions/?source=recommendations", - "waf": "Operations" + "severity": "High", + "text": "Connect the ExpressRoute Gateway to two or more circuits from different peering locations for higher resiliency.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Reliability" }, { + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "5d75e99d-624d-4afe-91d9-e17adc580790", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-platform-automation-and-devops", - "service": "SAP", + "guid": "3f79ed00-203b-4c95-9efd-691505f5a1f9", + "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-howto-setup-alerts-virtual-network-gateway-log", + "service": "ExpressRoute", "services": [ - "WAF", - "SAP" + "VNet", + "ExpressRoute", + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Azure supports automating SAP deployments in Linux and Windows. SAP Deployment Automation Framework is an open-source orchestration tool that can deploy, install, and maintain SAP environments.", - "training": "https://github.com/Azure/sap-automation", + "text": "Configure diagnostic logs and alerts for ExpressRoute virtual network gateway.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", "waf": "Operations" }, { + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "d17f6f39-a377-48a2-931f-5ead3ebe33a8", - "link": "https://learn.microsoft.com/azure/well-architected/sap/design-areas/data-platform", - "service": "SAP", + "guid": "5234c93f-b651-41dd-80c1-234177b91ced", + "link": "https://learn.microsoft.com/azure/expressroute/virtual-network-connectivity-guidance", + "service": "ExpressRoute", "services": [ - "WAF", - "SAP" + "VNet", + "ExpressRoute", + "WAF" ], "severity": "Medium", - "text": "Perform a point-in-time recovery for your production databases at any point and in a time frame that meets your RTO; point-in-time recovery typically includes operator errors deleting data either on the DBMS layer or through SAP, incidentally", - "waf": "Reliability" + "text": "Do not use ExpressRoute circuits for VNet-to-VNet communication.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Performance" }, { "checklist": "WAF checklist", - "guid": "c4b8e117-930b-4dbd-ae50-7bc5faf6f91a", - "service": "SAP", + "guid": "8ac6a9e0-1e6a-483d-b5de-32c199248160", + "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about", + "service": "N/A", "services": [ - "WAF", - "Backup" + "ACR", + "WAF" ], - "severity": "Medium", - "text": "Test the backup and recovery times to verify that they meet your RTO requirements for restoring all systems simultaneously after a disaster.", - "waf": "Reliability" + "severity": "Low", + "text": "Do not send Azure traffic to hybrid locations for inspection. Instead, follow the principle 'traffic in Azure stays in Azure' so that communication across resources in Azure occurs via the Microsoft backbone network.", + "waf": "Performance" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "b651423c-8552-42db-a545-5cb50c05527a", - "link": "https://learn.microsoft.com/azure/reliability/cross-region-replication-azure", - "service": "SAP", + "guid": "e6c4cfd3-e504-4547-a244-7ec66138a720", + "link": "https://learn.microsoft.com/azure/firewall/overview", + "service": "Firewall", "services": [ - "SQL", - "Storage", - "ASR", - "Backup", - "WAF", - "SAP" + "Firewall", + "WAF" ], "severity": "High", - "text": "You can replicate standard storage between paired regions, but you can't use standard storage to store your databases or virtual hard disks. You can replicate backups only between paired regions that you use. For all your other data, run your replication by using native DBMS features like SQL Server Always On or SAP HANA System Replication. Use a combination of Site Recovery, rsync or robocopy, and other third-party software for the SAP application layer.", - "training": "https://learn.microsoft.com/training/paths/ensure-business-continuity-implement-disaster-recovery/", - "waf": "Reliability" + "text": "Use Azure Firewall to govern Azure outbound traffic to the internet, non-HTTP/S inbound connections, and East/West traffic filtering (if the organization requires it).", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "aa208dca-784f-46c6-9014-cc919c542dc9", - "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-zones", - "service": "SAP", + "guid": "5a4b1511-e43a-458a-ac22-99c4d7b57d0c", + "link": "https://learn.microsoft.com/azure/firewall-manager/policy-overview", + "service": "Firewall", "services": [ + "ACR", + "Firewall", + "RBAC", "WAF", - "SAP" + "AzurePolicy" ], "severity": "Medium", - "text": "When using Azure Availability Zones to achieve high availability, you must consider latency between SAP application servers and database servers. For zones with high latencies, operational procedures need to be in place to ensure that SAP application servers and database servers are running in the same zone at all times.", - "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations", - "waf": "Reliability" + "text": "Create a global Azure Firewall policy to govern security posture across the global network environment and assign it to all Azure Firewall instances. Allow for granular policies to meet requirements of specific regions by delegating incremental firewall policies to local security teams via Azure role-based access control.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "graph": "resources| where type =~ 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType =~ 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant", - "guid": "ba07c007-1f90-43e9-aa4f-601346b80352", - "link": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering", - "service": "SAP", + "guid": "655562f2-b3e4-4563-a4d8-739748b662d6", + "link": "https://learn.microsoft.com/azure/firewall-manager/deploy-trusted-security-partner", + "service": "Firewall", "services": [ - "VPN", - "ExpressRoute", - "ASR", + "Firewall", "WAF" ], - "severity": "High", - "text": "Set up ExpressRoute connections from on-premises to the primary and secondary Azure disaster recovery regions. Also, as an alternative to using ExpressRoute, consider setting up VPN connections from on-premises to the primary and secondary Azure disaster recovery regions.", - "training": "https://learn.microsoft.com/azure/expressroute/use-s2s-vpn-as-backup-for-expressroute-privatepeering", - "waf": "Reliability" + "severity": "Low", + "text": "Configure supported partner SaaS security providers within Firewall Manager if the organization wants to use such solutions to help protect outbound connections.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "d2b30195-b11d-4a8f-a672-28b2b4169a7c", - "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant", + "guid": "14d99880-2f88-47e8-a134-62a7d85c94af", + "link": "https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules", + "service": "Firewall", "services": [ - "AKV", - "WAF", - "ACR" + "Firewall", + "DNS", + "WAF" ], - "severity": "Low", - "text": "Replicate key vault contents like certificates, secrets, or keys across regions so you can decrypt data in the DR region.", - "waf": "Reliability" + "severity": "High", + "text": "Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "05f1101d-250f-40e7-b2a1-b674ab50edbd", - "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-s4hana", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant", + "guid": "c10d51ef-f999-455d-bba0-5c90ece07447", + "link": "https://learn.microsoft.com/azure/firewall/premium-features", + "service": "Firewall", "services": [ - "ASR", - "WAF", - "SAP", - "VNet" + "Firewall", + "WAF" ], - "severity": "Medium", - "text": "Peer the primary and disaster recovery virtual networks. For example, for HANA System Replication, an SAP HANA DB virtual network needs to be peered to the disaster recovery site's SAP HANA DB virtual network.", - "waf": "Reliability" + "severity": "High", + "text": "Use Azure Firewall Premium to enable additional security features.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-firewall/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "d3351bf7-628a-46de-917d-dfc11d3b6b40", - "link": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-service-levels", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant", + "guid": "e9c8f584-6d5e-473b-8dc5-acc9fbaab4e3", + "link": "https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules", + "service": "Firewall", "services": [ - "Storage", - "WAF", - "SAP" + "Firewall", + "WAF" ], - "severity": "Low", - "text": "If you use Azure NetApp Files storage for your SAP deployments, at a minimum, create two Azure NetApp Files accounts in the Premium tier, in two regions.", - "training": "https://learn.microsoft.com/training/modules/choose-service-level-azure-netapp-files-hpc-applications/2-identify-decision-criteria", - "waf": "Reliability" + "severity": "High", + "text": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection.", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "726a1d3e-5508-4a06-9d54-93f4b50040c1", - "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant", + "guid": "b9d0dff5-bdd4-4cd8-88ed-5811610b2b2c", + "link": "https://learn.microsoft.com/azure/firewall/premium-features#idps", + "service": "Firewall", "services": [ + "Firewall", "WAF" ], "severity": "High", - "text": "Native database replication technology should be used to synchronize the database in a HA pair.", - "training": "https://learn.microsoft.com/training/modules/implement-disaster-recovery-for-sap-workloads-azure/?source=recommendations", - "waf": "Reliability" + "text": "Configure Azure Firewall IDPS mode to Deny for additional protection.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-firewall/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr", - "guid": "6561f847-3db5-4ff8-9200-5ad3c3b436ad", - "link": "https://learn.microsoft.com/ja-jp/azure/virtual-network/virtual-networks-faq", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant", + "guid": "a3784907-9836-4271-aafc-93535f8ec08b", + "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview", + "service": "Firewall", "services": [ "VNet", + "NVA", + "Firewall", + "VWAN", + "Storage", "WAF" ], "severity": "High", - "text": "The CIDR for the primary virtual network (VNet) shouldn't conflict or overlap with the CIDR of the DR site's VNet", - "training": "https://learn.microsoft.com/training/paths/azure-fundamentals-describe-azure-architecture-services/?source=recommendations", - "waf": "Reliability" + "text": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance.", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "0258ed30-fe42-434f-87b9-58f91f908e0a", - "service": "SAP", + "guid": "715d833d-4708-4527-90ac-1b142c7045ba", + "link": "https://learn.microsoft.com/azure/firewall/firewall-structured-logs", + "service": "Firewall", "services": [ - "VM", - "ASR", - "WAF", - "Entra" + "Storage", + "Firewall", + "WAF" ], - "severity": "High", - "text": "Use Site Recovery to replicate an application server to a DR site. Site Recovery can also help with replicating central-services cluster VMs to the DR site. When you invoke DR, you'll need to reconfigure the Linux Pacemaker cluster on the DR site (for example, replace the VIP or SBD, run corosync.conf, and more).", - "training": "https://learn.microsoft.com/training/paths/ensure-business-continuity-implement-disaster-recovery/", - "waf": "Reliability" + "severity": "Medium", + "text": "Add diagnostic settings to save logs, using the Resource Specific destination table, for all Azure Firewall deployments.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Operations" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "8300cb30-766b-4084-b126-0dd8fb1269a1", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-business-continuity-and-disaster-recovery", - "service": "SAP", + "guid": "e960fc6b-4ab2-4db6-9609-3745135f9ffa", + "link": "https://learn.microsoft.com/azure/firewall-manager/migrate-to-policy", + "service": "Firewall", "services": [ - "WAF", - "SAP" + "Firewall", + "AzurePolicy", + "WAF" ], "severity": "High", - "text": "Consider the availability of SAP software against single points of failure. This includes single points of failure within applications such as DBMSs utilized in SAP NetWeaver and SAP S/4HANA architectures, SAP ABAP and ASCS + SCS. Also, other tools such as SAP Web Dispatcher.", - "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/2-explore-high-availability-disaster-recovery-support-azure-for-sap-workloads?source=recommendations", - "waf": "Reliability" + "text": "Migrate from Azure Firewall Classic rules (if exist) to Firewall Policy.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", + "waf": "Operations" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "56402f11-ccbe-42c3-a2f6-c6f6f38ab579", - "link": "https://learn.microsoft.com/azure/sap/workloads/planning-supported-configurations", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant", + "guid": "22d6419e-b627-4d95-9e7d-019fa759387f", + "link": "https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size", + "service": "Firewall", "services": [ - "WAF", - "SAP" + "VNet", + "Firewall", + "WAF" ], "severity": "High", - "text": "For SAP and SAP databases, consider implementing automatic failover clusters. In Windows, Windows Server Failover Clustering supports failover. In Linux, Linux Pacemaker or third-party tools like SIOS Protection Suite and Veritas InfoScale support failover.", - "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", - "waf": "Reliability" + "text": "Use a /26 prefix for your Azure Firewall subnets.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-firewall/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "afae6bec-2671-49ae-bc69-140b8ec8d320", - "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", - "service": "SAP", + "guid": "828cec2e-af6c-40c2-8fa2-1b681ee63eb7", + "link": "https://learn.microsoft.com/azure/firewall-manager/rule-hierarchy", + "service": "Firewall", "services": [ - "VM", - "Storage", + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Azure doesn't support architectures in which the primary and secondary VMs share storage for DBMS data. For the DBMS layer, the common architecture pattern is to replicate databases at the same time and with different storage stacks than the ones that the primary and secondary VMs use.", - "training": "https://learn.microsoft.com/training/paths/ensure-business-continuity-implement-disaster-recovery/?source=recommendationshttps%3A%2F%2Flearn.microsoft.com%2Fja-jp%2Ftraining%2Fpaths%2Fensure-business-continuity-implement-disaster-recovery%2F%3Fsource%3Drecommendations", - "waf": "Reliability" + "severity": "Medium", + "text": "Arrange rules within the firewall policy into Rule Collection Groups and Rule Collections and based on their frequency of use.", + "training": "https://learn.microsoft.com/training/modules/intro-to-azure-firewall-manager/", + "waf": "Performance" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "ac614e95-6767-4bc3-b8a4-9953533da6ba", - "link": "https://learn.microsoft.com/azure/sap/workloads/dbms-guide-general", - "service": "SAP", + "guid": "0da83bb1-2f39-49af-b5c9-835fc455e3d1", + "link": "https://learn.microsoft.com/azure/firewall/ip-groups", + "service": "Firewall", "services": [ "Storage", - "WAF", - "SAP" + "WAF" ], - "severity": "High", - "text": "The DBMS data and transaction/redo log files are stored in Azure supported block storage or Azure NetApp Files. Azure Files or Azure Premium Files isn't supported as storage for DBMS data and/or redo log files with SAP workload.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-databases/2-explore-database-support-azure-for-sap-workloads", - "waf": "Reliability" + "severity": "Medium", + "text": "Use IP Groups or IP prefixes to reduce number of IP table rules.", + "waf": "Performance" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "1f737179-8e7f-4e1a-a30c-e5a649a3092b", - "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-wsfc-shared-disk", - "service": "SAP", + "guid": "c44c6f0e-1642-4a61-a17b-0922f835c93a", + "link": "https://learn.microsoft.com/azure/firewall/tutorial-firewall-dnat", + "service": "Firewall", "services": [ - "WAF", - "SAP" + "WAF" ], - "severity": "High", - "text": "You can use Azure shared disks in Windows for ASCS + SCS components and specific high-availability scenarios. Set up your failover clusters separately for SAP application layer components and the DBMS layer. Azure doesn't currently support high-availability architectures that combine SAP application layer components and the DBMS layer into one failover cluster.", - "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", - "waf": "Reliability" + "severity": "Medium", + "text": "Do not use wildcards as a source IP for DNATS, such as * or any, you should specify source IPs for incoming DNATs.", + "training": "https://learn.microsoft.com/training/modules/introduction-to-azure-virtual-networks/", + "waf": "Performance" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools =~ 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name =~ 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name =~ 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses))", - "guid": "a78b3d31-3170-44f2-b5d7-651a29f4ccf5", - "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-standard-load-balancer-outbound-connections", - "service": "SAP", + "guid": "7371dc21-251a-47a3-af14-6e01b9da4757", + "link": "https://learn.microsoft.com/azure/firewall/integrate-with-nat-gateway", + "service": "Firewall", "services": [ - "LoadBalancer", - "WAF", - "SAP" + "Monitor", + "WAF" ], - "severity": "High", - "text": "Most failover clusters for SAP application layer components (ASCS) and the DBMS layer require a virtual IP address for a failover cluster. Azure Load Balancer should handle the virtual IP address for all other cases. One design principle is to use one load balancer per cluster configuration. We recommend that you use the standard version of the load balancer (Standard Load Balancer SKU).", - "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations", - "waf": "Reliability" + "severity": "Medium", + "text": "Prevent SNAT Port exhaustion by monitoring SNAT port usage, evaluating NAT Gateway settings, and ensuring seamless failover. If the port count approaches the limit, it’s a sign that SNAT exhaustion might be imminent.", + "training": "https://learn.microsoft.com/training/modules/introduction-to-azure-virtual-networks/", + "waf": "Performance" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", - "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-ha-ports-overview?source=recommendations", - "service": "SAP", + "guid": "346840b8-1064-496e-8396-4b1340172d52", + "link": "https://learn.microsoft.com/azure/firewall/premium-features#tls-inspection", + "service": "Firewall", "services": [ - "LoadBalancer", + "Firewall", "WAF" ], "severity": "High", - "text": "Make sure the Floating IP is enabled on the Load balancer", - "training": "https://learn.microsoft.com/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations", - "waf": "Reliability" + "text": "If you are using Azure Firewall Premium, enable TLS Inspection.", + "waf": "Performance" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "c47cc4f3-f105-452c-845e-9b307b3856c1", - "link": "https://learn.microsoft.com/azure/virtual-machines/availability", - "service": "SAP", + "guid": "39990a13-915c-45f9-a2d3-562d7d6c4b7c", + "link": "https://learn.microsoft.com/azure/firewall/premium-features#web-categories", + "service": "Firewall", "services": [ + "ServiceBus", "WAF" ], - "severity": "High", - "text": "Before you deploy your high-availability infrastructure, and depending on the region you choose, determine whether to deploy with an Azure availability set or an availability zone.", - "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations", - "waf": "Reliability" + "severity": "Low", + "text": "Use web categories to allow or deny outbound access to specific topics.", + "waf": "Performance" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "844f69c3-07e5-4ec1-bff7-4be27bcf5fea", - "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", - "service": "SAP", + "guid": "6eff7e6c-6c4a-43d7-be3f-6641c2cb3d4a", + "link": "https://learn.microsoft.com/azure/architecture/example-scenario/gateway/application-gateway-before-azure-firewall", + "service": "Firewall", "services": [ - "VM", - "WAF", - "SAP", - "Entra" + "WAF" ], - "severity": "High", - "text": "If you want to meet the infrastructure SLAs for your applications for SAP components (central services, application servers, and databases), you must choose the same high availability options (VMs, availability sets, availability zones) for all components.", - "waf": "Reliability" + "severity": "Medium", + "text": "As part of your TLS inspection, plan for receiving traffic from Azure App Gateways for inspection.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-application-gateway/", + "waf": "Performance" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "cbe05bbe-209d-4490-ba47-778424d11678", - "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", - "service": "SAP", + "graph": "resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant", + "guid": "94f3eede-9aa3-4088-92a3-bb9a56509fad", + "link": "https://learn.microsoft.com/azure/firewall/dns-details", + "service": "Firewall", "services": [ - "RBAC", - "VM", - "WAF", - "Entra" + "Firewall", + "DNS", + "WAF" ], - "severity": "High", - "text": "Do not mix servers of different roles in the same availability set. Keep central services VMs, database VMs, application VMs in their own availability sets", - "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations", - "waf": "Reliability" + "severity": "Medium", + "text": "Enable Azure Firewall DNS proxy configuration.", + "training": "https://learn.microsoft.com/training/courses/az-700t00/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "f2201000-d045-40a6-a79a-d7cdc01b4d86", - "link": "https://learn.microsoft.com/azure/virtual-machines/co-location", - "service": "SAP", + "guid": "1dc04554-dece-4ffb-a49e-5c683e09f8da", + "link": "https://learn.microsoft.com/azure/firewall/firewall-diagnostics", + "service": "Firewall", "services": [ + "Firewall", + "Monitor", "WAF" ], - "severity": "Medium", - "text": "You can't deploy Azure availability sets within an Azure availability zone unless you use proximity placement groups.", - "training": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", - "waf": "Reliability" + "severity": "High", + "text": "Integrate Azure Firewall with Azure Monitor and enable diagnostic logging to store and analyze firewall logs and metrics.", + "training": "https://learn.microsoft.com/training/courses/az-700t00/", + "waf": "Operations" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "9674e7c7-7796-4181-8920-09f4429543ba", - "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", - "service": "SAP", + "guid": "64e7000e-3c06-485e-b455-ced7f454cba3", + "link": "https://learn.microsoft.com/azure/well-architected/service-guides/azure-firewall", + "service": "Firewall", "services": [ - "VM", + "Backup", "WAF" ], - "severity": "High", - "text": "When you create availability sets, use the maximum number of fault domains and update domains available. For example, if you deploy more than two VMs in one availability set, use the maximum number of fault domains (three) and enough update domains to limit the effect of potential physical hardware failures, network outages, or power interruptions, in addition to Azure planned maintenance. The default number of fault domains is two, and you can't change it online later.", - "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations", - "waf": "Reliability" + "severity": "Low", + "text": "Implement backups for your firewall rules", + "training": "https://learn.microsoft.com/training/courses/az-104t00/", + "waf": "Operations" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "ae4ecb95-b70f-428f-8b9a-4c5b7e3478a2", - "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", - "service": "SAP", + "graph": "resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false'", + "guid": "d38ad60c-bc9e-4d49-b699-97e5d4dcf707", + "link": "https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell", + "service": "Firewall", "services": [ - "WAF", - "SAP", - "Entra" + "ACR", + "Firewall", + "WAF" ], "severity": "High", - "text": "When you use Azure proximity placement groups in an availability set deployment, all three SAP components (central services, application server, and database) should be in the same proximity placement group.", + "text": "Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance.", + "training": "https://learn.microsoft.com/training/courses/az-104t00/", "waf": "Reliability" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", - "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", - "service": "SAP", + "graph": "resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled'", + "guid": "e8143efa-0301-4d62-be54-ca7b5ce566dc", + "link": "https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview", + "service": "Firewall", "services": [ - "WAF", - "SAP", - "ACR" + "VNet", + "Firewall", + "DDoS", + "WAF" ], "severity": "High", - "text": "Use one proximity placement group per SAP SID. Groups don't span across Availability Zones or Azure regions", + "text": "Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. ", "waf": "Reliability" }, { + "arm-service": "microsoft.network/applicationGateways", "checklist": "WAF checklist", - "guid": "bca3b10e-0ff5-4aec-ac16-4c4bd1a1c13f", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-business-continuity-and-disaster-recovery", - "service": "SAP", + "guid": "d301d6e8-72e5-42e3-911c-c58b5a4b1511", + "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", + "service": "App Gateway", "services": [ - "WAF", - "SAP", - "Entra" + "VNet", + "WAF" ], "severity": "High", - "text": "Use one of the following services to run SAP central services clusters, depending on the operating system.", - "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", - "waf": "Reliability" + "text": "Do not disrupt control-plane communication for Azure PaaS services injected into a virtual networks, such as with a 0.0.0.0/0 route or an NSG rule that blocks control plane traffic.", + "training": "https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn", + "waf": "Security" }, { + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "ed46b937-913e-4018-9c62-8393ab037e53", - "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-suse-multi-sid", - "service": "SAP", + "guid": "b3e4563a-4d87-4397-98b6-62d6d15f512a", + "link": "https://learn.microsoft.com/azure/private-link/private-endpoint-overview", + "service": "ExpressRoute", "services": [ - "VM", - "WAF", - "Entra" + "PrivateLink", + "ExpressRoute", + "WAF" ], "severity": "Medium", - "text": "Azure doesn't currently support combining ASCS and DB HA in the same Linux Pacemaker cluster; separate them into individual clusters. However, you can combine up to five multiple central-services clusters into a pair of VMs.", - "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", - "waf": "Reliability" + "text": "Access Azure PaaS services from on-premises via private endpoints and ExpressRoute private peering. This method avoids transiting over the public internet.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/virtualNetworks", "checklist": "WAF checklist", - "graph": "Resources | where type =~ 'Microsoft.Storage/storageAccounts' | where sku.name in~ ('Standard_LRS', 'Premium_LRS') | project name, id, tags, param1 = strcat('sku: ', sku.name)", - "guid": "f656e745-0cfb-453e-8008-0528fa21c933", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-business-continuity-and-disaster-recovery", - "service": "SAP", + "graph": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc", + "guid": "4704489a-8042-4d88-b79d-17b73b22a5a6", + "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview", + "service": "VNet", "services": [ - "VM", - "Storage", + "VNet", "WAF" ], - "severity": "Medium", - "text": "Deploy both VMs in the high-availability pair in an availability set or in availability zones. These VMs should be the same size and have the same storage configuration.", - "waf": "Reliability" + "severity": "High", + "text": "Don't enable virtual network service endpoints by default on all subnets.", + "training": "https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/azureFirewalls", "checklist": "WAF checklist", - "guid": "7f684ebc-95da-425e-b329-e782dbed050f", - "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel-with-hana-ascs-ers-dialog-instance", - "service": "SAP", + "guid": "7e7a8ed4-b30e-438c-9f29-812b2363cefe", + "link": "azure/private-link/inspect-traffic-with-azure-firewall", + "service": "Firewall", "services": [ + "NVA", + "Firewall", "WAF", - "SAP" + "PrivateLink", + "DNS" ], "severity": "Medium", - "text": "Azure supports installing and configuring SAP HANA and ASCS/SCS and ERS instances on the same high availability cluster running on Red Hat Enterprise Linux (RHEL).", - "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", - "waf": "Reliability" + "text": "Filter egress traffic to Azure PaaS services using FQDNs instead of IP addresses in Azure Firewall or an NVA to prevent data exfiltration. If using Private Link you can block all FQDNs, otherwise allow only the required PaaS services.", + "training": "https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn", + "waf": "Security" }, { + "arm-service": "microsoft.network/expressRouteCircuits", "checklist": "WAF checklist", - "guid": "07991f7d-6598-4d90-9431-45c62605d3a5", - "link": "https://learn.microsoft.com/azure/sap/workloads/planning-guide-storage", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant", + "guid": "f2aad7e3-bb03-4adc-8606-4123d342a917", + "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway", + "service": "ExpressRoute", "services": [ - "Storage", + "VNet", + "ExpressRoute", + "VPN", "WAF" ], "severity": "High", - "text": "Run all production systems on Premium managed SSDs and use Azure NetApp Files or Ultra Disk Storage. At least the OS disk should be on the Premium tier so you can achieve better performance and the best SLA.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-storage/?source=recommendations", - "waf": "Reliability" + "text": "Use at least a /27 prefix for your Gateway subnets.", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/networkSecurityGroups", "checklist": "WAF checklist", - "guid": "73cdaecc-7d74-48d8-a040-88416eebc98c", - "link": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-operations-storage", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)", + "guid": "11deb39d-8299-4e47-bbe0-0fb5a36318a8", + "link": "https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags", + "service": "NSG", "services": [ - "Storage", - "WAF", - "SAP" + "VNet", + "WAF" ], "severity": "High", - "text": "You should run SAP HANA on Azure only on the types of storage that are certified by SAP. Note that certain volumes must be run on certain disk configurations, where applicable. These configurations include enabling Write Accelerator and using Premium storage. You also need to ensure that the file system that runs on storage is compatible with the DBMS that runs on the machine.", - "training": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-premium-ssd-v1?source=recommendations", - "waf": "Reliability" + "text": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity.", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/networkSecurityGroups", "checklist": "WAF checklist", - "guid": "51904867-a70e-4fa0-b4ff-3e6292846d7c", - "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-overview-guide#storage", - "service": "SAP", + "graph": "resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant", + "guid": "872e52e3-611c-4c58-a5a4-b1511e43a58a", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation", + "service": "NSG", "services": [ - "Storage", - "ASR", - "WAF", - "SAP" + "ACR", + "VNet", + "WAF" ], - "severity": "High", - "text": "Consider configuring high availability depending on the type of storage you use for your SAP workloads. Some storage services available in Azure are not supported by Azure Site Recovery, so your high availability configuration may differ.", - "training": "https://learn.microsoft.com/training/modules/implement-disaster-recovery-for-sap-workloads-azure/2-explore-disaster-recovery-sap-workloads", - "waf": "Reliability" + "severity": "Medium", + "text": "Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones).", + "training": "https://learn.microsoft.com/learn/paths/implement-network-security/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/networkSecurityGroups", "checklist": "WAF checklist", - "guid": "1ac2d928-c9b7-42c6-ba18-23b1aea78693", - "link": "https://azure.microsoft.com/ja-jp/explore/global-infrastructure/products-by-region/", - "service": "SAP", + "guid": "a4d87397-48b6-462d-9d15-f512a65498f6", + "link": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", + "service": "NSG", "services": [ - "Storage", - "WAF", - "SAP" + "NVA", + "VNet", + "Entra", + "WAF" ], - "severity": "High", - "text": "Different native Azure storage services (like Azure Files, Azure NetApp Files, Azure Shared Disk) may not be available in all regions. So to have similar SAP setup on the DR region after failover, ensure the respective storage service is offered in DR site.", - "waf": "Reliability" + "severity": "Medium", + "text": "Use NSGs and application security groups to micro-segment traffic within the landing zone and avoid using a central NVA to filter traffic flows.", + "training": "https://learn.microsoft.com/learn/paths/implement-network-security/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/networkSecurityGroups", "checklist": "WAF checklist", - "guid": "925d1f8c-01f3-4a67-948e-aabf0a1fad60", - "link": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/optimize-your-azure-costs-by-automating-sap-system-start-stop/ba-p/2120675", - "service": "SAP", + "graph": "resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant", + "guid": "dfe237de-143b-416c-91d7-aa9b64704489", + "link": "https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview", + "service": "NSG", "services": [ - "SAP", - "WAF", - "Cost" + "VNet", + "NetworkWatcher", + "WAF" ], "severity": "Medium", - "text": "Automate SAP System Start-Stop to manage costs.", - "waf": "Cost" + "text": "Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows.", + "training": "https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/", + "waf": "Security" }, { + "arm-service": "Microsoft.Network/networkSecurityGroups", "checklist": "WAF checklist", - "guid": "71dc00cd-4392-4262-8949-20c05e6c0333", - "link": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-premium-ssd-v1", - "service": "SAP", + "graph": "resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900)", + "guid": "0390417d-53dc-44d9-b3f4-c8832f359b41", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits", + "service": "NSG", "services": [ - "VM", - "Cost", - "Storage", - "WAF", - "SAP" + "VNet", + "WAF" ], - "severity": "Low", - "text": "In the case of using Azure Premium Storage with SAP HANA, Azure Standard SSD storage can be used to select a cost-conscious storage solution. However, please note that choosing Standard SSD or Standard HDD Azure storage will affect the SLA of the individual VMs. Also, for systems with lower I/O throughput and low latency, such as non-production environments, lower series VMs can be used.", - "waf": "Cost" + "severity": "Medium", + "text": "Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules.", + "training": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", + "waf": "Reliability" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "guid": "9877f353-2591-4e8b-8381-e9043fed1010", - "link": "https://learn.microsoft.com/azure/sap/workloads/hana-vm-premium-ssd-v1", - "service": "SAP", + "guid": "412e7f98-3f63-4047-82dd-69c5b5c2622f", + "link": "https://learn.microsoft.com/azure/virtual-wan/scenario-any-to-any", + "service": "VWAN", "services": [ - "VM", - "Cost", - "Storage", - "WAF", - "SAP" + "VWAN", + "WAF" ], - "severity": "Low", - "text": "As a lower-cost alternative configuration (multipurpose), you can choose a low-performance SKU for your non-production HANA database server VMs. However, it is important to note that some VM types, such as E-series, are not HANA certified (SAP HANA Hardware Directory) or cannot achieve storage latency of less than 1ms.", - "waf": "Cost" + "severity": "Medium", + "text": "Use Virtual WAN if your scenario is explicitly described in the list of Virtual WAN routing designs.", + "training": "https://learn.microsoft.com/learn/modules/introduction-azure-virtual-wan/", + "waf": "Operations" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "graph": "resources | where type =~ 'microsoft.aad/domainservices' | extend replicaSets = properties.replicaSets | where array_length(replicaSets) < 2 | project name=name, id=id, tags=tags, param1=strcat('replicaSetLocation:', replicaSets[0].location)", - "guid": "fda1dbf3-dc95-4d48-a7c7-91dca0f6c565", - "link": "https://learn.microsoft.com/azure/well-architected/sap/design-areas/security", - "service": "SAP", + "guid": "54b69bad-33aa-4d5e-ac68-e1d76667313b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/virtual-wan-network-topology#virtual-wan-network-design-recommendationst", + "service": "VWAN", "services": [ - "RBAC", - "Subscriptions", + "ACR", + "VWAN", "WAF" ], - "severity": "High", - "text": "Enforce a RBAC model for management groups, subscriptions, resource groups and resources", - "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/", - "waf": "Security" + "severity": "Medium", + "text": "Use a Virtual WAN hub per Azure region to connect multiple landing zones together across Azure regions via a common global Azure Virtual WAN.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "waf": "Performance" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "guid": "45911475-e39e-4530-accc-d979366bcda2", - "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/scenario-azure-first-sap-identity-integration", - "service": "SAP", + "graph": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant", + "guid": "7d5d1e4e-6146-458d-9558-fd77249b8211", + "link": "https://learn.microsoft.com/azure/virtual-wan/howto-firewall", + "service": "VWAN", "services": [ - "WAF", - "SAP", - "Entra" + "Firewall", + "WAF" ], "severity": "Medium", - "text": "Enforce Principal propagation for forwarding the identity from SAP cloud application to SAP on-premises (Including IaaS) through cloud connector", - "training": "https://learn.microsoft.com/training/modules/explore-identity-services/2-explore-azure-virtual-machine-auth-access-control", + "text": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs.", + "training": "https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/", "waf": "Security" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "guid": "750ab1ab-039d-495d-94c7-c8929cb107d5", - "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/scenario-azure-first-sap-identity-integration", - "service": "SAP", + "guid": "6667313b-4f56-464b-9e98-4a859c773e7d", + "link": "https://learn.microsoft.com/azure/virtual-wan/migrate-from-hub-spoke-topology", + "service": "VWAN", "services": [ - "WAF", - "SAP", - "Entra" + "VWAN", + "WAF" ], "severity": "Medium", - "text": "Implement SSO to SAP SaaS applications like SAP Analytics Cloud, SAP Cloud Platform, Business by design, SAP Qualtrics and SAP C4C with Azure AD using SAML.", - "waf": "Security" + "text": "Ensure that your virtual WAN network architecture aligns to an identified architecture scenario.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "waf": "Reliability" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "guid": "325ae525-ba34-4d46-a5e2-213ace7bb122", - "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial", - "service": "SAP", + "guid": "261623a7-65a9-417e-8f34-8ef254c27d42", + "link": "https://learn.microsoft.com/azure/virtual-wan/azure-monitor-insights", + "service": "VWAN", "services": [ - "WAF", - "SAP" + "VWAN", + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Implement SSO to SAP NetWeaver-based web applications like SAP Fiori and SAP Web GUI by using SAML.", - "training": "https://learn.microsoft.com/training/modules/explore-identity-services/8-exercise-integrate-azure-active-directory-sap-netweaver", - "waf": "Security" + "text": "Use Azure Monitor Insights for Virtual WAN to monitor the end-to-end topology of the Virtual WAN, status, and key metrics.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "waf": "Operations" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "guid": "9eb54dad-7861-4e1c-973a-f3bb003fc9c1", - "service": "SAP", + "graph": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant", + "guid": "727c77e1-b9aa-4a37-a024-129d042422c1", + "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan", + "service": "VWAN", "services": [ - "WAF", - "SAP" + "VWAN", + "WAF" ], "severity": "Medium", - "text": "Implement SSO to SAP NetWeaver-based web applications like SAP Fiori and SAP Web GUI by using SAML.", - "training": "https://learn.microsoft.com/training/modules/explore-identity-services/6-exercise-integrate-azure-active-directory-sap-fiori", - "waf": "Security" + "text": "Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "waf": "Reliability" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "guid": "f29676ef-0c9c-4c4d-ab21-a55504c0c829", - "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial", - "service": "SAP", + "graph": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant", + "guid": "d49ac006-6670-4bc9-9948-d3e0a3a94f4d", + "link": "https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference", + "service": "VWAN", "services": [ - "WAF", - "SAP" + "ExpressRoute", + "VPN", + "WAF" ], "severity": "Medium", - "text": "You can implement SSO to SAP GUI by using SAP NetWeaver SSO or a partner solution.", - "training": "https://learn.microsoft.com/training/modules/explore-identity-services/8-exercise-integrate-azure-active-directory-sap-netweaver", - "waf": "Security" + "text": "Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "waf": "Reliability" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "guid": "23181aa4-1742-4694-9ff8-ae7d7d474317", - "service": "SAP", + "guid": "2586b854-237e-47f1-84a1-d45d4cd2310d", + "link": "https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing#labels", + "service": "VWAN", "services": [ - "AKV", - "WAF", - "SAP" + "VWAN", + "WAF" ], "severity": "Medium", - "text": "For SSO for SAP GUI and web browser access, implement SNC / Kerberos/SPNEGO (simple and protected GSSAPI negotiation mechanism) due to its ease of configuration and maintenance. For SSO with X.509 client certificates, consider the SAP Secure Login Server, which is a component of the SAP SSO solution.", - "training": "https://learn.microsoft.com/training/modules/explore-identity-services/9-exercise-integrate-active-directory-sap-single-sign-on", - "waf": "Security" + "text": "Configure label-based propagation in Virtual WAN, otherwise connectivity between virtual hubs will be impaired.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "waf": "Reliability" }, { + "arm-service": "microsoft.network/virtualWans", "checklist": "WAF checklist", - "guid": "6c8bcbf4-5bbe-4609-b8a0-3e97778424d6", - "link": "https://blogs.sap.com/2017/07/12/sap-single-sign-on-protect-your-sap-landscape-with-x.509-certificates/", - "service": "SAP", + "graph": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant", + "guid": "9c75dfef-573c-461c-a698-68598595581a", + "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation", + "service": "VWAN", "services": [ - "AKV", - "WAF", - "SAP" + "WAF" ], - "severity": "Medium", - "text": "For SSO for SAP GUI and web browser access, implement SNC / Kerberos/SPNEGO (simple and protected GSSAPI negotiation mechanism) due to its ease of configuration and maintenance. For SSO with X.509 client certificates, consider the SAP Secure Login Server, which is a component of the SAP SSO solution.", - "waf": "Security" + "severity": "High", + "text": "Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available.", + "training": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "16785d6f-a96c-496a-b885-18f482734c88", - "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial#configure-sap-netweaver-for-oauth", - "service": "SAP", + "guid": "5c986cb2-9131-456a-8247-6e49f541acdc", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "service": "Policy", "services": [ - "WAF", - "SAP" + "AzurePolicy", + "WAF" ], - "severity": "Medium", - "text": "Implement SSO by using OAuth for SAP NetWeaver to allow third-party or custom applications to access SAP NetWeaver OData services.", + "severity": "High", + "text": "Leverage Azure Policy strategically, define controls for your environment, using Policy Initiatives to group related policies.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "a747c350-8d4c-449c-93af-393dbca77c48", - "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/saphana-tutorial", - "service": "SAP", + "guid": "d8a2adb1-17d6-4326-af62-5ca44e5695f2", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "service": "Policy", "services": [ - "WAF", - "SAP" + "RBAC", + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Implement SSO to SAP HANA", + "text": "Map regulatory and compliance requirements to Azure Policy definitions and Azure role assignments.", + "training": "https://learn.microsoft.com/training/modules/governance-security/", "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "c7bae5bf-daf9-4761-9c56-f92891890aa4", - "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration#connectivity-with-sap-rise", - "service": "SAP", + "guid": "223ace8c-b123-408c-a501-7f154e3ab369", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "service": "Policy", "services": [ - "WAF", - "SAP", - "Entra" + "Subscriptions", + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Consider Azure AD an identity provider for SAP systems hosted on RISE. For more information, see Integrating the Service with Azure AD.", + "text": "Establish Azure Policy definitions at the intermediate root management group so that they can be assigned at inherited scopes.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "e4e48226-ce54-44b6-bb6b-bfa15bd8f753", - "link": "https://github.com/azuredevcollege/SAP/blob/master/sap-oauth-saml-flow/README.md", - "service": "SAP", + "guid": "3829e7e3-1618-4368-9a04-77a209945bda", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "service": "Policy", "services": [ - "WAF", - "SAP" + "AzurePolicy", + "WAF" ], - "severity": "Medium", - "text": "For applications that access SAP, you might want to use principal propagation to establish SSO.", + "severity": "High", + "text": "Manage policy assignments at the highest appropriate level with exclusions at bottom levels, if required.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "59921095-4980-4fc1-a5b6-524a5a560c79", - "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-hana-cloud-platform-identity-authentication-tutorial", - "service": "SAP", + "guid": "43334f24-9116-4341-a2ba-527526944008", + "link": "https://learn.microsoft.com/security/benchmark/azure/mcsb-asset-management#am-2-use-only-approved-services", + "service": "Policy", "services": [ - "WAF", - "SAP", - "Entra" + "Subscriptions", + "AzurePolicy", + "WAF" ], - "severity": "Medium", - "text": "If you're using SAP BTP services or SaaS solutions that require SAP Identity Authentication Service (IAS), consider implementing SSO between SAP Cloud Identity Authentication Services and Azure AD to access those SAP services. This integration lets SAP IAS act as a proxy identity provider and forwards authentication requests to Azure AD as the central user store and identity provider.", + "severity": "Low", + "text": "Use Azure Policy to control which services users can provision at the subscription/management group level.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "a709c664-317e-41e4-9e34-67d9016a86f4", - "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-hana-cloud-platform-tutorial", - "service": "SAP", + "guid": "be7d7e48-4327-46d8-adc0-55bcf619e8a1", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "service": "Policy", "services": [ - "WAF", - "SAP" + "AzurePolicy", + "WAF" ], - "severity": "Medium", - "text": "Implement SSO to SAP BTP", + "severity": "High", + "text": "Use built-in policies where possible to minimize operational overhead.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "01f11b7f-38df-4251-9c76-4dec19abd3e8", - "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-successfactors-inbound-provisioning-cloud-only-tutorial", - "service": "SAP", + "description": "Assigning the Resource Policy Contributor role to specific scopes allows you to delegate policy management to relevant teams. For instance, a central IT team may oversee management group-level policies, while application teams handle policies for their subscriptions, enabling distributed governance with adherence to organizational standards.", + "guid": "3f988795-25d6-4268-a6d7-0ba6c97be995", + "link": "https://learn.microsoft.com/azure/governance/policy/overview#azure-rbac-permissions-in-azure-policy", + "service": "Policy", "services": [ + "AzurePolicy", "WAF", - "SAP", + "RBAC", + "Subscriptions", "Entra" ], "severity": "Medium", - "text": "If you're using SAP SuccessFactors, consider using the Azure AD automated user provisioning. With this integration, as you add new employees to SAP SuccessFactors, you can automatically create their user accounts in Azure AD. Optionally, you can create user accounts in Microsoft 365 or other SaaS applications that are supported by Azure AD. Use write-back of the email address to SAP SuccessFactors.", + "text": "Assign the built-in Resource Policy Contributor role at a particular scope to enable application-level governance.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "description": "Keep your management group hierarchy reasonably flat, no more than four.", - "graph": "resourcecontainers| where type =~ 'microsoft.resources/subscriptions'| extend ManagementGroup = tostring(tags),mgmtChain = properties.managementGroupAncestorsChain| extend compliant =( array_length(mgmtChain) <= 4 and array_length(mgmtChain) > 1)", - "guid": "6ba28021-4591-4147-9e39-e5309cccd979", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups", - "service": "SAP", + "guid": "19048384-5c98-46cb-8913-156a12476e49", + "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "service": "Policy", "services": [ - "AzurePolicy", "Subscriptions", - "WAF", - "SAP" + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "enforce existing Management Group policies to SAP Subscriptions", - "training": "https://learn.microsoft.com/training/modules/enterprise-scale-organization/4-management-group-subscription-organization", - "waf": "Operations" + "text": "Limit the number of Azure Policy assignments made at the root management group scope to avoid managing through exclusions at inherited scopes.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-policy/", + "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "graph": "Resources | summarize count()", - "guid": "366bcda2-750a-4b1a-a039-d95d54c7c892", - "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", - "service": "SAP", + "guid": "5a917e1f-348e-4f25-9c27-d42e8bbac757", + "link": "https://learn.microsoft.com/industry/release-plan/2023wave2/cloud-sovereignty/enable-data-sovereignty-policy-baseline", + "service": "Policy", "services": [ - "Subscriptions", - "WAF", - "SAP" - ], - "severity": "High", - "text": "Integrate tightly coupled applications into the same SAP subscription to avoid additional routing and management complexity", - "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-subscriptions", - "waf": "Operations" + "AzurePolicy", + "WAF" + ], + "severity": "Medium", + "text": "If any data sovereignty requirements exist, Azure Policies should be deployed to enforce them.", + "training": "https://learn.microsoft.com/learn/paths/secure-your-cloud-data/", + "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "graph": "Resources | where type contains 'publicIPAddresses' and isnotempty(properties.ipAddress) | summarize count () by subscriptionId", - "guid": "9cb107d5-325a-4e52-9ba3-4d4685e2213a", - "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", - "service": "SAP", + "guid": "78b22132-b41c-460b-a4d3-df8f73a67dc2", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/sovereign-landing-zone", + "service": "Policy", "services": [ "Subscriptions", + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Leverage Subscription as scale unit and scaling our resources, consider deploying subscription per environment eg. Sandbox, non-prod, prod ", - "training": "https://learn.microsoft.com/training/modules/configure-subscriptions/?source=recommendations", - "waf": "Operations" + "severity": "Medium", + "text": "For Sovereign Landing Zone, deploy sovereignty policy baseline and assign at correct management group level.", + "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "graph": "QuotaResources | where type =~ 'microsoft.compute/locations/usages' | where subscriptionId in~ ('','') | mv-expand json = properties.value limit 400 | extend usagevCPUs = json.currentValue, QuotaLimit = json['limit'], quotaName = tostring(json['name'].localizedValue) | extend usagePercent = toint(usagevCPUs)*100 / toint(QuotaLimit) |where quotaName =~ 'Total Regional vCPUs' or quotaName =~ 'Total Regional Low-priority vCPUs' |project subscriptionId,quotaName,usagevCPUs,QuotaLimit,usagePercent,location,['json'] | order by ['usagePercent'] desc", - "guid": "ce7bb122-f7c9-45f0-9e15-4e3aa3592829", - "link": "https://learn.microsoft.com/azure/quotas/quotas-overview", - "service": "SAP", + "guid": "caeea0e9-1024-41df-a52e-d99c3f22a6f4", + "link": "https://learn.microsoft.com/industry/sovereignty/policy-portfolio-baseline", + "service": "Policy", "services": [ - "VM", - "Subscriptions", + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Ensure quota increase as a part of subscription provisioning (e.g. total available VM cores within a subscription)", - "training": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits", - "waf": "Operations" + "severity": "Medium", + "text": "For Sovereign Landing Zone, document Sovereign Control objectives to policy mapping.", + "waf": "Security" }, { + "arm-service": "Microsoft.Authorization/policyDefinitions", "checklist": "WAF checklist", - "guid": "ce4fab2f-433a-4d59-a5a9-3d1032e03ebc", - "link": "https://learn.microsoft.com/rest/api/reserved-vm-instances/quotaapi?branch=capacity", - "service": "SAP", + "guid": "9b461617-db7b-4399-8ac6-d4eb7153893a", + "link": "https://learn.microsoft.com/industry/sovereignty/policy-portfolio-baseline#sovereignty-baseline-policy-initiatives", + "service": "Policy", "services": [ + "AzurePolicy", "WAF" ], - "severity": "Low", - "text": "The Quota API is a REST API that you can use to view and manage quotas for Azure services. Consider using it if necessary.", - "waf": "Operations" + "severity": "Medium", + "text": "For Sovereign Landing Zone, ensure process is in place for management of 'Sovereign Control objectives to policy mapping'.", + "waf": "Security" }, { + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "guid": "cbfad17b-f240-42bf-a1d8-f4f4cee661c8", - "link": "https://learn.microsoft.com/azure/quotas/quickstart-increase-quota-portal", - "service": "SAP", + "guid": "67e7a8ed-4b30-4e38-a3f2-9812b2363cef", + "link": "https://learn.microsoft.com/en-us/azure/azure-monitor/logs/workspace-design#azure-regions", + "service": "Monitor", "services": [ - "VM", - "Subscriptions", - "WAF" + "AzurePolicy", + "Monitor", + "RBAC", + "WAF", + "Entra" ], - "severity": "High", - "text": "If deploying to an availability zone, ensure that the VM's zone deployment is available once the quota has been approved. Submit a support request with the subscription, VM series, number of CPUs and availability zone required.", + "severity": "Medium", + "text": "Use a single monitor logs workspace to manage platforms centrally except where Azure role-based access control (Azure RBAC), data sovereignty requirements, or data retention policies mandate separate workspaces.", + "training": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "waf": "Operations" }, { + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "guid": "e6e20617-3686-4af4-9791-f8935ada4332", - "link": "https://azure.microsoft.com/explore/global-infrastructure/products-by-region/", - "service": "SAP", + "guid": "7418ada9-4199-4c28-8286-d15e9433e8f3", + "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", + "service": "Monitor", "services": [ + "Monitor", "WAF" ], - "severity": "High", - "text": "Ensure required services and features are available within the chosen deployment regions eg. ANF , Zone etc.", - "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/migrate/azure-best-practices/multiple-regions?source=recommendations", - "waf": "Operations" + "severity": "Medium", + "text": "Decide whether to use a single Azure Monitor Logs workspace for all regions or to create multiple workspaces to cover various geographical regions. Each approach has advantages and disadvantages, including potential cross-region networking charges", + "training": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "graph": "resources | extend compliant = isnotnull(['tags']) | project name, id, subscriptionId, resourceGroup, tags, compliant", - "guid": "4e138115-2318-41aa-9174-26943ff8ae7d", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-resource-organization", - "service": "SAP", + "guid": "5e6c4cfd-3e50-4454-9c24-47ec66138a72", + "link": "https://learn.microsoft.com/azure/azure-monitor/logs/data-retention-archive?tabs=portal-1%2Cportal-2#how-retention-and-archiving-work", + "service": "Monitor", "services": [ - "TrafficManager", - "WAF", - "Cost" + "Storage", + "ARS", + "AzurePolicy", + "WAF" ], - "severity": "Medium", - "text": "Leverage Azure resource tag for cost categorization and resource grouping (: BillTo, Department (or Business Unit), Environment (Production, Stage, Development), Tier (Web Tier, Application Tier), Application Owner, ProjectName)", - "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/", + "severity": "High", + "text": "Export logs to Azure Storage if your log retention requirements exceed twelve years. Use immutable storage with a write-once, read-many policy to make data non-erasable and non-modifiable for a user-specified interval.", + "training": "https://learn.microsoft.com/learn/paths/architect-infrastructure-operations/", "waf": "Operations" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "2f7c95f0-6e15-44e3-aa35-92829e6e2061", - "link": "https://learn.microsoft.com/azure/backup/sap-hana-database-about", - "service": "SAP", + "guid": "e7d7e484-3276-4d8b-bc05-5bcf619e8a13", + "link": "https://learn.microsoft.com/azure/governance/machine-configuration/overview", + "service": "VM", "services": [ - "WAF", - "Backup" + "VM", + "Monitor", + "AzurePolicy", + "WAF" ], - "severity": "High", - "text": "Help protect your HANA database by using the Azure Backup service.", - "training": "https://learn.microsoft.com/training/modules/implement-azure-backup-sap-workloads-azure-virtual-machines/?source=recommendations", - "waf": "Reliability" + "severity": "Medium", + "text": "Monitor OS level virtual machine (VM) configuration drift using Azure Policy. Enabling Azure Automanage Machine Configuration audit capabilities through policy helps application team workloads to immediately consume feature capabilities with little effort.", + "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", + "waf": "Operations" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "302a2fbf-3745-4a5f-a365-c9d1a16ca22c", - "link": "https://learn.microsoft.com/azure/azure-netapp-files/azacsnap-introduction", - "service": "SAP", + "guid": "f9887952-5d62-4688-9d70-ba6c97be9951", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#update-management-considerations", + "service": "VM", "services": [ "VM", - "Storage", - "WAF", - "Entra" + "WAF" ], "severity": "Medium", - "text": "If you deploy Azure NetApp Files for your HANA, Oracle, or DB2 database, use the Azure Application Consistent Snapshot tool (AzAcSnap) to take application-consistent snapshots. AzAcSnap also supports Oracle databases. Consider using AzAcSnap on a central VM rather than on individual VMs.", - "waf": "Reliability" + "text": "Use Azure Update Manager as a patching mechanism for Windows and Linux VMs in Azure.", + "training": "https://learn.microsoft.com/azure/update-manager/overview?tabs=azure-vms", + "waf": "Operations" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "42d37218-a3a7-45df-bff6-1173e7f249ea", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-management-and-monitoring", - "service": "SAP", + "guid": "c806c048-26b7-4ddf-b4c2-b4f0c476925d", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#update-management-considerations ", + "service": "VM", "services": [ - "WAF", - "SAP" + "VM", + "WAF" ], - "severity": "High", - "text": "Ensure time-zone matches between the operating system and the SAP system.", + "severity": "Medium", + "text": "Use Azure Update Manager as a patching mechanism for Windows and Linux VMs outside of Azure using Azure Arc.", + "training": "https://learn.microsoft.com/azure/update-manager/overview?tabs=azure-vms", "waf": "Operations" }, { + "arm-service": "microsoft.network/networkWatchers", "checklist": "WAF checklist", - "guid": "c3c7abc0-716c-4486-893c-40e181d65539", - "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel-multi-sid", - "service": "SAP", + "guid": "90483845-c986-4cb2-a131-56a12476e49f", + "link": "https://learn.microsoft.com/azure/network-watcher/network-watcher-monitoring-overview", + "service": "Network Watcher", "services": [ - "WAF", - "Entra" + "Monitor", + "NetworkWatcher", + "WAF" ], "severity": "Medium", - "text": "Don't group different application services in the same cluster. For example, don't combine DRBD and central services clusters on the same cluster. However, you can use the same Pacemaker cluster to manage approximately five different central services (multi-SID cluster).", - "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", - "waf": "Reliability" + "text": "Use Network Watcher to proactively monitor traffic flows.", + "training": "https://learn.microsoft.com/learn/modules/configure-network-watcher/", + "waf": "Operations" }, { + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "guid": "a491dfc4-9353-4213-9217-eef0949f9467", - "link": "https://azure.microsoft.com/pricing/offers/dev-test/", - "service": "SAP", + "guid": "6944008b-e7d7-4e48-9327-6d8bdc055bcf", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-setup-guide/monitoring-reporting?tabs=AzureMonitor", + "service": "Monitor", "services": [ - "WAF", - "Cost" + "Monitor", + "WAF" ], - "severity": "Low", - "text": "Consider running dev/test systems in a snooze model to save and optimize Azure run costs.", - "waf": "Cost" + "severity": "Medium", + "text": "Use Azure Monitor Logs for insights and reporting.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-monitor/", + "waf": "Operations" }, { + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "guid": "b7056168-6199-4732-a514-cdbb2d5c9c54", - "link": "https://learn.microsoft.com/azure/lighthouse/overview", - "service": "SAP", + "guid": "97be9951-9048-4384-9c98-6cb2913156a1", + "link": "https://learn.microsoft.com/azure/azure-monitor/alerts/alerts-overview", + "service": "Monitor", "services": [ - "WAF", - "SAP", - "Entra" + "Monitor", + "WAF" ], "severity": "Medium", - "text": "If you partner with customers by managing their SAP estates, consider Azure Lighthouse. Azure Lighthouse allows managed service providers to use Azure native identity services to authenticate to the customers' environment. It puts the control in the hands of customers, because they can revoke access at any time and audit service providers' actions.", + "text": "Use Azure Monitor alerts for the generation of operational alerts.", + "training": "https://learn.microsoft.com/training/modules/incident-response-with-alerting-on-azure/", "waf": "Operations" }, { + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "guid": "4d116785-d2fa-456c-96ad-48408fe72734", - "link": "https://learn.microsoft.com/azure/update-manager/scheduled-patching?tabs=schedule-updates-single-machine%2Cschedule-updates-scale-overview", - "service": "SAP", + "guid": "fed3c55f-a67e-4875-aadd-3aba3f9fde31", + "link": "https://learn.microsoft.com/azure/automation/how-to/region-mappings", + "service": "Monitor", "services": [ - "VM", + "Monitor", "WAF" ], "severity": "Medium", - "text": "Use Azure Update Manager to check the status of available updates for a single VM or multiple VMs and consider scheduling regular patching.", - "training": "https://learn.microsoft.com/training/modules/keep-your-virtual-machines-updated/?source=recommendations", + "text": "When using Change and Inventory Tracking via Azure Automation Accounts, ensure that you have selected supported regions for linking your Log Analytics workspace and automation accounts together.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-automation-devops/", "waf": "Operations" }, { + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "76c8bcbf-45bb-4e60-ad8a-03e97778424d", - "link": "https://learn.microsoft.com/azure/sap/workloads/lama-installation", - "service": "SAP", + "guid": "eba8cf22-45c6-4dc1-9b57-2cceb3b97ce5", + "link": "https://learn.microsoft.com/azure/storage/common/storage-redundancy", + "service": "Backup", "services": [ - "WAF", - "SAP" + "Backup", + "WAF" ], "severity": "Low", - "text": "Optimize and manage SAP Basis operations by using SAP Landscape Management (LaMa). Use the SAP LaMa connector for Azure to relocate, copy, clone, and refresh SAP systems.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-remote-management/?source=recommendations", - "waf": "Operations" + "text": "When using Azure Backup, use the correct backup types (GRS, ZRS & LRS) for your backup, as the default setting is GRS.", + "training": "https://learn.microsoft.com/training/modules/design-solution-for-backup-disaster-recovery/", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "14591147-5e39-4e53-89cc-cd979366bcda", - "link": "https://learn.microsoft.com/azure/sap/monitor/about-azure-monitor-sap-solutions", - "service": "SAP", + "guid": "f541acdc-e979-4377-acdb-3751ab2ab13a", + "link": "https://learn.microsoft.com/azure/governance/policy/concepts/guest-configuration", + "service": "VM", "services": [ - "SQL", - "WAF", - "SAP", - "Monitor" + "VM", + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Use Azure Monitor for SAP solutions to monitor your SAP workloads(SAP HANA, high-availability SUSE clusters, and SQL systems) on Azure. Consider supplementing Azure Monitor for SAP solutions with SAP Solution Manager.", - "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations", - "waf": "Operations" + "text": "Use Azure guest policies to automatically deploy software configurations through VM extensions and enforce a compliant baseline VM configuration.", + "waf": "Security" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "2750ab1a-b039-4d95-b54c-7c8929cb107d", - "link": "https://learn.microsoft.com/azure/sap/workloads/vm-extension-for-sap", - "service": "SAP", + "description": "Use Azure Policy's guest configuration features to audit and remediate machine settings (e.g., OS, application, environment) to ensure resources align with expected configurations, and Update Management can enforce patch management for VMs.", + "guid": "da6e55d7-d8a2-4adb-817d-6326af625ca4", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#monitoring-for-configuration-drift", + "service": "VM", "services": [ "VM", - "Entra", "Monitor", - "WAF", - "SAP" + "AzurePolicy", + "WAF" ], - "severity": "High", - "text": "Run a VM Extension for SAP check. VM Extension for SAP uses the assigned managed identity of a virtual machine (VM) to access VM monitoring and configuration data. The check ensures that all performance metrics in your SAP application come from the underlying Azure Extension for SAP.", - "training": "https://learn.microsoft.com/training/modules/configure-azure-enhanced-monitoring-extension-for-sap/?source=recommendations", - "waf": "Operations" + "severity": "Medium", + "text": "Monitor VM security configuration drift via Azure Policy.", + "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/", + "waf": "Security" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "5325ae52-5ba3-44d4-985e-2213ace7bb12", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", - "service": "SAP", + "guid": "2476e49f-541a-4cdc-b979-377bcdb3751a", + "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", + "service": "VM", "services": [ - "AzurePolicy", + "ACR", + "VM", + "ASR", "WAF" ], "severity": "Medium", - "text": "Use Azure Policy for access control and compliance reporting. Azure Policy provides the ability to enforce organization-wide settings to ensure consistent policy adherence and fast violation detection. ", - "training": "https://learn.microsoft.com/learn/paths/architect-infrastructure-operations/", + "text": "Use Azure Site Recovery for Azure-to-Azure Virtual Machines disaster recovery scenarios. This enables you to replicate workloads across regions.", + "training": "https://learn.microsoft.com/training/modules/protect-infrastructure-with-site-recovery/", "waf": "Operations" }, { + "arm-service": "Microsoft.RecoveryServices/vaults", "checklist": "WAF checklist", - "guid": "523181aa-4174-4269-93ff-8ae7d7d47431", - "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-overview", - "service": "SAP", + "guid": "f625ca44-e569-45f2-823a-ce8cb12308ca", + "link": "https://learn.microsoft.com/azure/backup/backup-center-overview", + "service": "Backup", "services": [ - "NetworkWatcher", - "WAF", - "SAP", - "Monitor" + "Backup", + "WAF" ], "severity": "Medium", - "text": "Use Connection Monitor in Azure Network Watcher to monitor latency metrics for SAP databases and application servers. Or collect and display network latency measurements by using Azure Monitor.", - "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/collecting-and-displaying-niping-network-latency-measurements/ba-p/1833979", + "text": "Use Azure-native backup capabilities, or an Azure-compatible, 3rd-party backup solution.", + "training": "https://learn.microsoft.com/training/modules/design-solution-for-backup-disaster-recovery/", "waf": "Operations" }, { + "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", "checklist": "WAF checklist", - "guid": "73686af4-6791-4f89-95ad-a43324e13811", - "link": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/QualityCheck", - "service": "SAP", + "guid": "89cc5e11-aa4d-4c3b-893d-feb99215266a", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#add-diagnostic-settings-to-save-your-wafs-logs", + "service": "WAF", "services": [ - "VM", - "WAF", - "SAP" + "AppGW", + "FrontDoor", + "WAF" ], - "severity": "Medium", - "text": "Perform a quality check for SAP HANA on the provisioned Azure infrastructure to verify that provisioned VMs comply with SAP HANA on Azure best practices.", + "severity": "High", + "text": "Add diagnostic settings to save WAF logs from application delivery services like Azure Front Door and Azure Application Gateway. Regularly review the logs to check for attacks and for false positive detections.", + "training": "https://learn.microsoft.com/training/modules/capture-application-logs-app-service/", "waf": "Operations" }, { + "arm-service": "microsoft.network/frontdoorwebApplicationFirewalls", "checklist": "WAF checklist", - "guid": "616785d6-fa96-4c96-ad88-518f482734c8", - "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-zones", - "service": "SAP", + "guid": "7f408960-c626-44cb-a018-347c8d790cdf", + "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", + "service": "WAF", "services": [ - "Subscriptions", - "WAF", - "SAP" + "Sentinel", + "AppGW", + "FrontDoor", + "WAF" ], - "severity": "High", - "text": "For each Azure subscription, run a latency test on Azure availability zones before zonal deployment to choose low-latency zones for deployment of SAP on Azure.", - "training": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/AvZone-Latency-Test", - "waf": "Performance" + "severity": "Medium", + "text": "Send WAF logs from your application delivery services like Azure Front Door and Azure Application Gateway to Microsoft Sentinel. Detect attacks and integrate WAF telemetry into your overall Azure environment.", + "training": "https://learn.microsoft.com/training/paths/sc-200-connect-logs-to-azure-sentinel/", + "waf": "Operations" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "410adcba-db46-424f-a6c4-05ecde75c52e", - "link": "https://learn.microsoft.com/azure/advisor/advisor-how-to-improve-reliability", - "service": "SAP", + "guid": "5017f154-e3ab-4369-9829-e7e316183687", + "link": "https://learn.microsoft.com/azure/key-vault/general/overview", + "service": "Key Vault", "services": [ - "Storage", - "ASR", + "AKV", "WAF" ], - "severity": "Medium", - "text": "Run the Resiliency Report to ensure that the configuration of the entire provisioned Azure infrastructure (Compute, Database, Networking, Storage, Site Recovery) complies with the configuration defined by Cloud Adaption Framework for Azure.", - "training": "https://learn.microsoft.com/training/paths/azure-well-architected-framework/", - "waf": "Reliability" + "severity": "High", + "text": "Use Azure Key Vault to store your secrets and credentials.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-key-vault/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "86ba2802-1459-4114-95e3-9e5309cccd97", - "link": "https://learn.microsoft.com/azure/sentinel/sap/deployment-overview", - "service": "SAP", + "graph": "ResourceContainers | where type=='microsoft.resources/subscriptions'| parse id with '/subscriptions/' SubscriptionID| project subscriptionId, SubscriptionName = name| join kind=leftouter (Resources| where type == 'microsoft.keyvault/vaults'| project id, name, subscriptionId) on subscriptionId| join kind= leftouter (Resources| where type == 'microsoft.keyvault/vaults'| summarize ResourceCount = count() by subscriptionId) on subscriptionId| extend RCount = iff(isnull(ResourceCount), 0, ResourceCount)| project-away ResourceCount| extend compliant = (RCount <> 1)", + "guid": "a0477a20-9945-4bda-9333-4f2491163418", + "link": "https://learn.microsoft.com/azure/key-vault/general/overview-throttling", + "service": "Key Vault", "services": [ - "Sentinel", - "WAF", - "SAP", - "Monitor" + "AKV", + "WAF" ], "severity": "Medium", - "text": "Implement threat protection by using the Microsoft Sentinel solution for SAP. Use this solution to monitor your SAP systems and detect sophisticated threats throughout the business logic and application layers.", - "training": "https://learn.microsoft.com/training/modules/plan-microsoft-sentinel-deployment-sap/?source=recommendations", + "text": "Use different Azure Key Vaults for different applications and regions to avoid transaction scale limits and restrict access to secrets.", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/", "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "graph": "resources | extend compliant = isnotnull(['tags']) | project name, id, subscriptionId, resourceGroup, tags, compliant", - "guid": "579266bc-ca27-45fa-a1ab-fe9d55d04c3c", - "link": "https://learn.microsoft.com/azure/cost-management-billing/costs/enable-tag-inheritance", - "service": "SAP", + "guid": "2ba52752-6944-4008-ae7d-7e4843276d8b", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", "services": [ - "WAF", - "Cost" + "AKV", + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Azure tagging can be leveraged to logically group and track resources, automate their deployments, and most importantly, provide visibility on the incurred costs.", - "training": "https://learn.microsoft.com/training/modules/analyze-costs-create-budgets-azure-cost-management/?source=recommendations", - "waf": "Operations" + "text": "Provision Azure Key Vault with the soft delete and purge policies enabled to allow retention protection for deleted objects.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-key-vault/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "04b8e5e5-13cb-4b22-af62-5a8ecfcf0337", - "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-test-latency?tabs=windows", - "service": "SAP", + "guid": "dc055bcf-619e-48a1-9f98-879525d62688", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", "services": [ - "VM", - "WAF", - "Monitor" + "AKV", + "RBAC", + "Entra", + "WAF" ], - "severity": "Low", - "text": "Use inter-VM latency monitoring for latency-sensitive applications.", - "waf": "Performance" + "severity": "Medium", + "text": "Follow a least privilege model by limiting authorization to permanently delete keys, secrets, and certificates to specialized custom Microsoft Entra ID roles.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-key-vault/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "07e5ed53-3d96-43d8-87ea-631b77da5aba", - "link": "https://learn.microsoft.com/azure/sap/workloads/planning-guide-storage", - "service": "SAP", + "guid": "6d70ba6c-97be-4995-8904-83845c986cb2", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", "services": [ - "ASR", - "WAF", - "SAP", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Use Azure Site Recovery monitoring to maintain the health of the disaster recovery service for SAP application servers.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-storage/?source=recommendations", - "waf": "Reliability" + "text": "Automate the certificate management and renewal process with public certificate authorities to ease administration.", + "training": "https://learn.microsoft.com/en-us/training/modules/configure-and-manage-azure-key-vault/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "abb6af9c-982c-4cf1-83fb-329fafd1ee56", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-management-and-monitoring", - "service": "SAP", + "guid": "913156a1-2476-4e49-b541-acdce979377b", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", "services": [ - "Storage", - "WAF", - "SAP" + "WAF" ], "severity": "Medium", - "text": "Exclude all the database file systems and executable programs from antivirus scans. Including them could lead to performance problems. Check with the database vendors for prescriptive details on the exclusion list. For example, Oracle recommends excluding /oracle//sapdata from antivirus scans.", - "waf": "Performance" + "text": "Establish an automated process for key and certificate rotation.", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "c027f893-f404-41a9-b33d-39d625a14964", - "link": "https://sapit-forme-prod.authentication.eu11.hana.ondemand.com/login", - "service": "SAP", + "guid": "cdb3751a-b2ab-413a-ba6e-55d7d8a2adb1", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", "services": [ - "WAF", - "SAP" + "AKV", + "PrivateLink", + "VNet", + "WAF" ], - "severity": "Low", - "text": "Consider collecting full database statistics for non-HANA databases after migration. For example, implement SAP note 1020260 - Delivery of Oracle statistics.", - "waf": "Performance" + "severity": "Medium", + "text": "Enable firewall and virtual network service endpoint or private endpoint on the vault to control access to the key vault.", + "training": "https://learn.microsoft.com/training/modules/design-implement-private-access-to-azure-services/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "fdafb1f5-3eee-4354-a8c9-deb8127ebc2e", - "link": "https://learn.microsoft.com/azure/virtual-machines/workloads/oracle/configure-oracle-asm", - "service": "SAP", + "guid": "17d6326a-f625-4ca4-9e56-95f2223ace8c", + "link": "https://learn.microsoft.com/azure/key-vault/general/monitor-key-vault", + "service": "Key Vault", "services": [ - "Storage", - "WAF", - "SAP" + "AKV", + "Monitor", + "Entra", + "WAF" ], "severity": "Medium", - "text": "Consider using Oracle Automatic Storage Management (ASM) for all Oracle deployments that use SAP on Azure.", - "training": "https://learn.microsoft.com/training/paths/administer-infrastructure-resources-in-azure/?source=recommendations", - "waf": "Performance" + "text": "Use the platform-central Azure Monitor Log Analytics workspace to audit key, certificate, and secret usage within each instance of Key Vault.", + "training": "https://learn.microsoft.com/training/modules/analyze-infrastructure-with-azure-monitor-logs/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "33c5d5bf-daf3-4f0d-bd50-6010fdcec22e", - "link": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/announcement-sap-on-azure-oracle-performance-efficiency-scripts/ba-p/3725178", - "service": "SAP", + "guid": "b12308ca-5017-4f15-9e3a-b3693829e7e3", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", "services": [ - "SQL", - "WAF", - "SAP" + "AKV", + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "For SAP on Azure running Oracle, a collection of SQL scripts can help you diagnose performance problems. Automatic Workload Repository (AWR) reports contain valuable information for diagnosing problems in the Oracle system. We recommend that you run an AWR report during several sessions and choose peak times for it, to ensure broad coverage for the analysis.", - "training": "https://learn.microsoft.com/ja-jp/azure/well-architected/oracle-iaas/performance-efficiency", - "waf": "Performance" + "text": "Delegate Key Vault instantiation and privileged access and use Azure Policy to enforce a consistent compliant configuration.", + "training": "https://learn.microsoft.com/training/modules/configure-azure-key-vault-networking-settings/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "d89fd98d-23e4-4b40-a92e-32db9365522c", - "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-monitor-and-troubleshoot", - "service": "SAP", + "guid": "91163418-2ba5-4275-8694-4008be7d7e48", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", "services": [ - "ASR", - "WAF", - "SAP", - "Monitor" + "AKV", + "WAF" ], - "severity": "High", - "text": "Use Azure Site Recovery monitoring to maintain the health of the disaster recovery service for SAP application servers.", - "training": "https://learn.microsoft.com/training/modules/protect-on-premises-infrastructure-with-azure-site-recovery/?source=recommendations", - "waf": "Operations" + "severity": "Medium", + "text": "Use an Azure Key Vault per application per environment per region.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-key-vault/", + "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "5ba34d46-85e2-4213-ace7-bb122f7c95f0", - "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", - "service": "SAP", + "guid": "25d62688-6d70-4ba6-a97b-e99519048384", + "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "service": "Key Vault", "services": [ - "AppGW", - "AzurePolicy", + "ACR", + "ASR", + "AKV", "WAF" ], "severity": "Medium", - "text": "For secure delivery of HTTP/S apps, use Application Gateway v2 and ensure that WAF protection and policies are enabled.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/", + "text": "If you want to bring your own keys, this might not be supported across all considered services. Implement relevant mitigation so that inconsistencies don't hinder desired outcomes. Choose appropriate region pairs and disaster recovery regions that minimize latency.", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/", "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "fa9d30bc-1b82-4e4b-bfdf-6b017938b9e6", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", - "service": "SAP", + "guid": "4ac6b67c-b3a4-4ff9-8e87-b07a7ce7bbdb", + "link": "https://learn.microsoft.com/industry/sovereignty/key-management", + "service": "Key Vault", "services": [ - "VM", - "DNS", - "WAF", - "SAP" + "AKV", + "WAF" ], "severity": "Medium", - "text": "If the virtual machine's DNS or virtual name is not changed during migration to Azure, Background DNS and virtual names connect many system interfaces in the SAP landscape, and customers are only sometimes aware of the interfaces that developers define over time. Connection challenges arise between various systems when virtual or DNS names change after migrations, and it's recommended to retain DNS aliases to prevent these types of difficulties.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/4-explore-name-resolution", - "waf": "Operations" + "text": "For Sovereign Landing Zone, use Azure Key Vault managed HSM to store your secrets and credentials.", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "a2858f78-105b-4f52-b7a9-5b0f4439743b", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", - "service": "SAP", + "guid": "4e5695f2-223a-4ce8-ab12-308ca5017f15", + "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-reports", + "service": "Entra", "services": [ - "DNS", - "VNet", - "WAF", - "SAP" + "Entra", + "WAF" ], "severity": "Medium", - "text": "Use different DNS zones to distinguish each environment (sandbox, development, preproduction, and production) from each other. The exception is for SAP deployments with their own VNet; here, private DNS zones might not be necessary.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/4-explore-name-resolution", - "waf": "Operations" + "text": "Use Microsoft Entra ID reporting capabilities to generate access control audit reports.", + "training": "https://learn.microsoft.com/training/modules/monitor-report-aad-security-events/", + "waf": "Security" }, { "checklist": "WAF checklist", - "description": "When configuring VNet peering, use the Allow traffic to remote virtual networks setting.", - "graph": "resources | where type =~ 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess =~ True)", - "guid": "a3592829-e6e2-4061-9368-6af46791f893", - "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-peering-overview", - "service": "SAP", + "guid": "09945bda-4333-44f2-9911-634182ba5275", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/concept-cloud-security-posture-management", + "service": "Defender", "services": [ - "VNet", - "WAF", - "SAP", - "ACR" + "Defender", + "Subscriptions", + "WAF" ], - "severity": "Medium", - "text": "Local and global VNet peering provide connectivity and are the preferred approaches to ensure connectivity between landing zones for SAP deployments across multiple Azure regions", - "training": "https://learn.microsoft.com/training/modules/configure-vnet-peering/?source=recommendations", - "waf": "Reliability" + "severity": "High", + "text": "Enable Defender Cloud Security Posture Management for all subscriptions.", + "training": "https://learn.microsoft.com/training/modules/microsoft-defender-cloud-security-posture/", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "41742694-3ff8-4ae7-b7d4-743176c8bcbf", - "link": "https://learn.microsoft.com/azure/sap/workloads/planning-guide", - "service": "SAP", + "guid": "36a72a48-fffe-4c40-9747-0ab5064355ba", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/plan-defender-for-servers-select-plan", + "service": "Defender", "services": [ - "NVA", - "WAF", - "SAP" + "Defender", + "Subscriptions", + "WAF" ], "severity": "High", - "text": "It is not supported to deploy any NVA between SAP application and SAP Database server", - "training": "https://me.sap.com/notes/2731110", - "waf": "Performance" + "text": "Enable a Defender Cloud Workload Protection Plan for Servers on all subscriptions.", + "training": "https://learn.microsoft.com/training/modules/understand-azure-defender-cloud-workload-protection/", + "waf": "Security" }, { "checklist": "WAF checklist", - "graph": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic =~ 'true') | distinct id,compliant", - "guid": "7d4bc7d2-c34a-452e-8f1d-6ae3c8eafcc3", - "link": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/?source=recommendations", - "service": "SAP", + "guid": "77425f48-ecba-43a0-aeac-a3ac733ccc6a", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/connect-azure-subscription", + "service": "Defender", "services": [ - "VWAN", - "WAF", - "SAP", - "ACR" + "Defender", + "Subscriptions", + "WAF" ], - "severity": "Medium", - "text": "Use Virtual WAN for Azure deployments in new, large, or global networks where you need global transit connectivity across Azure regions and on-premises locations. With this approach, you won't need to manually set up transitive routing for Azure networking, and you can follow a standard for SAP on Azure deployments.", - "training": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about", - "waf": "Operations" + "severity": "High", + "text": "Enable Defender Cloud Workload Protection Plans for Azure Resources on all subscriptions.", + "training": "https://learn.microsoft.com/training/modules/understand-azure-defender-cloud-workload-protection/", + "waf": "Security" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "0cedb1f6-ae6c-492b-8b17-8061f50b16d3", - "link": "https://learn.microsoft.com/azure/well-architected/services/networking/network-virtual-appliances/reliability", - "service": "SAP", + "guid": "24d96b30-61ee-4436-a1cc-d6ef08bc574b", + "link": "https://learn.microsoft.com/mem/configmgr/protect/deploy-use/endpoint-protection", + "service": "VM", "services": [ - "NVA", - "VNet", "WAF" ], - "severity": "Medium", - "text": "Consider deploying network virtual appliances (NVAs) between regions only if partner NVAs are used. NVAs between regions or VNets aren't required if native NVAs are present. When you're deploying partner networking technologies and NVAs, follow the vendor's guidance to verify conflicting configurations with Azure networking.", - "training": "https://learn.microsoft.com/training/modules/control-network-traffic-flow-with-routes/?source=recommendations", - "waf": "Operations" + "severity": "High", + "text": "Enable Endpoint Protection on IaaS Servers.", + "training": "https://learn.microsoft.com/training/modules/design-solutions-securing-server-client-endpoints/", + "waf": "Security" }, { + "arm-service": "Microsoft.Compute/virtualMachines", "checklist": "WAF checklist", - "guid": "facc08c6-ea95-4641-91cd-fa09e573adbd", - "link": "https://learn.microsoft.com/azure/architecture/networking/hub-spoke-vwan-architecture", - "service": "SAP", + "guid": "15833ee7-ad6c-46d3-9331-65c7acbe44ab", + "link": "https://learn.microsoft.com/azure/security-center/", + "service": "VM", "services": [ - "VWAN", - "NVA", - "VNet", - "WAF", - "SAP" + "Defender", + "Monitor", + "WAF" ], "severity": "Medium", - "text": "Virtual WAN manages connectivity between spoke VNets for virtual-WAN-based topologies (no need to set up user-defined routing [UDR] or NVAs), and maximum network throughput for VNet-to-VNet traffic in the same virtual hub is 50 gigabits per second. If necessary, SAP landing zones can use VNet peering to connect to other landing zones and overcome this bandwidth limitation.", - "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/?source=recommendations", - "waf": "Operations" + "text": "Monitor base operating system patching drift via Azure Monitor Logs and Defender for Cloud.", + "training": "https://learn.microsoft.com/training/modules/create-log-analytics-workspace-microsoft-defender-cloud/", + "waf": "Security" }, { + "arm-service": "Microsoft.Insights/components", "checklist": "WAF checklist", - "graph": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)", - "guid": "82734c88-6ba2-4802-8459-11475e39e530", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", - "service": "SAP", + "guid": "e5f8d79f-2e87-4768-924c-516775c6ea95", + "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", + "service": "Monitor", "services": [ - "VM", - "WAF", - "SAP" + "Monitor", + "Entra", + "WAF" ], - "severity": "High", - "text": "Public IP assignment to VM running SAP Workload is not recommended.", - "training": "https://learn.microsoft.com/training/modules/design-ip-addressing-for-azure/?source=recommendations", + "severity": "Medium", + "text": "Connect default resource configurations to a centralized Azure Monitor Log Analytics workspace.", + "training": "https://learn.microsoft.com/training/modules/analyze-infrastructure-with-azure-monitor-logs/", "waf": "Security" }, { "checklist": "WAF checklist", - "graph": "Resources | where type contains 'publicIPAddresses' and isnotempty(properties.ipAddress) | summarize count () by subscriptionId", - "guid": "9cccd979-366b-4cda-8750-ab1ab039d95d", - "link": "https://learn.microsoft.com/training/modules/protect-on-premises-infrastructure-with-azure-site-recovery/?source=recommendations", - "service": "SAP", + "graph": "resources| where type == 'microsoft.operationalinsights/workspaces'| extend wsid = properties.customerId| project workspaceResourceId = tolower(id), name, wsid| join (resources| where type == 'microsoft.operationsmanagement/solutions'| where name has 'SecurityInsights'| extend workspaceResourceId = tostring(tolower(properties.workspaceResourceId))| project workspaceResourceId | summarize ResourceCount = count() by workspaceResourceId) on workspaceResourceId| extend RCount = iff(isnull(ResourceCount), 0, ResourceCount)| project-away ResourceCount| extend compliant = (RCount <> 0)", + "guid": "a56888b2-7e83-4404-bd31-b886528502d1", + "link": "https://learn.microsoft.com/en-us/azure/well-architected/security/monitor-threats#centralized-threat-detection-with-correlated-logs", + "service": "Entra", "services": [ - "ASR", + "ACR", + "Entra", "WAF" ], "severity": "High", - "text": "Consider reserving IP address on DR side when configuring ASR", - "training": "https://learn.microsoft.com/learn/paths/architect-network-infrastructure/", - "waf": "Operations" + "text": "Centralized threat detection with correlated logs - consolidate security data in a central location where it can be correlated across various services via SIEM (security information and event management)", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "54c7c892-9cb1-407d-9325-ae525ba34d46", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", - "service": "SAP", + "guid": "1761e147-f65e-4d09-bbc2-f464f23e2eba", + "link": "https://learn.microsoft.com/industry/sovereignty/transparency-logs", + "service": "Entra", "services": [ + "Entra", "WAF" ], - "severity": "High", - "text": "Avoid using overlapping IP address ranges for production and DR sites.", - "training": "https://learn.microsoft.com/training/modules/design-ip-addressing-for-azure/?source=recommendations", - "waf": "Operations" + "severity": "Medium", + "text": "For Sovereign Landing Zone, enable transparancy logs on the Entra ID tenant.", + "waf": "Security" }, { "checklist": "WAF checklist", - "guid": "6e154e3a-a359-4282-ae6e-206173686af4", - "link": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-delegate-subnet", - "service": "SAP", + "guid": "d21a922d-5ca7-427a-82a6-35f7b21f1bfc", + "link": "https://learn.microsoft.com/azure/security/fundamentals/customer-lockbox-overview", + "service": "Entra", "services": [ - "Storage", - "VNet", + "Entra", "WAF" ], "severity": "Medium", - "text": "While Azure does help you to create multiple delegated subnets in a VNet, only one delegated subnet can exist in a VNet for Azure NetApp Files. Attempts to create a new volume will fail if you use more than one delegated subnet for Azure NetApp Files.", - "training": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-network-topologies?source=recommendations", - "waf": "Operations" + "text": "For Sovereign Landing Zone, enable customer Lockbox on the Entra ID tenant.", + "waf": "Security" }, { + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "graph": "resources | where type=~'microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant", - "guid": "d8a03e97-7784-424d-9167-85d6fa96c96a", - "link": "https://learn.microsoft.com/azure/well-architected/services/networking/azure-firewall?toc=%2Fazure%2Ffirewall%2Ftoc.json&bc=%2Fazure%2Ffirewall%2Fbreadcrumb%2Ftoc.json", - "service": "SAP", + "guid": "b03ed428-4617-4067-a787-85468b9ccf3f", + "link": "https://learn.microsoft.com/azure/storage/common/storage-require-secure-transfer", + "service": "Storage", "services": [ - "Firewall", + "Storage", "WAF" ], - "severity": "Medium", - "text": "Use Azure Firewall to govern Azure outbound traffic to the internet, non-HTTP/S inbound connections, and East/West traffic filtering (if the organization requires it)", - "training": "https://learn.microsoft.com/training/paths/secure-networking-infrastructure/", + "severity": "High", + "text": "Enable secure transfer to storage accounts.", + "training": "https://learn.microsoft.com/training/modules/secure-azure-storage-account/", "waf": "Security" }, { + "arm-service": "Microsoft.Storage/storageAccounts", "checklist": "WAF checklist", - "guid": "91a65e40-be90-45b3-9f73-f3edbf8dc324", - "link": "https://learn.microsoft.com/azure/sap/workloads/expose-sap-process-orchestration-on-azure", - "service": "SAP", + "guid": "159aac9f-863f-4f48-82cf-00c28fa97a0e", + "link": "https://learn.microsoft.com/azure/storage/blobs/data-protection-overview#recommendations-for-basic-data-protection", + "service": "Storage", "services": [ - "AppGW", - "WAF", - "SAP" + "Storage", + "WAF" ], - "severity": "Medium", - "text": "Application Gateway and Web Application Firewall have limitations when Application Gateway serves as a reverse proxy for SAP web apps, as shown in the comparison between Application Gateway, SAP Web Dispatcher, and other third-party services.", - "training": "https://help.sap.com/docs/SUPPORT_CONTENT/si/3362959506.html", + "severity": "High", + "text": "Enable container soft delete for the storage account to recover a deleted container and its contents.", "waf": "Security" }, { + "arm-service": "Microsoft.KeyVault/vaults", "checklist": "WAF checklist", - "guid": "5e39e530-9ccc-4d97-a366-bcda2750ab1a", - "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", - "service": "SAP", + "guid": "108d5099-a11d-4445-bd8b-e12a5e95412e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/considerations/development-strategy-development-lifecycle#automated-builds", + "service": "Key Vault", "services": [ - "AzurePolicy", - "WAF", - "FrontDoor", - "ACR" + "VM", + "AKV", + "WAF" ], - "severity": "Medium", - "text": "Use Azure Front Door and WAF policies to provide global protection across Azure regions for inbound HTTP/S connections to a landing zone.", - "training": "https://learn.microsoft.com/training/paths/secure-application-delivery/", - "waf": "Security" + "severity": "High", + "text": "Use Key Vault secrets to avoid hard-coding sensitive information such as credentials (virtual machines user passwords), certificates or keys.", + "training": "https://learn.microsoft.com/en-us/training/modules/implement-azure-key-vault/", + "waf": "Operations" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "b039d95d-54c7-4c89-89cb-107d5325ae52", - "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", - "service": "SAP", + "guid": "4238f409-2ea0-43be-a06b-2a993c98aa7b", + "link": "https://learn.microsoft.com/en-us/azure/azure-functions/functions-scale#overview-of-plans", + "service": "Azure Functions", "services": [ - "AppGW", - "AzurePolicy", - "WAF", - "FrontDoor" + "WAF" ], - "severity": "Medium", - "text": "Take advantage of Web Application Firewall policies in Azure Front Door when you're using Azure Front Door and Application Gateway to protect HTTP/S applications. Lock down Application Gateway to receive traffic only from Azure Front Door.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations", - "waf": "Security" + "severity": "High", + "text": "Select the right Function hosting plan based on your business & SLO requirements", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "5ada4332-4e13-4811-9231-81aa41742694", - "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", - "service": "SAP", + "guid": "a9808100-d640-4f77-ac56-1ec0600f6752", + "link": "https://learn.microsoft.com/en-us/azure/azure-functions/functions-scale#overview-of-plans", + "query": "resources | where type =~ 'Microsoft.Web/sites' and kind has 'functionapp' and tolower(kind) !contains 'workflow' | extend aspResourceId = tostring(properties.serverFarmId), managedEnvId = tostring(properties.managedEnvironmentId), sku = tostring(properties.sku) | extend sku = iif(isnotempty(sku), sku, iif(isnotempty(managedEnvId), 'ContainerApps', '')) | where sku !in ('Dynamic', 'FlexConsumption', '') | extend aspName = tostring(split(aspResourceId, '/').[-1]), managedEnvName = tostring(split(managedEnvId, '/').[-1]) | extend HostingPlan = tostring(iif(isnotempty(aspName), aspName, managedEnvName)) | project functionAppName = name, functionAppId = id, HostingPlan, sku | join kind=inner ( resources | where type =~ 'Microsoft.Web/serverfarms' or type =~ 'Microsoft.App/managedEnvironments' | extend HostingPlan = tostring(name), zoneRedundant = tostring(properties.zoneRedundant), compliant = tobool(properties.zoneRedundant) | project HostingPlan, resourceId = id, zoneRedundant, compliant ) on HostingPlan | project functionAppName, functionAppId, sku, HostingPlan, resourceId, zoneRedundant, compliant", + "service": "Azure Functions", "services": [ - "AppGW", - "LoadBalancer", "WAF" ], - "severity": "Medium", - "text": "Use a web application firewall to scan your traffic when it's exposed to the internet. Another option is to use it with your load balancer or with resources that have built-in firewall capabilities like Application Gateway or third-party solutions.", - "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations", - "waf": "Security" + "severity": "High", + "text": "Leverage Availability Zones where regionally applicable (not available for Consumption tier)", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "e73de7d5-6f36-4217-a526-e1a621ecddde", - "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", - "service": "SAP", + "guid": "5969d03e-eacf-4042-b127-73c55e3575fa", + "link": "https://learn.microsoft.com/en-us/azure/reliability/reliability-functions?tabs=azure-portal#cross-region-disaster-recovery-and-business-continuity", + "service": "Azure Functions", "services": [ - "VWAN", - "WAF", - "SAP", - "ACR" + "WAF" ], "severity": "Medium", - "text": "Use Virtual WAN for Azure deployments in new, large, or global networks where you need global transit connectivity across Azure regions and on-premises locations. With this approach, you won't need to manually set up transitive routing for Azure networking, and you can follow a standard for SAP on Azure deployments.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/10-explore-azure-front-door", - "waf": "Performance" + "text": "Consider a Cross-Region DR strategy for critical workloads", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "3c536a3e-1b6b-4e87-95ca-15edb47251c0", - "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", - "service": "SAP", + "guid": "47a0aae0-d8a0-43b1-9791-e934dee3754c", + "link": "https://learn.microsoft.com/en-us/azure/app-service/environment/intro", + "service": "Azure Functions", "services": [ - "ACR", - "Storage", - "PrivateLink", - "VNet", - "Backup", + "AppSvc", "WAF" ], - "severity": "Medium", - "text": "To prevent data leakage, use Azure Private Link to securely access platform as a service resources like Azure Blob Storage, Azure Files, Azure Data Lake Storage Gen2, Azure Data Factory, and more. Azure Private Endpoint can also help to secure traffic between VNets and services like Azure Storage, Azure Backup, and more. Traffic between your VNet and the Private Endpoint enabled service travels across the Microsoft global network, which prevents its exposure to the public internet.", - "training": "https://learn.microsoft.com/training/modules/design-implement-private-access-to-azure-services/?source=recommendations", - "waf": "Security" + "severity": "High", + "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "graph": "Resources | where type =~ 'Microsoft.Network/NetworkInterfaces' | where properties.enableAcceleratedNetworking =~ 'false' | project name, subscriptionId, properties.enableAcceleratedNetworking", - "guid": "85e2213a-ce7b-4b12-8f7c-95f06e154e3a", - "link": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview?tabs=redhat", - "service": "SAP", + "guid": "17232891-f89f-4eaa-90f1-3b34bf798ed5", + "link": "https://learn.microsoft.com/en-us/azure/azure-functions/dedicated-plan#always-on", + "query": "resources | where type =~ 'Microsoft.Web/sites' and kind has 'functionapp' | where tolower(kind) !contains 'workflow' | where isnotempty(properties.serverFarmId) | extend sku = tostring(properties.sku) | where isnotempty(sku) | where sku !in ('Dynamic', 'FlexConsumption', 'ElasticPremium') | extend alwaysOn = properties.siteConfig.alwaysOn | project functionAppName = name, functionAppId = id, serverFarmId = tostring(properties.serverFarmId), sku, alwaysOn, compliant = tobool(alwaysOn)", + "service": "Azure Functions", "services": [ - "VM", - "WAF", - "SAP" + "AppSvc", + "WAF" ], "severity": "High", - "text": "Make sure that Azure accelerated networking is enabled on the VMs used in the SAP application and DBMS layers.", - "training": "https://learn.microsoft.com/training/paths/azure-fundamentals-describe-azure-architecture-services/?source=recommendations", - "waf": "Performance" + "text": "Ensure 'Always On' is enabled for all Function Apps running on App Service Plan", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "guid": "3ff8ae7d-7d47-4431-96c8-bcbf45bbe609", - "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-multivip-overview", - "service": "SAP", + "guid": "40a325c2-7c0e-49e6-86d8-c273b4dc21ba", + "link": "https://learn.microsoft.com/en-us/azure/azure-functions/storage-considerations?tabs=azure-cli#shared-storage-accounts", + "service": "Azure Functions", "services": [ - "LoadBalancer", + "Storage", "WAF" ], "severity": "Medium", - "text": "Make sure that internal deployments for Azure Load Balancer are set up to use Direct Server Return (DSR). This setting (Enabling Floating IP) will reduce latency when internal load balancer configurations are used for high-availability configurations on the DBMS layer.", - "training": "https://learn.microsoft.com/ja-jp/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations", - "waf": "Security" + "text": "Pair a Function App to its own storage account. Try not to re-use storage accounts for Function Apps unless they are tightly coupled", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Web/sites", "checklist": "WAF checklist", - "graph": "Resources | where type =~ 'microsoft.network/networksecuritygroups' and isnull(properties.networkInterfaces) and isnull(properties.subnets) | project name, resourceGroup | sort by name asc", - "guid": "6791f893-5ada-4433-84e1-3811523181aa", - "link": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", - "service": "SAP", + "guid": "bb42650c-257d-4cb0-822a-131138b8e6f0", + "link": "https://learn.microsoft.com/en-us/training/modules/deploy-azure-functions/", + "service": "Azure Functions", "services": [ - "VM", - "VNet", - "WAF", - "SAP" + "WAF" ], "severity": "Medium", - "text": "You can use application security group (ASG) and NSG rules to define network security access-control lists between the SAP application and DBMS layers. ASGs group virtual machines to help manage their security.", - "training": "https://learn.microsoft.com/training/modules/configure-network-security-groups/?source=recommendations", - "waf": "Security" + "text": "Leverage Azure DevOps or GitHub to streamline CI/CD and safeguard your Function App code", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "45bbe609-d8a0-43e9-9778-424d616785d6", - "link": "https://me.sap.com/notes/2015553", - "service": "SAP", + "guid": "d7941d4a-7b6f-458f-8714-2f8f8c059ad4", + "link": "https://learn.microsoft.com/azure/api-management/api-management-error-handling-policies", + "service": "APIM", "services": [ - "VNet", - "WAF", - "SAP" + "AzurePolicy", + "WAF" ], - "severity": "High", - "text": "Placing of the SAP application layer and SAP DBMS in different Azure VNets that aren't peered isn't supported.", - "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", - "waf": "Performance" + "severity": "Medium", + "text": "Implement an error handling policy at the global level", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "fa96c96a-d885-418f-9827-34c886ba2802", - "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", - "service": "SAP", + "guid": "0b0c0765-ff37-4369-90bd-3eb23ce71b08", + "link": "https://learn.microsoft.com/azure/api-management/set-edit-policies?tabs=form#use-base-element-to-set-policy-evaluation-order", + "service": "APIM", "services": [ - "WAF", - "SAP" + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "For optimal network latency with SAP applications, consider using Azure proximity placement groups.", - "training": "https://learn.microsoft.com/azure/virtual-machines/co-location#planned-maintenance-and-proximity-placement-groups", - "waf": "Performance" + "text": "Ensure all APIs policies include a element.", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "18c8b61c-855a-4405-b6ed-266455e4f4ce", - "link": "https://me.sap.com/notes/2015553", - "service": "SAP", + "guid": "a5c45b03-93b6-42fe-b16b-8fccb6a79902", + "link": "https://learn.microsoft.com/azure/api-management/policy-fragments", + "service": "APIM", "services": [ - "WAF", - "SAP" + "ACR", + "AzurePolicy", + "WAF" ], - "severity": "High", - "text": "It is NOT supported at all to run an SAP Application Server layer and DBMS layer split between on-premise and Azure. Both layers need to completely reside either on-premise or in Azure.", - "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", - "waf": "Performance" + "severity": "Medium", + "text": "Use Policy Fragments to avoid repeating same policies definitions across multiple APIs", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "b65c878b-4b14-4f4e-92d8-d873936493f2", - "link": "https://me.sap.com/notes/2015553", - "service": "SAP", + "guid": "c3818a95-6ff3-4474-88dc-e809b46dad6a", + "link": "https://learn.microsoft.com/azure/api-management/monetization-support", + "service": "APIM", "services": [ - "SAP", - "VNet", - "WAF", - "Cost" + "WAF" ], - "severity": "High", - "text": "It isn't recommended to host the database management system (DBMS) and application layers of SAP systems in different VNets and connect them with VNet peering because of the substantial costs that excessive network traffic between the layers can produce. Recommend using subnets within the Azure virtual network to separate the SAP application layer and DBMS layer.", - "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", - "waf": "Cost" + "severity": "Medium", + "text": "If you are planning to monetize your APIs, review the 'monetization support' article for best practices", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "402a9846-d515-4061-aff8-cd30088693fa", - "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel", - "service": "SAP", + "guid": "a7d0840a-c8c4-4e83-adec-5ca578eb4049", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-use-azure-monitor#resource-logs", + "service": "APIM", "services": [ - "LoadBalancer", + "Monitor", "WAF" ], "severity": "High", - "text": "If using Load Balancer with Linux guest operating systems, check that the Linux network parameter net.ipv4.tcp_timestamps is set to 0.", - "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations", - "waf": "Performance" + "text": "Enable Diagnostics Settings to export logs to Azure Monitor", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "87585797-5551-4d53-bb7d-a94ee415734d", - "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration", - "service": "SAP", + "guid": "8691fa38-45ed-4299-a247-fecd98d35deb", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-app-insights", + "service": "APIM", "services": [ - "VNet", - "WAF", - "SAP" + "WAF" ], "severity": "Medium", - "text": "For SAP RISE/ECS deployments, virtual peering is the preferred way to establish connectivity with customer's existing Azure environment. Both the SAP vnet and customer vnet(s) are protected with network security groups (NSG), enabling communication on SAP and database ports through the vnet peering", - "waf": "Security" + "text": "Enable Application Insights for more detailed telemetry", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "ff5136bd-dcf1-4d2b-ae52-39333efdf45a", - "link": "https://learn.microsoft.com/azure/backup/sap-hana-database-about", - "service": "SAP", + "guid": "55fd27bb-76ac-4a91-bc37-049e885be6b7", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-use-azure-monitor", + "service": "APIM", "services": [ - "VM", - "SAP", - "WAF", - "Backup" + "Monitor", + "WAF" ], "severity": "High", - "text": "Review SAP HANA database backups for Azure VMs.", - "waf": "Cost" + "text": "Configure alerts on the most critical metrics", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "cafde29d-a0af-4bcd-87c0-0f299d63f0e8", - "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-monitor-and-troubleshoot", - "service": "SAP", + "guid": "39460bdb-156f-4dc2-a87f-1e8c11ab0998", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#certificate-management-in-azure-key-vault", + "service": "APIM", "services": [ - "ASR", - "WAF", - "SAP", - "Monitor" + "AKV", + "WAF" ], - "severity": "Medium", - "text": "Review Site Recovery built-in monitoring, where used for SAP.", - "waf": "Cost" + "severity": "High", + "text": "Ensure that custom SSL certificates are stored an Azure Key Vault so they can be securely accessed and updated", + "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "82d7b8de-d3f1-44a0-830b-38e200e82acf", - "link": "https://help.sap.com/docs/SAP_HANA_PLATFORM/c4d7c773af4a4e5dbebb6548d6e2d4f4/e3111d2ebb5710149510cc120646bf3f.html?locale=en-US", - "service": "SAP", + "guid": "e9217997-5f6c-479d-8576-8f2adf706ec8", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#azure-ad-authentication-required-for-data-plane-access", + "service": "APIM", "services": [ - "WAF", - "SAP", - "Monitor" + "Entra", + "WAF" ], "severity": "High", - "text": "Review the Monitoring the SAP HANA System Landscape guidance.", - "waf": "Operations" + "text": "Protect incoming requests to APIs (data plane) with Azure AD", + "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "c823873a-2bec-4c2a-b684-a1ce8ae80efd", - "link": "https://learn.microsoft.com/azure/virtual-machines/workloads/oracle/oracle-database-backup-strategies", - "service": "SAP", + "guid": "5e5f64ba-c90e-480e-8888-398d96cf0bfb", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-aad", + "service": "APIM", "services": [ - "VM", - "WAF", - "Backup" + "Entra", + "WAF" ], "severity": "Medium", - "text": "Review Oracle Database in Azure Linux VM backup strategies.", - "waf": "Operations" + "text": "Use Microsoft Entra ID to authenticate users in the Developer Portal", + "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "2943b6d8-1d31-4e19-ade7-78e6b26d1962", - "link": "https://learn.microsoft.com/sql/relational-databases/tutorial-use-azure-blob-storage-service-with-sql-server-2016?view=sql-server-ver16", - "service": "SAP", + "guid": "f8e574ce-280f-49c8-b2ef-68279b081cf3", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-create-groups", + "service": "APIM", "services": [ - "Storage", - "SQL", "WAF" ], "severity": "Medium", - "text": "Review the use of Azure Blob Storage with SQL Server 2016.", - "waf": "Operations" + "text": "Create appropriate groups to control the visibility of the products", + "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "b82e650f-676d-417d-994d-fc33ca54ec14", - "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/automated-backup?view=azuresql", - "service": "SAP", + "guid": "06862505-2d9a-4874-9491-2837b00a3475", + "link": "https://learn.microsoft.com/azure/api-management/backends", + "service": "APIM", "services": [ - "VM", - "WAF", - "Backup" + "WAF" ], "severity": "Medium", - "text": "Review the use of Automated Backup v2 for Azure VMs.", + "text": "Use Backends feature to eliminate redundant API backend configurations", "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "347c2dcc-e6eb-4b04-80c5-628b171aa62d", - "service": "SAP", + "guid": "03b125d5-b69b-4739-b7fd-84b86da4933e", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-properties?tabs=azure-portal", + "service": "APIM", "services": [ + "AzurePolicy", "WAF" ], - "severity": "High", - "text": "Enabling Write accelerator for M series when using premium disks(V1)", + "severity": "Medium", + "text": "Use Named Values to store common values that can be used in policies", "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "b96512cf-996f-4b17-b9b8-6b16db1a2a94", - "link": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/AvZone-Latency-Test", - "service": "SAP", + "guid": "beae759e-4ddb-4326-bf26-47f87d3454b6", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region", + "service": "APIM", "services": [ + "ACR", "WAF" ], "severity": "Medium", - "text": "Test availability zone latency.", - "waf": "Performance" + "text": "For DR, leverage the premium tier with deployments scaled across two or more regions for 99.99% SLA", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "9fd7ffd4-da11-49f6-a374-8d03e94c511d", - "link": "https://support.sap.com/en/offerings-programs/support-services/earlywatch-alert.html", - "service": "SAP", + "guid": "9c8d1664-dd9a-49d4-bd83-950af0af4044", + "link": "https://learn.microsoft.com/azure/api-management/high-availability", + "service": "APIM", "services": [ - "WAF", - "SAP" + "WAF" ], "severity": "Medium", - "text": "Activate SAP EarlyWatch Alert for all SAP components.", - "training": "https://help.sap.com/docs/SUPPORT_CONTENT/techops/3362700736.html", - "waf": "Performance" + "text": "Deploy at least one unit in two or more availability zones for an increased SLA of 99.99%", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "b9b140cf-413a-483d-aad2-8802c4e3c017", - "link": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/sap-on-azure-general-update-march-2019/ba-p/377456", - "service": "SAP", + "guid": "8d2db6e8-85c6-4118-a52c-ae76a4f27934", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#service-native-backup-capability", + "service": "APIM", "services": [ - "WAF", - "SAP" + "Backup", + "WAF" ], - "severity": "Medium", - "text": "Review SAP application server to database server latency using SAP ABAPMeter report /SSA/CAT.", - "training": "https://me.sap.com/notes/0002879613", - "waf": "Performance" + "severity": "High", + "text": "Ensure there is an automated backup routine", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "62fbf0f8-51db-49e1-a961-bb5df7a35f80", - "service": "SAP", + "guid": "43e60b94-7bca-43a2-aadf-efb04d63a485", + "link": "https://learn.microsoft.com/azure/api-management/retry-policy", + "service": "APIM", "services": [ - "SQL", - "WAF", - "Monitor" + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Review SQL Server performance monitoring using CCMS.", - "waf": "Performance" + "text": "Use Policies to add a fail-over backend URL and caching to reduce failing calls.", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "35709da7-fc7d-4efe-bb20-2e91547b7390", - "link": "https://me.sap.com/notes/500235", - "service": "SAP", + "guid": "8210699f-8d43-45c2-8f19-57e54134bd8f", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-log-event-hubs", + "service": "APIM", "services": [ - "VM", - "WAF", - "SAP" + "EventHubs", + "AzurePolicy", + "WAF" + ], + "severity": "Low", + "text": "If you need to log at high performance levels, consider Event Hubs policy", + "waf": "Operations" + }, + { + "arm-service": "Microsoft.ApiManagement/service", + "checklist": "WAF checklist", + "guid": "121bfc39-fa7b-4096-b93b-ab56c1bc0bed", + "link": "https://learn.microsoft.com/azure/api-management/api-management-sample-flexible-throttling", + "service": "APIM", + "services": [ + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Test network latency between SAP application layer VMs and DBMS VMs (NIPING).", - "training": "https://me.sap.com/notes/1100926/E", + "text": "Apply throttling policies to control the number of requests per second", + "training": "https://learn.microsoft.com/training/modules/protect-apis-on-api-management/", "waf": "Performance" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "9e9bb4c8-e934-4e4b-a13c-6f7c7c38eb43", - "link": "https://learn.microsoft.com/en-us/azure/sap/large-instances/hana-monitor-troubleshoot", - "service": "SAP", + "guid": "bb5f356b-3daf-47a2-a9ee-867a8100bbd5", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-autoscale", + "service": "APIM", "services": [ - "WAF", - "SAP", - "Monitor" + "WAF" ], "severity": "Medium", - "text": "Review SAP HANA studio alerts.", + "text": "Configure autoscaling to scale out the number of instances when the load increases", "waf": "Performance" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "f1a92ab5-9509-4b57-86ff-b0ade361b694", - "link": "https://me.sap.com/notes/1969700", - "service": "SAP", + "guid": "84b94abb-59b6-4b9d-8587-3413669468e8", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-provision-self-hosted-gateway", + "service": "APIM", "services": [ - "WAF", - "SAP" + "WAF" ], "severity": "Medium", - "text": "Perform SAP HANA health checks using HANA_Configuration_Minichecks.", + "text": "Deploy self-hosted gateways where Azure doesn't have a region close to the backend APIs.", "waf": "Performance" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "18dffcf3-248c-4039-a67c-dec8e3a5f804", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", - "service": "SAP", + "guid": "1fe8db45-a017-4888-8c4d-4422583cfae0", + "link": "https://learn.microsoft.com/azure/api-management/upgrade-and-scale#upgrade-and-scale", + "service": "APIM", "services": [ - "VM", "WAF" ], "severity": "Medium", - "text": "If you run Windows and Linux VMs in Azure, on-premises, or in other cloud environments, you can use the Update management center in Azure Automation to manage operating system updates, including security patches.", - "training": "https://learn.microsoft.com/azure/automation/update-management/overview", - "waf": "Security" + "text": "Use the premium tier for production workloads.", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "08951710-79a2-492a-adbc-06d7a401545b", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", - "service": "SAP", + "guid": "1b8d68a4-66cd-44d5-ba94-3ee94440e8d6", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region#-route-api-calls-to-regional-backend-services", + "service": "APIM", "services": [ - "WAF", - "SAP" + "AzurePolicy", + "WAF" ], "severity": "Medium", - "text": "Routinely review the SAP security OSS notes because SAP releases highly critical security patches, or hot fixes, that require immediate action to protect your SAP systems.", - "training": "https://support.sap.com/en/my-support/knowledge-base/security-notes-news.html", - "waf": "Security" + "text": "In multi-region model, use Policies to route the requests to regional backends based on availability or latency.", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "1b8b394e-ae64-4a74-8933-357b523ea0a0", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", - "service": "SAP", + "guid": "46f07d33-ef9a-44e8-8f98-67c097c5d8cd", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits#api-management-limits", + "service": "APIM", "services": [ - "SQL", - "WAF", - "SAP" + "APIM", + "Entra", + "WAF" ], - "severity": "Low", - "text": "For SAP on SQL Server, you can disable the SQL Server system administrator account because the SAP systems on SQL Server don't use the account. Ensure that another user with system administrator rights can access the server before disabling the original system administrator account.", - "waf": "Security" + "severity": "High", + "text": "Be aware of APIM's limits", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "5a76a033-ced9-4eef-9a43-5e4f96634c8e", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", - "service": "SAP", + "graph": "resources | where type =~ 'microsoft.apimanagement/service' | extend compliant = (properties.platformVersion != 'stv1') | project id, compliant", + "guid": "46f07d33-ef9a-44e8-8f98-67c097c5d8ce", + "link": "https://learn.microsoft.com/en-us/azure/api-management/migrate-stv1-to-stv2", + "service": "APIM", "services": [ - "SQL", "WAF" ], "severity": "High", - "text": "Disable xp_cmdshell. The SQL Server feature xp_cmdshell enables a SQL Server internal operating system command shell. It's a potential risk in security audits.", - "training": "https://me.sap.com/notes/3019299/E", - "waf": "Security" + "text": "Upgrade the platform version and follow lifecyle. stv1 is retirng on 31 August 2024", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", - "service": "SAP", + "guid": "10f58602-f0f9-4d77-972a-956f6e0f2600", + "link": "https://learn.microsoft.com/en-us/azure/api-management/self-hosted-gateway-overview", + "service": "APIM", "services": [ - "SQL", - "Storage", - "Backup", - "WAF", - "SAP" + "WAF" ], "severity": "High", - "text": "Encrypting SAP HANA database servers on Azure uses SAP HANA native encryption technology. Additionally, if you are using SQL Server on Azure, use Transparent Data Encryption (TDE) to protect your data and log files and ensure that your backups are also encrypted.", - "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", - "waf": "Security" + "text": "Ensure that the self-hosted gateway deployments are resilient.", + "waf": "Reliability" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", - "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", - "service": "SAP", + "guid": "7519e385-a88b-4d34-966b-6269d686e890", + "link": "https://learn.microsoft.com/azure/api-management/front-door-api-management", + "service": "APIM", "services": [ - "Storage", + "FrontDoor", + "APIM", + "Entra", "WAF" ], "severity": "Medium", - "text": "Azure Storage encryption is enabled for all Azure Resource Manager and classic storage accounts, and can't be disabled. Because your data is encrypted by default, you don't need to modify your code or applications to use Azure Storage encryption.", - "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations", - "waf": "Security" + "text": "Use Azure Front Door in front of APIM for multi-region deployment", + "waf": "Performance" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "graph": "Resources | join kind=leftouter (ResourceContainers | where type=~'microsoft.resources/subscriptions' | project SubName=name, subscriptionId) on subscriptionId | where type =~ 'microsoft.keyvault/vaults' | project type, name, SubName", - "guid": "ce9bd3bb-0cdb-43b5-9eb2-ec14eeaa3592", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview", - "service": "SAP", + "guid": "cd45c90e-7690-4753-930b-bf290c69c074", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#virtual-network-integration", + "service": "APIM", "services": [ - "AKV", + "VNet", "WAF" ], - "severity": "High", - "text": "Use Azure Key Vault to store your secrets and credentials", - "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations", + "severity": "Medium", + "text": "Deploy the service within a Virtual Network (VNet)", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "829e2edb-2173-4676-aff6-691b4935ada4", - "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", - "service": "SAP", + "guid": "02661582-b3d1-48d1-9d7b-c6a918a0ca33", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#network-security-group-support", + "service": "APIM", "services": [ - "AzurePolicy", - "RBAC", - "Subscriptions", - "WAF" + "Monitor", + "WAF", + "VNet", + "APIM", + "Entra" ], "severity": "Medium", - "text": "It is recommended to LOCK the Azure Resources post successful deployment to safeguard against unauthorized changes. You can also enforce LOCK constraints and rules on your per-subscription basis using customized Azure policies(Custome role).", - "training": "https://learn.microsoft.com/training/modules/use-azure-resource-manager/?source=recommendations", + "text": "Deploy network security groups (NSG) to your subnets to restrict or monitor traffic to/from APIM.", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "2223ece8-1b12-4318-8a54-17415833fb4a", - "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", - "service": "SAP", + "guid": "67437a28-2721-4a2c-becd-caa54c8237a5", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#azure-private-link", + "service": "APIM", "services": [ - "AKV", - "AzurePolicy", - "WAF" + "WAF", + "VNet", + "PrivateLink", + "APIM", + "Entra" ], "severity": "Medium", - "text": "Provision Azure Key Vault with the soft delete and purge policies enabled to allow retention protection for deleted objects.", - "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations", + "text": "Deploy Private Endpoints to filter incoming traffic when APIM is not deployed to a VNet.", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "e3c2df74-3165-4c3a-abe0-5bbe209d490d", - "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", - "service": "SAP", + "guid": "d698adbd-3288-44cb-b10a-9b572da395ae", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#disable-public-network-access", + "service": "APIM", "services": [ - "AzurePolicy", - "RBAC", "WAF" ], "severity": "High", - "text": "Based on existing requirements, regulatory and compliance controls (internal/external) - Determine what Azure Policies and Azure RBAC role are needed", - "training": "https://learn.microsoft.com/training/paths/describe-azure-management-governance/?source=recommendations", + "text": "Disable Public Network Access", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "a4777842-4d11-4678-9d2f-a56c56ad4840", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", - "service": "SAP", + "guid": "0674d750-0c6f-4ac0-8717-ceec04d0bdbd", + "link": "https://learn.microsoft.com/azure/api-management/automation-manage-api-management", + "service": "APIM", "services": [ - "Storage", - "WAF", - "SAP", - "Defender" + "WAF" ], - "severity": "High", - "text": "When enabling Microsoft Defender for Endpoint on SAP environment, recommend excluding data and log files on DBMS servers instead of targeting all servers. Follow your DBMS vendor's recommendations when excluding target files.", - "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/microsoft-defender-endpoint-mde-for-sap-applications-on-windows/ba-p/3912268", - "waf": "Security" + "severity": "Medium", + "text": "Simplify management with PowerShell automation scripts", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "8fe72734-c486-4ba2-a0dc-0591cf65de8e", - "link": "https://learn.microsoft.com/azure/defender-for-cloud/just-in-time-access-overview?tabs=defender-for-container-arch-aks", - "service": "SAP", + "guid": "c385bfcd-49fd-4786-81ba-cedbb4c57345", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/app-platform/api-management/platform-automation-and-devops#design-recommendations", + "service": "APIM", "services": [ - "RBAC", - "WAF", - "SAP", - "Defender" + "APIM", + "Entra", + "WAF" ], - "severity": "High", - "text": "Delegate an SAP admin custom role with just-in-time access of Microsoft Defender for Cloud.", - "training": "https://learn.microsoft.com/training/modules/secure-vms-with-azure-security-center/?source=recommendations", - "waf": "Security" + "severity": "Medium", + "text": "Configure APIM via Infrastructure-as-code. Review DevOps best practices from the Cloud Adaption Framework APIM Landing Zone Accelerator", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "1309cccd-5792-466b-aca2-75faa1abfe9d", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", - "service": "SAP", + "guid": "6c3a27c0-197f-426c-9ffa-86fed51d9ab6", + "link": "https://learn.microsoft.com/azure/api-management/visual-studio-code-tutorial", + "service": "APIM", "services": [ - "WAF", - "SAP" + "APIM", + "Entra", + "WAF" ], - "severity": "Low", - "text": "encrypt data in transit by integrating the third-party security product with secure network communications (SNC) for DIAG (SAP GUI), RFC, and SPNEGO for HTTPS", - "training": "https://learn.microsoft.com/azure/security/fundamentals/encryption-overview#encryption-of-data-in-transit", - "waf": "Security" + "severity": "Medium", + "text": "Promote usage of Visual Studio Code APIM extension for faster API development", + "waf": "Operations" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", - "link": "https://learn.microsoft.com/azure/storage/common/storage-encryption-key-model-get?tabs=portal", - "service": "SAP", + "guid": "354f1c03-8112-4965-85ad-c0074bddf231", + "link": "https://learn.microsoft.com/azure/api-management/devops-api-development-templates", + "service": "APIM", "services": [ - "AKV", "WAF" ], "severity": "Medium", - "text": "Default to Microsoft-managed keys for principal encryption functionality and use customer-managed keys when required.", - "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations", + "text": "Implement DevOps and CI/CD in your workflow", + "waf": "Operations" + }, + { + "arm-service": "Microsoft.ApiManagement/service", + "checklist": "WAF checklist", + "guid": "b6439493-426a-45f3-9697-cf65baee208d", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-mutual-certificates-for-clients", + "service": "APIM", + "services": [ + "WAF" + ], + "severity": "Medium", + "text": "Secure APIs using client certificate authentication", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "graph": "Resources | join kind=leftouter (ResourceContainers | where type=~'microsoft.resources/subscriptions' | project SubName=name, subscriptionId) on subscriptionId | where type =~ 'microsoft.keyvault/vaults' | project type, name, SubName", - "guid": "4935ada4-2223-4ece-a1b1-23181a541741", - "link": "https://learn.microsoft.com/ja-jp/azure/key-vault/general/best-practices", - "service": "SAP", + "guid": "2a67d143-1033-4c0a-8732-680896478f08", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-mutual-certificates", + "service": "APIM", "services": [ - "AKV", "WAF" ], - "severity": "High", - "text": "Use an Azure Key Vault per application per environment per region.", - "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations", + "severity": "Medium", + "text": "Secure backend services using client certificate authentication", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "abc9634d-c44d-41e9-a530-e8444e16aa3c", - "link": "https://learn.microsoft.com/azure/key-vault/certificates/certificate-scenarios", - "service": "SAP", + "guid": "074435f5-4a46-41ac-b521-d6114cb5d845", + "link": "https://learn.microsoft.com/azure/api-management/mitigate-owasp-api-threats", + "service": "APIM", "services": [ - "AKV", - "WAF", - "SAP" + "WAF" ], - "severity": "High", - "text": "To control and manage disk encryption keys and secrets for non-HANA Windows and non-Windows operating systems, use Azure Key Vault. SAP HANA isn't supported with Azure Key Vault, so you must use alternate methods like SAP ABAP or SSH keys.", - "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/?source=recommendations", + "severity": "Medium", + "text": "Review 'Recommendations to mitigate OWASP API Security Top 10 threats' article and check what is applicable to your APIs", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "209d490d-a477-4784-84d1-16785d2fa56c", - "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles", - "service": "SAP", + "guid": "5507c4b8-a7f8-41d6-9661-418c987100c9", + "link": "https://learn.microsoft.com/azure/api-management/authorizations-overview", + "service": "APIM", "services": [ - "RBAC", - "Subscriptions", - "WAF", - "SAP" + "WAF" ], - "severity": "High", - "text": "Customize role-based access control (RBAC) roles for SAP on Azure spoke subscriptions to avoid accidental network-related changes", - "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations", + "severity": "Medium", + "text": "Use Authorizations feature to simplify management of OAuth 2.0 token for your backend APIs", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", - "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/", - "service": "SAP", + "guid": "2deee033-b906-4bc2-9f26-c8d3699fe091", + "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-manage-protocols-ciphers", + "service": "APIM", "services": [ - "NVA", - "PrivateLink", - "WAF", - "SAP" + "WAF" ], "severity": "High", - "text": "Isolate DMZs and NVAs from the rest of the SAP estate, configure Azure Private Link, and securely manage and control the SAP on Azure resources", - "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal", + "text": "Use the latest TLS version when encrypting information in transit. Disable outdated and unnecessary protocols and ciphers when possible.", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", - "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", - "service": "SAP", + "guid": "f8af3d94-1d2b-4070-846f-849197524258", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#im-8-restrict-the-exposure-of-credential-and-secrets", + "service": "APIM", "services": [ - "VM", - "Storage", + "AKV", "WAF" ], - "severity": "Low", - "text": "Consider using Microsoft anti-malware software on Azure to protect your virtual machines from malicious files, adware, and other threats.", - "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/", + "severity": "High", + "text": "Ensure that secrets (Named values) are stored an Azure Key Vault so they can be securely accessed and updated", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", - "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", - "service": "SAP", + "guid": "791abd8b-7706-4e31-9569-afefde724be3", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#managed-identities", + "service": "APIM", "services": [ - "WAF", - "Defender" + "Entra", + "WAF" ], - "severity": "Low", - "text": "For even more powerful protection, consider using Microsoft Defender for Endpoint.", - "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations", + "severity": "Medium", + "text": "Use managed identities to authenticate to other Azure resources whenever possible", "waf": "Security" }, { + "arm-service": "Microsoft.ApiManagement/service", "checklist": "WAF checklist", - "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", - "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", - "service": "SAP", + "guid": "220c4ca6-6688-476b-b2b5-425a78e6fb87", + "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#ns-6-deploy-web-application-firewall", + "service": "APIM", "services": [ - "VNet", - "WAF", - "SAP" + "AppGW", + "APIM", + "Entra", + "WAF" ], "severity": "High", - "text": "Isolate the SAP application and database servers from the internet or from the on-premises network by passing all traffic through the hub virtual network, which is connected to the spoke network by virtual network peering. The peered virtual networks guarantee that the SAP on Azure solution is isolated from the public internet.", - "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations", + "text": "Use web application firewall (WAF) by deploying Application Gateway in front of APIM", "waf": "Security" }, { + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", - "service": "SAP", + "guid": "43e52f47-22d9-428c-8b1c-d521e54a29a9", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foundations-playbooks-CosmosDB_v1.docx", + "service": "CosmosDB", "services": [ - "WAF", - "SAP" + "WAF" ], - "severity": "Low", - "text": "For internet-facing applications like SAP Fiori, make sure to distribute load per application requirements while maintaining security levels. For Layer 7 security, you can use a third-party Web Application Firewall (WAF) available in the Azure Marketplace.", - "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations", - "waf": "Security" + "severity": "Medium", + "text": "FTA Resiliency Playbook", + "waf": "Reliability" }, { + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", - "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions", - "service": "SAP", + "guid": "de39ac0e-7c28-4dc9-9565-7202bff4564b", + "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#slas", + "service": "CosmosDB", "services": [ - "AKV", - "WAF", - "SAP", - "Monitor" + "WAF" ], - "severity": "Medium", - "text": "To enable secure communication in Azure Monitor for SAP solutions, you can choose to use either a root certificate or a server certificate. We highly recommend that you use root certificates.", - "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations", - "waf": "Security" + "severity": "High", + "text": "Leverage Availablity Zones where regionally applicable and ofcourse if the service offers it", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ServiceBus/namespaces", + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "description": "Azure Service Bus Premium provides encryption of data at rest. If you use your own key, the data is still encrypted using the Microsoft-managed key, but in addition the Microsoft-managed key will be encrypted using the customer-managed key. ", - "guid": "87af4a79-1f89-439b-ba47-768e14c11567", - "link": "https://learn.microsoft.com/azure/service-bus-messaging/configure-customer-managed-key", - "service": "Service Bus", + "guid": "0d934a34-8b26-43e7-bd60-513a3649906e", + "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#replica-outages", + "service": "CosmosDB", "services": [ - "ServiceBus", "WAF" ], - "severity": "Low", - "text": "Use customer-managed key option in data at rest encryption when required", - "training": "https://learn.microsoft.com/learn/modules/plan-implement-administer-conditional-access/", - "waf": "Security" + "severity": "Medium", + "text": "Run multiple replicas of the database (>1 ) in Prod", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ServiceBus/namespaces", + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "description": "Communication between a client application and an Azure Service Bus namespace is encrypted using Transport Layer Security (TLS). Azure Service Bus namespaces permit clients to send and receive data with TLS 1.0 and above. To enforce stricter security measures, you can configure your Service Bus namespace to require that clients send and receive data with a newer version of TLS.", - "guid": "5c1ea55b-46a9-448f-b8ae-7d7e4b475b6c", - "link": "https://learn.microsoft.com/azure/service-bus-messaging/transport-layer-security-enforce-minimum-version", - "service": "Service Bus", + "description": "Multi-region writes capability allows you to take advantage of the provisioned throughput for your databases and containers across the globe", + "guid": "bad38ead-53cc-47de-8d8a-aab3571449ab", + "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#multiple-write-regions", + "service": "CosmosDB", "services": [ - "ServiceBus", + "ACR", "WAF" ], "severity": "Medium", - "text": "Enforce a minimum required version of Transport Layer Security (TLS) for requests ", - "training": "https://learn.microsoft.com/learn/modules/secure-aad-users-with-mfa/", - "waf": "Security" + "text": "Leverage Multi-Region Writes", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ServiceBus/namespaces", + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "description": "When you create a Service Bus namespace, a SAS rule named RootManageSharedAccessKey is automatically created for the namespace. This policy has Manage permissions for the entire namespace. It's recommended that you treat this rule like an administrative root account and don't use it in your application. Using AAD as an authentication provider with RBAC is recommended. ", - "guid": "8bcbf59b-ce65-4de8-a03f-97879468d66a", - "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-sas#shared-access-authorization-policies", - "service": "Service Bus", + "description": "Span Cosmos account across two or more regions with multi-region writes", + "guid": "8153d89f-89dc-47b3-9be2-b1a27f7b9e91", + "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#slas", + "service": "CosmosDB", "services": [ - "Entra", - "ServiceBus", - "TrafficManager", - "AzurePolicy", - "RBAC", + "ACR", "WAF" ], "severity": "Medium", - "text": "Avoid using root account when it is not necessary", - "training": "https://learn.microsoft.com/learn/paths/azure-administrator-manage-identities-governance/", - "waf": "Security" + "text": "Distribute your data globally", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ServiceBus/namespaces", + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "description": "Microsoft Entra ID provides superior security and ease of use over shared access signatures (SAS). With Microsoft Entra ID, there’s no need to store the tokens in your code and risk potential security vulnerabilities. We recommend that you use Microsoft Entra ID with your Azure Service Bus applications when possible.", - "graph": "Resources | where type =~ 'microsoft.servicebus/namespaces' | extend compliant = iif(properties.disableLocalAuth == 'false', 'No', 'Yes') | project id, compliant", - "guid": "786d60f9-6c96-4ad8-a55d-04c2b39c986b", - "link": "https://learn.microsoft.com/en-us/azure/service-bus-messaging/disable-local-authentication", - "service": "Service Bus", + "description": "Choose from various consistency levels such as Eventual, Consistent Prefix, Session, Bounded Staleness and strong", + "guid": "9f8ea848-25ec-4140-bc32-2758e6ee9ac0", + "link": "https://learn.microsoft.com/azure/cosmos-db/consistency-levels", + "service": "CosmosDB", "services": [ - "ServiceBus", - "WAF", - "Entra" + "WAF" ], - "severity": "Medium", - "text": "When possible, disable SAS key authentication (or local authentication) and use only Microsoft Entra ID for authentication", - "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", - "waf": "Security" + "severity": "High", + "text": "Choose from several well-defined consistency models", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ServiceBus/namespaces", + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "description": "When creating permissions, provide fine-grained control over a client's access to Azure Service Bus. Permissions in Azure Service Bus can and should be scoped to the individual resource level e.g. queue, topic or subscription. ", - "guid": "f615658d-e558-4f93-9249-b831112dbd7e", - "link": "https://learn.microsoft.com/azure/service-bus-messaging/authenticate-application#azure-built-in-roles-for-azure-service-bus", - "service": "Service Bus", + "description": "Maintain business continuity during regional outages. Azure Cosmos DB supports service-managed failover during a regional outage. During a regional outage, Azure Cosmos DB continues to maintain its latency, availability, consistency, and throughput SLAs. To help make sure that your entire application is highly available, Azure Cosmos DB offers a manual failover API to simulate a regional outage. By using this API, you can carry out regular business continuity drills.", + "guid": "a47e4d1e-bb79-43f9-bf87-69e1032b72fe", + "link": "https://learn.microsoft.com/azure/cosmos-db/how-to-manage-database-account#automatic-failover", + "service": "CosmosDB", "services": [ - "ServiceBus", - "Storage", - "RBAC", - "Subscriptions", + "CosmosDB", "WAF" ], - "severity": "High", - "text": "Use least privilege data plane RBAC", - "training": "https://learn.microsoft.com/learn/modules/explore-basic-services-identity-types/", - "waf": "Security" + "severity": "Medium", + "text": "Enable Service managed failover", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ServiceBus/namespaces", + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "description": "Azure Service Bus resource logs include operational logs, virtual network and IP filtering logs. Runtime audit logs capture aggregated diagnostic information for various data plane access operations (such as send or receive messages) in Service Bus.", - "guid": "af12e7f9-43f6-4304-922d-929c2b1cd622", - "link": "https://learn.microsoft.com/azure/service-bus-messaging/monitor-service-bus-reference", - "service": "Service Bus", + "description": "Azure Cosmos DB automatically takes backups of your data at regular intervals. The automatic backups are taken without affecting the performance or availability of the database operations. All the backups are stored separately in a storage service.", + "guid": "3499c9c1-133d-42f7-a4b1-a5bd06ff1a90", + "link": "https://learn.microsoft.com/azure/cosmos-db/online-backup-and-restore", + "service": "CosmosDB", "services": [ - "ServiceBus", - "VNet", - "WAF", - "Monitor" + "Storage", + "Backup", + "CosmosDB", + "WAF" ], "severity": "Medium", - "text": "Enable logging for security investigation. Use Azure Monitor to trace resource logs and runtime audit logs (currently available only in the premium tier)", - "training": "https://learn.microsoft.com/learn/paths/manage-identity-and-access/", - "waf": "Security" + "text": "Enable Automatic Backups", + "training": "https://learn.microsoft.com/learn/modules/explore-basic-services-identity-types/", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ServiceBus/namespaces", + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "description": "Azure Service Bus by default has a public IP address and is Internet-reachable. Private endpoints allow traffic between your virtual network and Azure Service Bus traverses over the Microsoft backbone network. In addition to that, you should disable public endpoints if those are not used. ", - "guid": "9ae669ca-48e4-4a85-b222-3ece8bb12307", - "link": "https://learn.microsoft.com/azure/service-bus-messaging/private-link-service", - "service": "Service Bus", + "description": "This mode is the default backup mode for all existing accounts. In this mode, backup is taken at a periodic interval and the data is restored by creating a request with the support team. In this mode, you configure a backup interval and retention for your account. The maximum retention period extends to a month. The minimum backup interval can be one hour.", + "guid": "a6eb33f6-005c-4d92-9286-7655672d6121", + "link": "https://learn.microsoft.com/azure/cosmos-db/periodic-backup-restore-introduction", + "service": "CosmosDB", "services": [ - "ServiceBus", - "PrivateLink", - "VNet", + "Backup", "WAF" ], "severity": "Medium", - "text": "Consider using private endpoints to access Azure Service Bus and disable public network access when applicable.", - "training": "https://learn.microsoft.com/learn/modules/azure-ad-privileged-identity-management/", - "waf": "Security" + "text": "Perform Periodic Backups", + "training": "https://learn.microsoft.com/learn/paths/manage-identity-and-access/", + "waf": "Reliability" }, { - "arm-service": "Microsoft.ServiceBus/namespaces", + "arm-service": "microsoft.documentdb/databaseAccounts", "checklist": "WAF checklist", - "description": "With IP firewall, you can restrict the public endpoint further to only a set of IPv4 addresses or IPv4 address ranges in CIDR (Classless Inter-Domain Routing) notation. ", - "guid": "ca5f06f1-58e3-4ea3-a92c-2de7e2165c3a", - "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-ip-filtering", - "service": "Service Bus", + "description": "Continous 7 day retention and 30 day retention backups. Azure Cosmos DB performs data backup in the background without consuming any extra provisioned throughput (RUs) or affecting the performance and availability of your database. Continuous backups are taken in every region where the account exists.", + "guid": "d43918a8-cd28-49be-b6b1-7cb8245461e1", + "link": "https://learn.microsoft.com/azure/cosmos-db/continuous-backup-restore-introduction", + "service": "CosmosDB", "services": [ - "ServiceBus", + "Backup", + "CosmosDB", "WAF" ], "severity": "Medium", - "text": "Consider only allowing access to Azure Service Bus namespace from specific IP addresses or ranges", - "training": "https://learn.microsoft.com/learn/paths/implement-resource-mgmt-security/", - "waf": "Security" + "text": "Continous Backup with point-in-time restore in Azure Cosmos DB", + "training": "https://learn.microsoft.com/learn/modules/create-custom-azure-roles-with-rbac/", + "waf": "Reliability" }, { + "arm-service": "Microsoft.DBforPostgreSQL/servers", "checklist": "WAF checklist", - "graph": "resources | where type=~'Microsoft.ServiceFabric/managedClusters' | extend compliant = (sku=~'{\"name\":\"Standard\"}') | distinct id,compliant", - "guid": "182840d2-9ef8-4238-8fd6-0d76186830ac", - "link": "https://learn.microsoft.com/azure/service-fabric/overview-managed-cluster#service-fabric-managed-cluster-skus", - "service": "Azure Service Fabric", + "guid": "65285269-441c-44bf-9d3e-0844276d4bdc", + "link": "https://learn.microsoft.com/azure/postgresql/flexible-server/overview", + "service": "PostgreSQL", "services": [ "WAF" ], "severity": "Medium", - "text": "Use Standard SKU for production scenarios.", + "text": "Leverage Flexible Server", "waf": "Reliability" }, { + "arm-service": "Microsoft.DBforPostgreSQL/servers", "checklist": "WAF checklist", - "graph": "resources | where type=~'Microsoft.ServiceFabric/clusters' | extend nodeTypes= array_concat(properties.nodeTypes) | mv-expand nodeTypes | summarize BronzeDurabilityCount = countif(nodeTypes.durabilityLevel == 'Bronze') by id | extend compliant = (BronzeDurabilityCount == 0) | distinct id,compliant", - "guid": "182840d2-9ef8-4238-8fd6-0d76186830ac", - "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-cluster-capacity#durability-characteristics-of-the-cluster", - "service": "Azure Service Fabric", + "guid": "016ccf31-ae5a-41eb-9888-9535e227896d", + "link": "https://learn.microsoft.com/azure/postgresql/flexible-server/overview#architecture-and-high-availability", + "service": "PostgreSQL", "services": [ - "VM", "WAF" ], - "severity": "Medium", - "text": "Use durability level Silver (5 VMs) or greater for production scenarios", + "severity": "High", + "text": "Leverage Availability Zones where regionally applicable", "waf": "Reliability" }, { + "arm-service": "Microsoft.DBforPostgreSQL/servers", "checklist": "WAF checklist", - "graph": "resources | where type=~'Microsoft.ServiceFabric/managedClusters' | extend compliant= ( properties.zonalResiliency =~ 'true') | distinct id,compliant", - "guid": "2363878d-55c4-4cbd-9bc2-94523c85f12e", - "link": "https://learn.microsoft.com/azure/service-fabric/how-to-managed-cluster-availability-zones", - "service": "Azure Service Fabric", + "guid": "31b67c67-be59-4519-8083-845d587cb391", + "link": "https://learn.microsoft.com/azure/postgresql/single-server/concepts-business-continuity#cross-region-read-replicas", + "service": "PostgreSQL", "services": [ - "WAF", - "ACR" + "WAF" ], "severity": "Medium", - "text": "Consider using Availability Zones for your Service Fabric clusters. Service Fabric managed cluster supports deployments that span across multiple Availability Zones to provide zone resiliency. This configuration will ensure high-availability of the critical system services and your applications to protect from single-points-of-failure.", + "text": "Leverage cross-region read replicas for BCDR", "waf": "Reliability" }, { + "arm-service": "Microsoft.Devices/deviceUpdateServices", "checklist": "WAF checklist", - "guid": "5ba74cc8-3ca2-44d5-9a67-bdc8e102e7b4", - "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-api-management-overview", - "service": "Azure Service Fabric", + "guid": "0e03f5ee-4648-423c-bb86-7239480f9171", + "link": "https://learn.microsoft.com/en-us/azure/iot-dps/iot-dps-ha-dr#high-availability", + "service": "Device Update for IoT Hub", "services": [ - "WAF", - "APIM" + "WAF" ], - "severity": "Medium", - "text": "Consider using Azure API Management to expose and offload cross-cutting functionality for APIs hosted on the cluster. API Management can integrate with Service Fabric directly.", + "severity": "High", + "text": "Leverage Availability Zones if regionally applicable (this is automatically enabled).", "waf": "Reliability" }, { + "arm-service": "Microsoft.Devices/deviceUpdateServices", "checklist": "WAF checklist", - "guid": "ef17bb8f-4e2c-488b-8ceb-a07c3d750dd3", - "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-reliable-services-introduction", - "service": "Azure Service Fabric", + "guid": "c0c273bd-00ad-419a-9f2f-fc72fb181e55", + "link": "https://learn.microsoft.com/en-us/azure/iot-dps/iot-dps-ha-dr#high-availability", + "service": "Device Update for IoT Hub", "services": [ "WAF" ], - "severity": "Medium", - "text": "For stateful workload scenarios, consider using Reliable Services. The Reliable Services model allows your services to stay up even in unreliable environments where your machines fail or hit network issues, or in cases where the services themselves encounter errors and crash or fail. For stateful services, your state is preserved even in the presence of network or other failures.", + "severity": "High", + "text": "Be aware of Microsoft-initiated failovers. These are exercised by Microsoft in rare situations to fail over all the DPS instances from an affected region to the corresponding geo-paired region.", "waf": "Reliability" }, { + "arm-service": "Microsoft.Devices/deviceUpdateServices", "checklist": "WAF checklist", - "graph": "resources | where type=~'Microsoft.Compute/virtualMachineScaleSets' | extend vmssExtension= array_concat(properties.virtualMachineProfile.extensionProfile.extensions) | mv-expand vmssExtension | where vmssExtension.properties.publisher matches regex '^Microsoft.Azure.ServiceFabric.*' | summarize arg_max(id, *) | summarize compliant = countif(sku.name matches regex '^Standard_[^d]*$' ) by id", - "guid": "4da21268-f775-4c89-a271-eb80543c8df7", - "service": "Azure Service Fabric", + "guid": "3af8abe6-07eb-4287-b393-6c4abe3702eb", + "link": "https://learn.microsoft.com/en-us/azure/logic-apps/business-continuity-disaster-recovery-guidance?toc=%2Fazure%2Freliability%2Ftoc.json&bc=%2Fazure%2Freliability%2Fbreadcrumb%2Ftoc.json", + "service": "Device Update for IoT Hub", "services": [ - "VM", "WAF" ], - "severity": "Medium", - "text": "Avoid VM SKUs with temp disk offerings. Service Fabric uses managed disks by default, so avoiding temp disk offerings ensures you don't pay for unneeded resources.", - "waf": "Cost" + "severity": "High", + "text": "Consider a Cross-Region DR strategy for critical workloads", + "waf": "Reliability" }, { + "arm-service": "Microsoft.Devices/deviceUpdateServices", "checklist": "WAF checklist", - "guid": "1890b796-f300-41a3-a8d4-29738c1f4ad0", - "link": "https://learn.microsoft.com/azure/service-fabric/how-to-managed-cluster-stateless-node-type#temporary-disk-support", - "service": "Azure Service Fabric", + "guid": "bd91245c-fe32-4e98-a085-794a40f4bfe1", + "link": "https://learn.microsoft.com/en-us/azure/app-service/environment/intro", + "service": "Device Update for IoT Hub", "services": [ - "VM", + "AppSvc", "WAF" ], - "severity": "Medium", - "text": "If you need to select a certain VM SKU for capacity reasons and it happens to offer temp disk, consider using temporary disk support for your stateless workloads.", - "waf": "Cost" + "severity": "High", + "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "5247bb32-6778-49c7-8b40-e171c9a3ce1e", - "service": "Azure Service Fabric", + "guid": "bb235c70-5e17-496f-bedf-a8a4c8cdec4c", + "link": "https://learn.microsoft.com/entra/identity-platform/msal-acquire-cache-tokens", + "service": "Entra", "services": [ + "Entra", "WAF" ], "severity": "Medium", - "text": "Align SKU selection and managed disk size with workload requirements. Matching your selection to your workload demands ensures you don't pay for unneeded resources.", - "waf": "Cost" + "text": "Use long-live revocable token, cache your token and acquire your silently using Microsoft Identity Library", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "6028759b-446a-41bc-8b0e-7728e61ca704", - "link": "https://learn.microsoft.com/azure/service-fabric/how-to-managed-cluster-networking#manage-nsg-rules", - "service": "Azure Service Fabric", + "guid": "503547c1-447e-4c66-828a-71f0f1ce16dd", + "link": "https://learn.microsoft.com/azure/active-directory-b2c/deploy-custom-policies-devops", + "service": "AAD B2C", "services": [ - "VNet", - "WAF", - "APIM" + "WAF" ], "severity": "Medium", - "text": "Ensure Network Security Groups (NSG) are configured to restrict traffic flow between subnets and node types. For example, you may have an API Management instance (one subnet), a frontend subnet (exposing a website directly), and a backend subnet (accessible only to frontend).", - "waf": "Security" + "text": "Make sure that your sign-in user flows are backed up and resilient. Make sure that the code that you use to sign-in your users are backed up and recoverable. Resilient interfaces with external processes", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "graph": "resources | where type=~'Microsoft.Compute/virtualMachineScaleSets' | extend vmssExtension= array_concat(properties.virtualMachineProfile.extensionProfile.extensions) | mv-expand vmssExtension | where vmssExtension.properties.publisher matches regex '^Microsoft.Azure.ServiceFabric.*' | summarize arg_max(id, *) | extend compliant = (isnotnull(properties.virtualMachineProfile.osProfile.secrets))", - "guid": "4e98c903-14cf-4c72-9c45-b8b23bc4cbd8", - "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-best-practices-security#deploy-key-vault-certificates-to-service-fabric-cluster-virtual-machine-scale-sets", - "service": "Azure Service Fabric", + "guid": "3e3553a4-c873-4964-ab66-2d6c15f51296", + "link": "https://learn.microsoft.com/entra/architecture/resilient-end-user-experience#use-a-content-delivery-network", + "service": "AAD B2C", "services": [ - "VM", - "Entra", - "Storage", - "AKV", "WAF" ], "severity": "Medium", - "text": "Deploy Key Vault certificates to Service Fabric cluster virtual machine scale sets. Centralizing storage of application secrets in Azure Key Vault allows you to control their distribution. Key Vault greatly reduces the chances that secrets may be accidentally leaked.", - "waf": "Security" + "text": "Custom brand assets should be hosted on a CDN", + "waf": "Performance" }, { "checklist": "WAF checklist", - "guid": "001cbb6f-d88d-4431-8434-d01333397776", - "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-best-practices-security#apply-an-access-control-list-acl-to-your-certificate-for-your-service-fabric-cluster", - "service": "Azure Service Fabric", + "guid": "5398e6df-d237-4de1-93b1-6c21d79a9b64", + "link": "https://learn.microsoft.com/entra/identity/monitoring-health/reference-sla-performance", + "service": "AAD B2C", "services": [ "WAF" ], - "severity": "Medium", - "text": "Apply an Access Control List (ACL) to your client certificate for your Service Fabric cluster. Using an ACL provides an additional level of authentication.", - "waf": "Security" + "severity": "Low", + "text": "Have multiple identiy providers (i.e., login with your microsoft, google, facebook accounts)", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "4b74b7a5-bb1e-4fca-948c-037ba95fb73b", - "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-resource-governance#resource-governance-mechanism", - "service": "Azure Service Fabric", + "guid": "604489a8-f42d-478e-98c0-7a73b22a4a57", + "link": "https://azure.microsoft.com/blog/setting-up-active-directory-for-a-disaster-recovery-environment-2/", + "service": "Windows AD", "services": [ - "WAF", - "ACR" + "VM", + "WAF" ], "severity": "Medium", - "text": "Use resource requests and limits to govern resource usage across the nodes in your cluster. Enforcing resource limits helps ensure that one service doesn't consume too many resources and starve other services.", - "waf": "Security" + "text": "Follow VM rules for high availability on the VM level (premium disks, two or more in a region, in different availability zones)", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "cd9233ba-f3aa-4353-8d2f-7ea4a64160e6", - "link": "", - "service": "Azure Service Fabric", + "guid": "e7a8dd4a-30e3-47c3-b297-11b2362ceee0", + "link": "https://azure.microsoft.com/blog/setting-up-active-directory-for-a-disaster-recovery-environment-2/", + "service": "Windows AD", "services": [ "WAF" ], "severity": "Medium", - "text": "Encrypt Service Fabric package secret values. Encryption on your secret values provides an additional level of security.", - "waf": "Security" + "text": "Don't replicate! Replication can create issues with directory synchronization", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "44b989d4-9f72-42b6-99da-ec2a79f83299", - "link": "", - "service": "Azure Service Fabric", + "guid": "79b598de-fc59-472c-b4cd-21b078036f5e", + "link": "https://azure.microsoft.com/blog/setting-up-active-directory-for-a-disaster-recovery-environment-2/", + "service": "Windows AD", "services": [ - "AKV", "WAF" ], "severity": "Medium", - "text": "Include client certificates in Service Fabric applications. Having your applications use client certificates for authentication provides opportunities for security at both the cluster and workload level.", - "waf": "Security" + "text": "Have active-active for multi-regions", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "28e66ff7-4a77-4b2c-910d-0335f141208a", - "link": "https://learn.microsoft.com/azure/service-fabric/how-to-managed-identity-managed-cluster-virtual-machine-scale-sets", - "service": "Azure Service Fabric", + "guid": "6b4bfd3d-5035-447c-8447-ec66128a71f0", + "link": "https://learn.microsoft.com/entra/identity/domain-services/tutorial-perform-disaster-recovery-drill", + "service": "Entra", "services": [ - "WAF", - "Entra" + "Entra", + "WAF" ], "severity": "Medium", - "text": "Authenticate Service Fabric applications to Azure Resources using Managed Identity. Using Managed Identity allow you to securely manage the credentials in your code for authenticating to various services without saving them locally on a developer workstation or in source control.", - "waf": "Security" + "text": "Add Azure AD Domain service stamps to additional regions and locations", + "waf": "Reliability" }, { "checklist": "WAF checklist", - "guid": "f16c413c-00a6-43aa-852c-b97292c33a56", - "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-best-practices-security#hosting-untrusted-applications-in-a-service-fabric-cluster", - "service": "Azure Service Fabric", + "guid": "f1ce16dd-3f1d-45e8-92e4-2e3611cc58b4", + "link": "https://learn.microsoft.com/entra/identity/domain-services/tutorial-perform-disaster-recovery-drill", + "service": "Entra", "services": [ "WAF" ], "severity": "Medium", - "text": "Follow Service Fabric best practices when hosting untrusted applications. Following the best practices provides a security standard to follow.", - "waf": "Security" + "text": "Use Replica Sets for DR", + "waf": "Reliability" }, { "category": "Security", @@ -32540,11 +33402,11 @@ "link": "https://learn.microsoft.com/azure/event-hubs/authorize-access-shared-access-signature#shared-access-authorization-policies", "service": "Event Hubs", "services": [ + "EventHubs", "Entra", + "RBAC", "TrafficManager", - "EventHubs", - "AzurePolicy", - "RBAC" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -32560,11 +33422,11 @@ "link": "https://learn.microsoft.com/azure/event-hubs/authenticate-managed-identity?tabs=latest", "service": "Event Hubs", "services": [ - "VM", - "Entra", - "Storage", + "AKV", "EventHubs", - "AKV" + "Storage", + "VM", + "Entra" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -32580,9 +33442,9 @@ "link": "https://learn.microsoft.com/azure/event-hubs/authorize-access-azure-active-directory#azure-built-in-roles-for-azure-event-hubs", "service": "Event Hubs", "services": [ - "RBAC", "EventHubs", - "Entra" + "Entra", + "RBAC" ], "severity": "High", "subcategory": "Identity and Access Management", @@ -32598,9 +33460,9 @@ "link": "https://learn.microsoft.com/azure/event-hubs/monitor-event-hubs-reference", "service": "Event Hubs", "services": [ - "VNet", "EventHubs", - "Monitor" + "Monitor", + "VNet" ], "severity": "Medium", "subcategory": "Monitoring", @@ -32617,8 +33479,8 @@ "service": "Event Hubs", "services": [ "PrivateLink", - "VNet", - "EventHubs" + "EventHubs", + "VNet" ], "severity": "Medium", "subcategory": "Networking", @@ -32664,8 +33526,8 @@ "link": "https://learn.microsoft.com/azure/event-hubs/event-hubs-premium-overview#high-availability-with-availability-zones", "service": "Event Hubs", "services": [ - "EventHubs", - "ACR" + "ACR", + "EventHubs" ], "severity": "High", "subcategory": "Zone Redudancy", @@ -32942,10 +33804,10 @@ "link": "https://learn.microsoft.com/azure/service-fabric/service-fabric-best-practices-security#deploy-key-vault-certificates-to-service-fabric-cluster-virtual-machine-scale-sets", "service": "Azure Service Fabric", "services": [ - "AKV", "Storage", - "VM", - "Entra" + "AKV", + "Entra", + "VM" ], "severity": "Medium", "subcategory": "Cluster architecture", @@ -33049,9 +33911,9 @@ "link": "https://learn.microsoft.com/azure/architecture/web-apps/spring-apps/architectures/spring-apps-multi-region", "service": "Spring Apps", "services": [ - "TrafficManager", "ASR", - "FrontDoor" + "FrontDoor", + "TrafficManager" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -33247,8 +34109,8 @@ "guid": "338ee253-c17d-432e-aaaa-b7571549ab81", "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-outages-disasters#availability-zones", "services": [ - "ServiceBus", - "ACR" + "ACR", + "ServiceBus" ], "severity": "High", "subcategory": "Best Practices", @@ -33263,8 +34125,8 @@ "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-outages-disasters#geo-disaster-recovery", "services": [ "ServiceBus", - "Storage", - "ASR" + "ASR", + "Storage" ], "severity": "Medium", "subcategory": "Geo-Disaster Recovery", @@ -33278,9 +34140,9 @@ "guid": "1f38c403-a822-4c24-93cf-0f18ac699ef1", "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-federation-overview", "services": [ + "ACR", "ServiceBus", - "ASR", - "ACR" + "ASR" ], "severity": "Medium", "subcategory": "Geo-Disaster Recovery", @@ -33334,9 +34196,9 @@ "guid": "4a69b9d3-39ac-44e7-a68d-1d75657202b4", "link": "https://learn.microsoft.com/azure/well-architected/service-guides/service-bus/reliability#checklist", "services": [ + "PrivateLink", "ServiceBus", - "Storage", - "PrivateLink" + "Storage" ], "severity": "Medium", "subcategory": "Best Practices", @@ -33397,10 +34259,10 @@ "service": "Service Bus", "services": [ "Entra", - "ServiceBus", + "RBAC", "TrafficManager", - "AzurePolicy", - "RBAC" + "ServiceBus", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -33434,11 +34296,11 @@ "link": "https://learn.microsoft.com/azure/service-bus-messaging/authenticate-application#azure-built-in-roles-for-azure-service-bus", "service": "Service Bus", "services": [ - "Entra", - "ServiceBus", "Storage", "RBAC", - "Subscriptions" + "Subscriptions", + "ServiceBus", + "Entra" ], "severity": "High", "subcategory": "Identity and Access Management", @@ -33455,8 +34317,8 @@ "service": "Service Bus", "services": [ "ServiceBus", - "VNet", - "Monitor" + "Monitor", + "VNet" ], "severity": "Medium", "subcategory": "Monitoring", @@ -33551,8 +34413,8 @@ "guid": "32d41e36-11c8-417b-8afb-c410d4391898", "service": "Azure Synapse Analytics", "services": [ - "SQL", - "Entra" + "Entra", + "SQL" ], "severity": "High", "subcategory": "", @@ -33581,8 +34443,8 @@ "guid": "ec823923-7a15-42d6-ac5e-402925388e5d", "service": "Azure Synapse Analytics", "services": [ - "AzurePolicy", - "Entra" + "Entra", + "AzurePolicy" ], "severity": "High", "subcategory": "", @@ -33597,8 +34459,8 @@ "link": "https://learn.microsoft.com/azure/synapse-analytics/security/synapse-workspace-understand-what-role-you-need", "service": "Azure Synapse Analytics", "services": [ - "RBAC", "Storage", + "RBAC", "Monitor", "Entra" ], @@ -33614,8 +34476,8 @@ "link": "https://learn.microsoft.com/sql/relational-databases/security/row-level-security?view=sql-server-ver16&context=%2Fazure%2Fsynapse-analytics%2Fcontext%2Fcontext", "service": "Azure Synapse Analytics", "services": [ - "SQL", - "Entra" + "Entra", + "SQL" ], "severity": "Medium", "subcategory": "", @@ -33742,12 +34604,14 @@ "description": "You can store credentials or secret values in an Azure Key Vault and use them during pipeline execution to pass to your activities.", "guid": "a3aec2c4-e243-46b0-936d-b55e17960eee", "link": "https://learn.microsoft.com/azure/data-factory/how-to-use-azure-key-vault-secrets-pipeline-activities", + "service": "Azure Data Factory", "services": [ "AKV" ], "severity": "Medium", "subcategory": "", - "text": "Use Azure Key Vault secrets in pipeline activities" + "text": "Use Azure Key Vault secrets in pipeline activities", + "waf": "Security" }, { "category": "Identity and Access Management", @@ -33785,8 +34649,8 @@ "guid": "4350d092-d234-4292-a752-8537a551c5bf", "service": "Azure Data Factory", "services": [ - "AzurePolicy", - "Entra" + "Entra", + "AzurePolicy" ], "severity": "High", "subcategory": "", @@ -33801,7 +34665,8 @@ "services": [], "severity": "Medium", "subcategory": "", - "text": "Disable access over public internet and configure either firewall rules or trusted services rules" + "text": "Disable access over public internet and configure either firewall rules or trusted services rules", + "waf": "Security" }, { "category": "Network Security", @@ -33841,8 +34706,8 @@ "service": "Azure Data Factory", "services": [ "PrivateLink", - "VNet", - "EventHubs" + "EventHubs", + "VNet" ], "severity": "Medium", "subcategory": "", @@ -33855,13 +34720,15 @@ "description": "By using Azure Private Link, you can connect to various platform as a service (PaaS) deployments in Azure via a private endpoint. A private endpoint is a private IP address within a specific virtual network and subnet", "guid": "b47a393a-0804-4272-a479-8b1578b219a4", "link": "https://learn.microsoft.com/azure/data-factory/data-factory-private-link", + "service": "Azure Data Factory", "services": [ "PrivateLink", "VNet" ], "severity": "Medium", "subcategory": "", - "text": "Configure Private Links to connect to sources in customer Vnet and data factory" + "text": "Configure Private Links to connect to sources in customer Vnet and data factory", + "waf": "Security" }, { "category": "Data Protection", @@ -33932,7 +34799,8 @@ ], "severity": "Medium", "subcategory": "", - "text": "Use Azure Key Vault secrets in pipeline activities" + "text": "Use Azure Key Vault secrets in pipeline activities", + "waf": "Security" }, { "category": "Data Protection", @@ -33944,7 +34812,8 @@ "services": [], "severity": "Medium", "subcategory": "", - "text": "Encrypt credentials for on-premises using SHIR data stores in Azure Data Factory" + "text": "Encrypt credentials for on-premises using SHIR data stores in Azure Data Factory", + "waf": "Security" }, { "category": "Identity and Access Management", @@ -33969,8 +34838,8 @@ "service": "Microsoft Purview", "services": [ "RBAC", - "Subscriptions", - "Entra" + "Entra", + "Subscriptions" ], "severity": "Medium", "subcategory": "", @@ -34095,8 +34964,8 @@ "service": "Microsoft Purview", "services": [ "VM", - "VNet", - "PrivateLink" + "PrivateLink", + "VNet" ], "severity": "Medium", "subcategory": "", @@ -34183,8 +35052,8 @@ "guid": "7f3165c3-a87a-405b-9a20-9949bda47778", "service": "Microsoft Purview", "services": [ - "RBAC", - "Storage" + "Storage", + "RBAC" ], "severity": "Medium", "subcategory": "", @@ -34248,8 +35117,8 @@ "link": "https://learn.microsoft.com/entra/identity/role-based-access-control/security-emergency-access", "service": "Microsoft Purview", "services": [ - "Subscriptions", - "Entra" + "Entra", + "Subscriptions" ], "severity": "Medium", "subcategory": "", @@ -34351,10 +35220,10 @@ "guid": "11cc57b4-a4b1-4410-b43a-58a9c2289b3d", "service": "Azure Databricks", "services": [ - "SQL", + "EventHubs", "Entra", "Storage", - "EventHubs", + "SQL", "AzurePolicy" ], "severity": "Medium", @@ -34368,12 +35237,14 @@ "description": "Account admins can configure a workspace setting called RestrictWorkspaceAdmins to restrict workspace admins to only change a job owner to themselves and the job run as setting to a service principal that they have the Service Principal User role on.", "guid": "6b57dfc6-5546-41e1-a3e3-453a3c863964", "link": "https://learn.microsoft.com/azure/databricks/admin/workspace-settings/restrict-workspace-admins", + "service": "Azure Databricks", "services": [ "RBAC" ], "severity": "High", "subcategory": "", - "text": "Restrict workspace admins" + "text": "Restrict workspace admins", + "waf": "Security" }, { "category": "Identity and Access Management", @@ -34399,7 +35270,8 @@ ], "severity": "High", "subcategory": "", - "text": "Regenerate/rotate keys if using them periodically" + "text": "Regenerate/rotate keys if using them periodically", + "waf": "Security" }, { "category": "Identity and Access Management", @@ -34469,10 +35341,10 @@ "link": "https://learn.microsoft.com/azure/databricks/security/keys/customer-managed-keys", "service": "Azure Databricks", "services": [ - "AKV", "Storage", - "SQL", - "Backup" + "AKV", + "Backup", + "SQL" ], "severity": "Medium", "subcategory": "", @@ -34633,12 +35505,12 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "App Gateway", "services": [ - "AppGW", - "Entra", - "NVA", "VNet", + "NVA", "Subscriptions", - "WAF" + "AppGW", + "WAF", + "Entra" ], "severity": "Medium", "subcategory": "App Gateway", @@ -34683,8 +35555,8 @@ "link": "https://learn.microsoft.com/azure/reliability/migrate-app-gateway-v2", "service": "App Gateway", "services": [ - "AppGW", - "ACR" + "ACR", + "AppGW" ], "severity": "Medium", "subcategory": "App Gateway", @@ -34700,9 +35572,9 @@ "service": "Front Door", "services": [ "AppGW", + "FrontDoor", "AzurePolicy", - "WAF", - "FrontDoor" + "WAF" ], "severity": "Medium", "subcategory": "App delivery", @@ -34935,8 +35807,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/best-practices#send-logs-to-microsoft-sentinel", "service": "App Gateway", "services": [ - "AppGW", "Sentinel", + "AppGW", "WAF" ], "severity": "Medium", @@ -35354,8 +36226,8 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance", "service": "Key Vault", "services": [ - "AKV", - "ACR" + "ACR", + "AKV" ], "severity": "Medium", "subcategory": "High Availability", @@ -35398,10 +36270,10 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#design-considerations", "service": "Key Vault", "services": [ - "Storage", + "AKV", "ASR", "Backup", - "AKV", + "Storage", "Subscriptions" ], "severity": "Medium", @@ -35416,8 +36288,8 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", "service": "Key Vault", "services": [ - "AKV", - "ASR" + "ASR", + "AKV" ], "severity": "High", "subcategory": "Business continuity and disaster recovery", @@ -35431,8 +36303,8 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", "service": "Key Vault", "services": [ - "AKV", - "ASR" + "ASR", + "AKV" ], "severity": "Low", "subcategory": "Business continuity and disaster recovery", @@ -35446,8 +36318,8 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#limitations", "service": "Key Vault", "services": [ - "AKV", "ASR", + "AKV", "Backup" ], "severity": "Low", @@ -35462,8 +36334,8 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/backup?tabs=azure-cli#limitations", "service": "Key Vault", "services": [ - "AKV", "ASR", + "AKV", "Backup" ], "severity": "Low", @@ -35478,8 +36350,8 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview#purge-protection", "service": "Key Vault", "services": [ - "AKV", "ASR", + "AKV", "EventHubs" ], "severity": "Medium", @@ -35496,8 +36368,8 @@ "service": "Key Vault", "services": [ "AKV", - "RBAC", - "Entra" + "Entra", + "RBAC" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -35511,9 +36383,9 @@ "guid": "56c57ba5-9119-4bf8-b8f5-c586c7d9cdc1", "link": "https://azure.microsoft.com/support/legal/sla/virtual-desktop/v1_0/", "services": [ - "AVD", "VM", "ASR", + "AVD", "Subscriptions" ], "severity": "High", @@ -35528,10 +36400,10 @@ "guid": "6acc076e-f9b1-441a-a989-579e76b897e7", "link": "https://learn.microsoft.com/azure/architecture/example-scenario/wvd/azure-virtual-desktop-multi-region-bcdr", "services": [ - "VM", - "AVD", "Storage", - "ASR" + "ASR", + "AVD", + "VM" ], "severity": "Medium", "subcategory": "Compute", @@ -35545,8 +36417,8 @@ "guid": "10a7da7b-e996-46e1-9d3c-4ada97cc3d13", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ - "AVD", - "ASR" + "ASR", + "AVD" ], "severity": "Low", "subcategory": "Compute", @@ -35560,9 +36432,9 @@ "guid": "25ab225c-6f4e-4168-9fdd-dea8a4b7cdeb", "link": "https://techcommunity.microsoft.com/t5/azure-virtual-desktop-blog/announcing-general-availability-of-support-for-azure/ba-p/3636262", "services": [ - "AVD", + "ACR", "ASR", - "ACR" + "AVD" ], "severity": "High", "subcategory": "Compute", @@ -35576,9 +36448,9 @@ "guid": "4c61fc3f-c14e-4ea6-b69e-8d9a3eec218e", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ - "AVD", - "VM", "ASR", + "VM", + "AVD", "Backup" ], "severity": "Medium", @@ -35593,11 +36465,11 @@ "guid": "5da58639-ca3a-4961-890b-29663c5e10d", "link": "https://learn.microsoft.com/azure/site-recovery/azure-to-azure-how-to-enable-zone-to-zone-disaster-recovery", "services": [ - "VM", - "Cost", "AVD", + "Cost", "ASR", - "Backup" + "Backup", + "VM" ], "severity": "Medium", "subcategory": "Compute", @@ -35611,11 +36483,11 @@ "guid": "dd2e0d5d-771d-441e-9610-cc57b4a4a141", "link": "https://learn.microsoft.com/azure/virtual-machines/azure-compute-gallery", "services": [ - "VM", "ACR", "AVD", + "ASR", "Storage", - "ASR" + "VM" ], "severity": "Low", "subcategory": "Dependencies", @@ -35629,8 +36501,8 @@ "guid": "fd339489-8c12-488b-9c6a-57cfb644451e", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ - "AVD", - "ASR" + "ASR", + "AVD" ], "severity": "Medium", "subcategory": "Dependencies", @@ -35644,9 +36516,9 @@ "guid": "687ab077-adb5-49e5-a960-3334fdf8cc23", "link": "https://docs.microsoft.com/fslogix/manage-profile-content-cncpt", "services": [ - "AVD", "Storage", - "ASR" + "ASR", + "AVD" ], "severity": "Medium", "subcategory": "Storage", @@ -35661,9 +36533,9 @@ "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ "AVD", - "Storage", - "ASR", "Backup", + "ASR", + "Storage", "AzurePolicy" ], "severity": "Medium", @@ -35678,9 +36550,9 @@ "guid": "9f7547c1-746d-4c56-868a-714435bd09dd", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ - "AVD", "Storage", - "ASR" + "ASR", + "AVD" ], "severity": "Medium", "subcategory": "Storage", @@ -35694,9 +36566,9 @@ "guid": "3d4f3537-c134-46dc-9602-7a71efe1bd05", "link": "https://docs.microsoft.com/azure/backup/backup-afs", "services": [ - "AVD", "Storage", "ASR", + "AVD", "Backup" ], "severity": "Medium", @@ -35711,9 +36583,9 @@ "guid": "10d4e875-d502-4142-a795-f2b6eff34f88", "link": "https://learn.microsoft.com/azure/storage/files/files-redundancy#zone-redundant-storage", "services": [ - "AVD", "Storage", - "ASR" + "ASR", + "AVD" ], "severity": "High", "subcategory": "Storage", @@ -35729,9 +36601,9 @@ "services": [ "ACR", "AVD", - "Storage", "ASR", - "Backup" + "Backup", + "Storage" ], "severity": "Medium", "subcategory": "Storage", @@ -35787,9 +36659,9 @@ "guid": "5a2adb2c-3e23-426b-b225-ca44e1696fdd", "link": "https://learn.microsoft.com/azure/virtual-machines/shared-image-galleries", "services": [ + "Storage", "VM", - "AVD", - "Storage" + "AVD" ], "severity": "Low", "subcategory": "Golden Images", @@ -35845,8 +36717,8 @@ "guid": "829e3fec-2183-4687-a017-7a2b5945bda4", "link": "https://github.com/The-Virtual-Desktop-Team/Virtual-Desktop-Optimization-Tool", "services": [ - "AVD", - "RBAC" + "RBAC", + "AVD" ], "severity": "Low", "subcategory": "Golden Images", @@ -35860,8 +36732,8 @@ "guid": "e3d3e084-4276-4d4b-bc01-5bcf219e4a1e", "link": "https://learn.microsoft.com/azure/virtual-desktop/install-office-on-wvd-master-image#install-onedrive-in-per-machine-mode", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Low", "subcategory": "Golden Images", @@ -35903,9 +36775,9 @@ "guid": "90083845-c587-4cb3-a1ec-16a1d076ef9f", "link": "https://docs.microsoft.com/azure/virtual-desktop/app-attach-file-share", "services": [ - "AVD", + "Cost", "Storage", - "Cost" + "AVD" ], "severity": "Medium", "subcategory": "MSIX & AppAttach", @@ -35933,10 +36805,10 @@ "guid": "66e15d4d-5a2a-4db2-a3e2-326bf225ca41", "link": "https://docs.microsoft.com/azure/virtual-desktop/app-attach-file-share", "services": [ + "Storage", "VM", "AVD", - "RBAC", - "Storage" + "RBAC" ], "severity": "Medium", "subcategory": "MSIX & AppAttach", @@ -35992,8 +36864,8 @@ "guid": "e4633254-3185-40a1-b120-bd563a1c8e9d", "link": "https://docs.microsoft.com/azure/virtual-machines/generation-2", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "Medium", "subcategory": "Session Host", @@ -36021,8 +36893,8 @@ "guid": "8468c55a-775c-46ee-a5b8-6ad8844ce3b2", "link": "https://learn.microsoft.com/azure/virtual-desktop/terminology#host-pools", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -36036,8 +36908,8 @@ "guid": "4e98495f-d3c0-4af2-aa59-a793395a32a7", "link": "https://learn.microsoft.com/azure/virtual-desktop/terminology?WT.mc_id=Portal-fx#host-pools", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -36079,8 +36951,8 @@ "guid": "b3724959-4943-4577-a3a9-e10ff6345f24", "link": "https://learn.microsoft.com/windows-server/remote/remote-desktop-services/virtual-machine-recs", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "Medium", "subcategory": "Capacity Planning", @@ -36094,8 +36966,8 @@ "guid": "b384b7ed-1cdd-457e-a2cd-c8d4d55bc144", "link": "https://learn.microsoft.com/azure/virtual-desktop/terminology?WT.mc_id=Portal-fx#application-groups", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -36109,8 +36981,8 @@ "guid": "971cc4a4-b1f7-4c12-90e0-1ad96808f00c", "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-virtual-desktop-service-limits", "services": [ - "AVD", "ACR", + "AVD", "Entra" ], "severity": "Medium", @@ -36139,9 +37011,9 @@ "guid": "38b19ab6-0693-4992-9394-5590883916ec", "link": "https://learn.microsoft.com/azure/virtual-desktop/configure-host-pool-personal-desktop-assignment-type?tabs=azure#reassign-a-personal-desktop", "services": [ + "Storage", "VM", - "AVD", - "Storage" + "AVD" ], "severity": "Low", "subcategory": "Capacity Planning", @@ -36155,8 +37027,8 @@ "guid": "e1112dbd-7ba0-412e-9b94-ef6e047d2ea2", "link": "https://docs.microsoft.com/windows-server/remote/remote-desktop-services/virtual-machine-recs", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -36170,8 +37042,8 @@ "guid": "992b1cd6-d2f5-44b2-a769-e3a691e8838a", "link": "https://learn.microsoft.com/azure/architecture/example-scenario/wvd/windows-virtual-desktop#considerations", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -36199,8 +37071,8 @@ "guid": "b47a393a-0803-4272-a479-8b1578b219a4", "link": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "Low", "subcategory": "Capacity Planning", @@ -36228,9 +37100,9 @@ "guid": "6abca2a4-fda1-4dbf-9dc9-5d48c7c791dc", "link": "https://learn.microsoft.com/azure/architecture/example-scenario/wvd/windows-virtual-desktop?toc=%2Fazure%2Fvirtual-desktop%2Ftoc.json&bc=%2Fazure%2Fvirtual-desktop%2Fbreadcrumb%2Ftoc.json", "services": [ - "AVD", - "Storage", "ExpressRoute", + "Storage", + "AVD", "VPN" ], "severity": "Medium", @@ -36315,9 +37187,9 @@ "guid": "8053d89e-89dc-47b3-9be2-a1a27f7a9e91", "link": "https://docs.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits", "services": [ - "AVD", + "Storage", "VM", - "Storage" + "AVD" ], "severity": "Low", "subcategory": "General", @@ -36331,10 +37203,10 @@ "guid": "c14aea7e-65e8-4d9a-9aec-218e6436b073", "link": "https://docs.microsoft.com/azure/architecture/reference-architectures/identity/adds-extend-domain", "services": [ - "AVD", "Storage", - "VNet", - "Entra" + "AVD", + "Entra", + "VNet" ], "severity": "Medium", "subcategory": "Active Directory", @@ -36393,8 +37265,8 @@ "guid": "347dc560-28a7-41ff-b1cd-15dd2f0d5e77", "link": "https://learn.microsoft.com/azure/virtual-desktop/prerequisites?tabs=portal#session-hosts", "services": [ - "AVD", "VM", + "AVD", "Entra" ], "severity": "Medium", @@ -36424,9 +37296,9 @@ "guid": "2289b3d6-b57c-4fc6-9546-1e1a3e3453a3", "link": "https://docs.microsoft.com/azure/storage/files/storage-files-identity-ad-ds-enable", "services": [ - "AzurePolicy", - "AVD", "Storage", + "AVD", + "AzurePolicy", "Entra" ], "severity": "High", @@ -36456,8 +37328,8 @@ "guid": "e777fd5e-c5f1-4d6e-8fa9-fc210b88e338", "link": "https://learn.microsoft.com/azure/storage/files/storage-files-identity-auth-hybrid-identities-enable", "services": [ - "AVD", "Storage", + "AVD", "Entra" ], "severity": "Medium", @@ -36474,8 +37346,8 @@ "services": [ "VNet", "AVD", - "Subscriptions", - "Entra" + "Entra", + "Subscriptions" ], "severity": "High", "subcategory": "Requirements", @@ -36534,8 +37406,8 @@ "guid": "ea962a15-9394-46da-a7cc-3923266b2258", "link": "https://learn.microsoft.com/azure/virtual-desktop/prerequisites?tabs=portal#supported-identity-scenarios", "services": [ - "AVD", "VM", + "AVD", "Entra" ], "severity": "High", @@ -36581,8 +37453,8 @@ "guid": "3334fdf9-1c23-4418-8b65-285269440b4b", "link": "https://learn.microsoft.com/azure/virtual-desktop/management", "services": [ - "AVD", "VM", + "AVD", "Monitor" ], "severity": "Low", @@ -36612,10 +37484,10 @@ "guid": "7138b820-102c-4e16-be30-1e6e872e52e3", "link": "https://learn.microsoft.com/azure/virtual-desktop/autoscale-scenarios", "services": [ - "AVD", + "Cost", "VM", - "Monitor", - "Cost" + "AVD", + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -36629,10 +37501,10 @@ "guid": "55f612fe-f215-4f0d-a956-10e7dd96bcbc", "link": "https://learn.microsoft.com/azure/virtual-desktop/start-virtual-machine-connect", "services": [ - "AVD", + "Cost", "VM", - "Monitor", - "Cost" + "AVD", + "Monitor" ], "severity": "Low", "subcategory": "Management", @@ -36646,11 +37518,11 @@ "guid": "79a686ea-d971-4ea0-a9a8-1aea074c94cb", "link": "https://learn.microsoft.com/azure/virtual-desktop/start-virtual-machine-connect-faq#are-vms-automatically-deallocated-when-a-user-stops-using-them", "services": [ - "VM", - "Cost", "AVD", - "AzurePolicy", - "Monitor" + "Monitor", + "Cost", + "VM", + "AzurePolicy" ], "severity": "Low", "subcategory": "Management", @@ -36664,14 +37536,14 @@ "guid": "51bcafca-476a-48fa-9b91-9645a7679f20", "link": "https://learn.microsoft.com/azure/virtual-desktop/tag-virtual-desktop-resources", "services": [ - "VPN", + "ExpressRoute", + "AVD", + "Monitor", "Cost", "VWAN", - "DNS", - "AVD", "Storage", - "ExpressRoute", - "Monitor" + "VPN", + "DNS" ], "severity": "Low", "subcategory": "Management", @@ -36685,9 +37557,9 @@ "guid": "611dd68c-5a4b-4252-8e44-a59a9c2399c4", "link": "https://learn.microsoft.com/azure/virtual-desktop/azure-advisor-recommendations", "services": [ - "AVD", - "Monitor", "Cost", + "Monitor", + "AVD", "Entra" ], "severity": "Low", @@ -36732,8 +37604,8 @@ "guid": "d1e8c38e-c936-4667-913c-005674b1e944", "link": "https://docs.microsoft.com/azure/virtual-desktop/create-validation-host-pool", "services": [ - "AVD", "VM", + "AVD", "Monitor" ], "severity": "Medium", @@ -36748,8 +37620,8 @@ "guid": "a459c373-e7ed-4616-83b3-65a917ecbe48", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/wvd/eslz-platform-automation-and-devops", "services": [ - "AVD", "VM", + "AVD", "Monitor" ], "severity": "Medium", @@ -36764,8 +37636,8 @@ "guid": "ebe54cd7-df2e-48bb-ac35-81559bb9153e", "link": "https://docs.microsoft.com/azure/virtual-desktop/faq", "services": [ - "AVD", "VM", + "AVD", "Monitor" ], "severity": "Medium", @@ -36795,8 +37667,8 @@ "guid": "81770afb-c4c0-4e43-a186-58d2857ed671", "link": "https://docs.microsoft.com/azure/virtual-desktop/diagnostics-log-analytics", "services": [ - "AVD", "VM", + "AVD", "Monitor" ], "severity": "Medium", @@ -36811,8 +37683,8 @@ "guid": "2463cffe-179c-4599-be0d-5973dd4ce32c", "link": "https://docs.microsoft.com/azure/storage/files/storage-files-monitoring?tabs=azure-portal", "services": [ - "AVD", "Storage", + "AVD", "Monitor" ], "severity": "Medium", @@ -36844,8 +37716,8 @@ "services": [ "NVA", "AVD", - "ExpressRoute", - "VPN" + "VPN", + "ExpressRoute" ], "severity": "Medium", "subcategory": "Networking", @@ -36859,8 +37731,8 @@ "guid": "c8639648-a652-4d6c-85e5-02965388e5de", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/wvd/eslz-network-topology-and-connectivity", "services": [ - "AVD", "VWAN", + "AVD", "VNet" ], "severity": "Medium", @@ -36891,8 +37763,8 @@ "link": "https://docs.microsoft.com/azure/firewall/protect-windows-virtual-desktop", "services": [ "NVA", - "AVD", "Firewall", + "AVD", "VNet" ], "severity": "Medium", @@ -36921,8 +37793,8 @@ "guid": "73676ae4-6691-4e88-95ad-a42223e13810", "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/onboard-windows-multi-session-device?view=o365-worldwide", "services": [ - "AVD", - "Defender" + "Defender", + "AVD" ], "severity": "Medium", "subcategory": "Networking", @@ -36937,8 +37809,8 @@ "link": "https://docs.microsoft.com/azure/firewall/protect-windows-virtual-desktop", "services": [ "NVA", - "AVD", "Firewall", + "AVD", "VNet" ], "severity": "Low", @@ -36953,8 +37825,8 @@ "guid": "cc6edca0-aeca-4566-9e92-cf246f1465af", "link": "https://learn.microsoft.com/azure/virtual-desktop/proxy-server-support", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "High", "subcategory": "Networking", @@ -36968,8 +37840,8 @@ "guid": "516785c6-fa96-4c96-ad88-408f372734c8", "link": "https://learn.microsoft.com/azure/virtual-desktop/rdp-bandwidth", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "Low", "subcategory": "Networking", @@ -36983,11 +37855,11 @@ "guid": "ec27d589-9178-426d-8df2-ff60020f30a6", "link": "https://learn.microsoft.com/azure/storage/files/storage-files-networking-endpoints", "services": [ - "Cost", "AVD", + "Cost", "Storage", - "PrivateLink", - "VNet" + "VNet", + "PrivateLink" ], "severity": "Medium", "subcategory": "Networking", @@ -37030,8 +37902,8 @@ "guid": "b1172576-9ef6-4691-a483-5ac932223ece", "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/deployment-vdi-microsoft-defender-antivirus", "services": [ - "AVD", - "Defender" + "Defender", + "AVD" ], "severity": "High", "subcategory": "Host Configuration", @@ -37045,9 +37917,9 @@ "guid": "0fd32907-98bc-4178-adc5-a06ca7144351", "link": "https://learn.microsoft.com/azure/virtual-machines/disk-encryption-overview", "services": [ + "Storage", "AKV", "AVD", - "Storage", "VM" ], "severity": "Low", @@ -37062,8 +37934,8 @@ "guid": "36a5a67f-bb9e-4d5b-9547-8c4479816b28", "link": "https://learn.microsoft.com/azure/virtual-desktop/security-guide#azure-virtual-desktop-support-for-trusted-launch", "services": [ - "AVD", "VM", + "AVD", "Monitor" ], "severity": "Medium", @@ -37078,8 +37950,8 @@ "guid": "135d3899-4b31-44d3-bc8f-028871a359d8", "link": "https://learn.microsoft.com/windows/whats-new/windows-11-requirements", "services": [ - "AVD", - "VM" + "VM", + "AVD" ], "severity": "High", "subcategory": "Host Configuration", @@ -37135,8 +38007,8 @@ "guid": "e19dd344-29eb-4722-a237-a151c5bb4e4f", "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/web-protection-overview", "services": [ - "AVD", - "Defender" + "Defender", + "AVD" ], "severity": "Medium", "subcategory": "Management", @@ -37164,12 +38036,12 @@ "guid": "1814387e-5ca9-4c26-a9b3-2ab5bdfc6998", "link": "https://learn.microsoft.com/azure/virtual-desktop/security-guide#enable-microsoft-defender-for-cloud", "services": [ - "VM", - "Defender", "AVD", - "Storage", + "Defender", "AKV", - "Subscriptions" + "Storage", + "Subscriptions", + "VM" ], "severity": "Medium", "subcategory": "Management", @@ -37199,8 +38071,8 @@ "guid": "baaab757-1849-4ab8-893d-c9fc9d1bb73b", "link": "https://docs.microsoft.com/azure/virtual-desktop/rbac", "services": [ - "AVD", "RBAC", + "AVD", "Entra" ], "severity": "Low", @@ -37215,8 +38087,8 @@ "guid": "b9ea80c8-0628-49fc-ae63-125aa4c0a284", "link": "https://learn.microsoft.com/azure/virtual-desktop/security-guide#windows-defender-application-control", "services": [ - "AVD", - "Defender" + "Defender", + "AVD" ], "severity": "Medium", "subcategory": "Management", @@ -37259,8 +38131,8 @@ "guid": "9164e990-9ae2-48c8-9c33-b6b7808bafe6", "link": "https://learn.microsoft.com/azure/virtual-desktop/fslogix-containers-azure-files#best-practices-for-azure-virtual-desktop", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "Azure Files", @@ -37274,10 +38146,10 @@ "guid": "5784b6ca-5e9e-4bcf-8b54-c95459ea7369", "link": "https://learn.microsoft.com/azure/storage/files/storage-files-smb-multichannel-performance", "services": [ - "AVD", + "ACR", "Storage", "Cost", - "ACR" + "AVD" ], "severity": "Low", "subcategory": "Azure Files", @@ -37291,8 +38163,8 @@ "guid": "4a359836-ee79-4d6c-9d3a-364a5b7abae3", "link": "https://azure.microsoft.com/global-infrastructure/services/", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "Azure NetApp Files", @@ -37306,8 +38178,8 @@ "guid": "a2661898-866a-4c8d-9d1f-8cfc86e88024", "link": "https://learn.microsoft.com/azure/virtual-desktop/create-fslogix-profile-container", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "Azure NetApp Files", @@ -37321,8 +38193,8 @@ "guid": "6647e977-db49-48a8-bc35-743f17499d42", "link": "https://docs.microsoft.com/azure/azure-netapp-files/create-active-directory-connections", "services": [ - "AVD", "Storage", + "AVD", "VNet" ], "severity": "High", @@ -37337,8 +38209,8 @@ "guid": "3611c818-b0a0-4bc5-80e4-3a18a9cd289c", "link": "https://docs.microsoft.com/azure/virtual-machines/disks-types", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "Capacity Planning", @@ -37352,9 +38224,9 @@ "guid": "ed6b17db-8255-4462-b2ae-e4553afc8339", "link": "https://docs.microsoft.com/azure/virtual-desktop/store-fslogix-profile", "services": [ + "Storage", "VM", - "AVD", - "Storage" + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -37368,8 +38240,8 @@ "guid": "2fad62bd-5004-453c-ace4-64d862e7f5a4", "link": "https://learn.microsoft.com/azure/virtual-desktop/store-fslogix-profile", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -37383,8 +38255,8 @@ "guid": "680e7828-9c93-4665-9d02-bff4564b0d93", "link": "https://learn.microsoft.com/azure/virtual-desktop/faq#what-s-the-largest-profile-size-fslogix-can-handle-", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -37398,9 +38270,9 @@ "guid": "8aad53cc-79e2-4e86-9673-57c549675c5e", "link": "https://docs.microsoft.com/azure/virtual-desktop/fslogix-containers-azure-files", "services": [ - "AVD", + "Cost", "Storage", - "Cost" + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -37414,9 +38286,9 @@ "guid": "df47d2d9-2881-4b1c-b5d1-e54a29759e39", "link": "https://learn.microsoft.com/fslogix/concepts-container-types#when-to-use-profile-and-odfc-containers", "services": [ - "AVD", "Storage", - "ASR" + "ASR", + "AVD" ], "severity": "High", "subcategory": "FSLogix", @@ -37430,8 +38302,8 @@ "guid": "83f63047-22ee-479d-9b5c-3632054b69ba", "link": "https://learn.microsoft.com/fslogix/overview-prerequisites#configure-antivirus-file-and-folder-exclusions", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "FSLogix", @@ -37445,8 +38317,8 @@ "guid": "01e6a84d-e5df-443d-8992-481718d5d1e5", "link": "https://docs.microsoft.com/fslogix/profile-container-configuration-reference", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "FSLogix", @@ -37460,10 +38332,10 @@ "guid": "d34aad5e-8c78-4e1d-9666-7313c405674c", "link": "https://learn.microsoft.com/fslogix/concepts-configuration-examples", "services": [ - "AKV", - "AVD", + "ACR", "Storage", - "ACR" + "AKV", + "AVD" ], "severity": "High", "subcategory": "FSLogix", @@ -37477,8 +38349,8 @@ "guid": "5e985b85-9c77-43e7-b261-623b775a917e", "link": "https://learn.microsoft.com/fslogix/concepts-multi-concurrent-connections", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "FSLogix", @@ -37492,9 +38364,9 @@ "guid": "b2d1215a-e114-4ba3-9df5-85ecdcd9bd3b", "link": "https://docs.microsoft.com/fslogix/cloud-cache-configuration-reference", "services": [ - "AVD", + "Storage", "VM", - "Storage" + "AVD" ], "severity": "Low", "subcategory": "FSLogix", @@ -37508,8 +38380,8 @@ "guid": "0b50ca97-b1d2-473c-b4d9-6e98b0f912de", "link": "https://docs.microsoft.com/fslogix/manage-profile-content-cncpt#redirectionsxml", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "FSLogix", @@ -37669,9 +38541,9 @@ "guid": "5cf9f485-2784-49b3-9824-75d9b8bdb57b", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", "services": [ - "Subscriptions", "Cost", - "Entra" + "Entra", + "Subscriptions" ], "severity": "Low", "subcategory": "Enterprise Agreement", @@ -37699,8 +38571,8 @@ "guid": "90e87802-602f-4dfb-acea-67c60689f1d7", "link": "https://learn.microsoft.com/azure/cost-management-billing/manage/mca-section-invoice", "services": [ - "Storage", "Cost", + "Storage", "Entra" ], "severity": "Low", @@ -37746,10 +38618,10 @@ "link": "https://learn.microsoft.com/azure/role-based-access-control/overview", "service": "Entra", "services": [ - "Entra", + "ACR", "RBAC", - "Subscriptions", - "ACR" + "Entra", + "Subscriptions" ], "severity": "High", "subcategory": "Identity", @@ -37808,8 +38680,8 @@ "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/overview", "service": "Entra", "services": [ - "AzurePolicy", - "Entra" + "Entra", + "AzurePolicy" ], "severity": "High", "subcategory": "Identity", @@ -37868,9 +38740,9 @@ "guid": "1559ab91-53e8-4908-ae28-c84c33b6b780", "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/identity/adds-extend-domain#vm-recommendations", "services": [ - "Entra", + "ACR", "VM", - "ACR" + "Entra" ], "severity": "High", "subcategory": "Identity", @@ -37898,10 +38770,10 @@ "guid": "f5664b5e-984a-4859-a773-e7d261623a76", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access#prerequisites-for-a-landing-zone---design-recommendations", "services": [ - "Entra", + "ACR", "RBAC", - "Subscriptions", - "ACR" + "Entra", + "Subscriptions" ], "severity": "Medium", "subcategory": "Identity", @@ -38024,8 +38896,8 @@ "guid": "9cf5418b-1520-4b7b-add7-88eb28f833e8", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access-landing-zones#identity-and-access-management-in-the-azure-landing-zone-accelerator", "services": [ - "VNet", - "Entra" + "Entra", + "VNet" ], "severity": "High", "subcategory": "Landing zones", @@ -38039,11 +38911,11 @@ "guid": "d4d1ad54-1abc-4919-b267-3f342d3b49e4", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access-landing-zones#rbac-recommendations", "services": [ - "Entra", "ACR", - "Storage", "AKV", - "RBAC" + "Storage", + "RBAC", + "Entra" ], "severity": "Medium", "subcategory": "Landing zones", @@ -38112,8 +38984,8 @@ "guid": "61623a76-5a91-47e1-b348-ef254c27d42e", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups#management-group-recommendations", "services": [ - "AzurePolicy", "RBAC", + "AzurePolicy", "Subscriptions" ], "severity": "Medium", @@ -38129,8 +39001,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups#management-group-recommendations", "services": [ "VWAN", - "DNS", "ExpressRoute", + "DNS", "Subscriptions" ], "severity": "Medium", @@ -38188,10 +39060,10 @@ "guid": "49b82111-2df2-47ee-912e-7f983f630472", "link": "https://learn.microsoft.com/entra/id-governance/access-reviews-overview", "services": [ - "AzurePolicy", + "Cost", "RBAC", - "Subscriptions", - "Cost" + "AzurePolicy", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -38219,8 +39091,8 @@ "guid": "c68e1d76-6673-413b-9f56-64b5e984a859", "link": "https://learn.microsoft.com/azure/cost-management-billing/reservations/save-compute-costs-reservations", "services": [ - "Subscriptions", - "Cost" + "Cost", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -38236,8 +39108,8 @@ "link": "https://learn.microsoft.com/azure/azure-portal/azure-portal-dashboards", "services": [ "Storage", - "Subscriptions", - "Monitor" + "Monitor", + "Subscriptions" ], "severity": "Medium", "subcategory": "Subscriptions", @@ -38251,8 +39123,8 @@ "guid": "ae28c84c-33b6-4b78-88b9-fe5c41049d40", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/get-started/manage-costs", "services": [ - "Subscriptions", - "Cost" + "Cost", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -38266,8 +39138,8 @@ "guid": "3a923c34-74d0-4001-aac6-a9e01e6a83de", "link": "https://learn.microsoft.com/azure/governance/management-groups/overview", "services": [ - "Subscriptions", - "Entra" + "Entra", + "Subscriptions" ], "severity": "Medium", "subcategory": "Subscriptions", @@ -38282,8 +39154,8 @@ "guid": "5de32c19-9248-4160-9d5d-1e4e614658d3", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/track-costs", "services": [ - "Subscriptions", - "Cost" + "Cost", + "Subscriptions" ], "severity": "Medium", "subcategory": "Subscriptions", @@ -38381,13 +39253,13 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/traditional-azure-networking-topology", "service": "VNet", "services": [ - "VPN", - "Entra", - "DNS", + "ExpressRoute", "NVA", "Firewall", - "ExpressRoute", - "VNet" + "VPN", + "VNet", + "DNS", + "Entra" ], "severity": "High", "subcategory": "Hub and spoke", @@ -38431,8 +39303,8 @@ "link": "https://learn.microsoft.com/azure/expressroute/expressroute-howto-coexist-resource-manager#to-enable-transit-routing-between-expressroute-and-azure-vpn", "service": "ExpressRoute", "services": [ - "ARS", "ExpressRoute", + "ARS", "VPN" ], "severity": "Low", @@ -38465,8 +39337,8 @@ "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-faq#can-i-create-a-peering-connection-to-a-vnet-in-a-different-region", "service": "VNet", "services": [ - "VNet", - "ACR" + "ACR", + "VNet" ], "severity": "Medium", "subcategory": "Hub and spoke", @@ -38606,8 +39478,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", "service": "ExpressRoute", "services": [ - "VNet", - "ACR" + "ACR", + "VNet" ], "severity": "High", "subcategory": "IP plan", @@ -38671,8 +39543,8 @@ "link": "https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone", "service": "Public IP Addresses", "services": [ - "VNet", - "ACR" + "ACR", + "VNet" ], "severity": "High", "subcategory": "IP plan", @@ -38703,9 +39575,9 @@ "link": "https://learn.microsoft.com/azure/dns/dns-private-resolver-overview", "service": "DNS", "services": [ + "ACR", "DNS", - "VNet", - "ACR" + "VNet" ], "severity": "Medium", "subcategory": "IP plan", @@ -38801,10 +39673,10 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", "service": "WAF", "services": [ - "AzurePolicy", - "WAF", + "ACR", "FrontDoor", - "ACR" + "AzurePolicy", + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -38820,9 +39692,9 @@ "service": "WAF", "services": [ "AppGW", + "FrontDoor", "AzurePolicy", - "WAF", - "FrontDoor" + "WAF" ], "severity": "Low", "subcategory": "Internet", @@ -38897,8 +39769,8 @@ "link": "https://github.com/Azure/Enterprise-Scale/wiki/ALZ-Policies#corp", "service": "Policy", "services": [ - "AzurePolicy", - "VM" + "VM", + "AzurePolicy" ], "severity": "High", "subcategory": "Internet", @@ -38913,9 +39785,9 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/connectivity-to-azure", "service": "ExpressRoute", "services": [ + "Backup", "ExpressRoute", - "VPN", - "Backup" + "VPN" ], "severity": "Medium", "subcategory": "Hybrid", @@ -38964,8 +39836,8 @@ "link": "https://learn.microsoft.com/azure/expressroute/plan-manage-cost", "service": "ExpressRoute", "services": [ - "ExpressRoute", - "Cost" + "Cost", + "ExpressRoute" ], "severity": "High", "subcategory": "Hybrid", @@ -38981,8 +39853,8 @@ "link": "https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local", "service": "ExpressRoute", "services": [ - "ExpressRoute", - "Cost" + "Cost", + "ExpressRoute" ], "severity": "High", "subcategory": "Hybrid", @@ -39074,8 +39946,8 @@ "link": "https://learn.microsoft.com/azure/expressroute/expressroute-erdirect-about", "service": "ExpressRoute", "services": [ - "ExpressRoute", - "Cost" + "Cost", + "ExpressRoute" ], "severity": "High", "subcategory": "Hybrid", @@ -39121,9 +39993,9 @@ "link": "https://learn.microsoft.com/azure/expressroute/how-to-configure-connection-monitor", "service": "ExpressRoute", "services": [ - "NetworkWatcher", + "ACR", "Monitor", - "ACR" + "NetworkWatcher" ], "severity": "Medium", "subcategory": "Hybrid", @@ -39186,8 +40058,8 @@ "link": "https://learn.microsoft.com/azure/expressroute/designing-for-high-availability-with-expressroute#active-active-connections", "service": "ExpressRoute", "services": [ - "ExpressRoute", - "ACR" + "ACR", + "ExpressRoute" ], "severity": "High", "subcategory": "Hybrid", @@ -39307,10 +40179,10 @@ "link": "https://learn.microsoft.com/azure/firewall-manager/policy-overview", "service": "Firewall", "services": [ - "AzurePolicy", + "ACR", "RBAC", "Firewall", - "ACR" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Firewall", @@ -39341,8 +40213,8 @@ "link": "https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules", "service": "Firewall", "services": [ - "DNS", - "Firewall" + "Firewall", + "DNS" ], "severity": "High", "subcategory": "Firewall", @@ -39405,10 +40277,10 @@ "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview", "service": "Firewall", "services": [ - "VWAN", "NVA", - "Storage", "Firewall", + "VWAN", + "Storage", "VNet" ], "severity": "High", @@ -39439,8 +40311,8 @@ "link": "https://learn.microsoft.com/azure/firewall-manager/migrate-to-policy", "service": "Firewall", "services": [ - "AzurePolicy", - "Firewall" + "Firewall", + "AzurePolicy" ], "severity": "High", "subcategory": "Firewall", @@ -39571,8 +40443,8 @@ "link": "https://learn.microsoft.com/azure/firewall/dns-details", "service": "Firewall", "services": [ - "DNS", - "Firewall" + "Firewall", + "DNS" ], "severity": "Medium", "subcategory": "Firewall", @@ -39619,8 +40491,8 @@ "link": "https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell", "service": "Firewall", "services": [ - "Firewall", - "ACR" + "ACR", + "Firewall" ], "severity": "High", "subcategory": "Firewall", @@ -39636,8 +40508,8 @@ "link": "https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview", "service": "Firewall", "services": [ - "DDoS", "Firewall", + "DDoS", "VNet" ], "severity": "High", @@ -39714,9 +40586,9 @@ "service": "Firewall", "services": [ "NVA", - "DNS", + "PrivateLink", "Firewall", - "PrivateLink" + "DNS" ], "severity": "Medium", "subcategory": "PaaS", @@ -39778,8 +40650,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation", "service": "NSG", "services": [ - "VNet", - "ACR" + "ACR", + "VNet" ], "severity": "Medium", "subcategory": "Segmentation", @@ -39795,8 +40667,8 @@ "service": "NSG", "services": [ "NVA", - "VNet", - "Entra" + "Entra", + "VNet" ], "severity": "Medium", "subcategory": "Segmentation", @@ -39812,8 +40684,8 @@ "link": "https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview", "service": "NSG", "services": [ - "NetworkWatcher", - "VNet" + "VNet", + "NetworkWatcher" ], "severity": "Medium", "subcategory": "Segmentation", @@ -39859,8 +40731,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/virtual-wan-network-topology#virtual-wan-network-design-recommendationst", "service": "VWAN", "services": [ - "VWAN", - "ACR" + "ACR", + "VWAN" ], "severity": "Medium", "subcategory": "Virtual WAN", @@ -40003,8 +40875,8 @@ "link": "https://learn.microsoft.com/azure/governance/policy/overview", "service": "Policy", "services": [ - "AzurePolicy", - "RBAC" + "RBAC", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Governance", @@ -40082,10 +40954,10 @@ "link": "https://learn.microsoft.com/azure/governance/policy/overview#azure-rbac-permissions-in-azure-policy", "service": "Policy", "services": [ - "AzurePolicy", "RBAC", - "Subscriptions", - "Entra" + "Entra", + "AzurePolicy", + "Subscriptions" ], "severity": "Medium", "subcategory": "Governance", @@ -40173,9 +41045,9 @@ "guid": "29fd366b-a180-452b-9bd7-954b7700c667", "link": "https://learn.microsoft.com/azure/cost-management-billing/costs/tutorial-acm-create-budgets?bc=%2Fazure%2Fcloud-adoption-framework%2F_bread%2Ftoc.json&toc=%2Fazure%2Fcloud-adoption-framework%2Ftoc.json", "services": [ + "Cost", "TrafficManager", - "Monitor", - "Cost" + "Monitor" ], "severity": "Medium", "subcategory": "Optimize your cloud investment", @@ -40190,9 +41062,9 @@ "link": "https://learn.microsoft.com/en-us/azure/azure-monitor/logs/workspace-design#azure-regions", "service": "Monitor", "services": [ - "AzurePolicy", "RBAC", "Monitor", + "AzurePolicy", "Entra" ], "severity": "Medium", @@ -40223,10 +41095,10 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/logs/data-retention-archive?tabs=portal-1%2Cportal-2#how-retention-and-archiving-work", "service": "Monitor", "services": [ - "AzurePolicy", "Storage", "Monitor", - "ARS" + "ARS", + "AzurePolicy" ], "severity": "High", "subcategory": "Monitoring", @@ -40241,9 +41113,9 @@ "link": "https://learn.microsoft.com/azure/governance/machine-configuration/overview", "service": "VM", "services": [ - "AzurePolicy", "VM", - "Monitor" + "Monitor", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Monitoring", @@ -40288,8 +41160,8 @@ "link": "https://learn.microsoft.com/azure/network-watcher/network-watcher-monitoring-overview", "service": "Network Watcher", "services": [ - "NetworkWatcher", - "Monitor" + "Monitor", + "NetworkWatcher" ], "severity": "Medium", "subcategory": "Monitoring", @@ -40317,9 +41189,9 @@ "guid": "a6e55d7d-8a2a-4db1-87d6-326af625ca44", "link": "https://learn.microsoft.com/azure/governance/policy/concepts/effect-deny", "services": [ - "AzurePolicy", "RBAC", - "Monitor" + "Monitor", + "AzurePolicy" ], "severity": "Low", "subcategory": "Monitoring", @@ -40449,8 +41321,8 @@ "guid": "aa45be6a-8f2d-4896-b0e3-775e6e94e610", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-monitor", "services": [ - "AzurePolicy", - "Monitor" + "Monitor", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Monitoring", @@ -40479,8 +41351,8 @@ "guid": "0d83fd81-952c-4d47-a6cb-3a930925ef2e", "link": "https://learn.microsoft.com/en-gb/azure/storage/common/redundancy-migration?tabs=portal", "services": [ - "Storage", - "Cost" + "Cost", + "Storage" ], "severity": "High", "subcategory": "Data Protection", @@ -40522,8 +41394,8 @@ "link": "https://learn.microsoft.com/azure/governance/policy/concepts/guest-configuration", "service": "VM", "services": [ - "AzurePolicy", - "VM" + "VM", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Operational compliance", @@ -40538,9 +41410,9 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management-operational-compliance#monitoring-for-configuration-drift", "service": "VM", "services": [ - "AzurePolicy", "VM", - "Monitor" + "Monitor", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Operational compliance", @@ -40555,9 +41427,9 @@ "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", "service": "VM", "services": [ + "ACR", "VM", - "ASR", - "ACR" + "ASR" ], "severity": "Medium", "subcategory": "Protect and Recover", @@ -40602,8 +41474,8 @@ "service": "WAF", "services": [ "AppGW", - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "High", "subcategory": "App delivery", @@ -40618,10 +41490,10 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", "service": "WAF", "services": [ - "AppGW", "Sentinel", - "WAF", - "FrontDoor" + "AppGW", + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "App delivery", @@ -40833,9 +41705,9 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "service": "Key Vault", "services": [ - "AKV", + "ACR", "ASR", - "ACR" + "AKV" ], "severity": "Medium", "subcategory": "Encryption and keys", @@ -40880,8 +41752,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export?tabs=portal", "services": [ "Storage", - "Monitor", - "ARS" + "ARS", + "Monitor" ], "severity": "Medium", "subcategory": "Operations", @@ -40896,8 +41768,8 @@ "link": "https://learn.microsoft.com/azure/defender-for-cloud/concept-cloud-security-posture-management", "service": "Defender", "services": [ - "Subscriptions", - "Defender" + "Defender", + "Subscriptions" ], "severity": "High", "subcategory": "Operations", @@ -40912,8 +41784,8 @@ "link": "https://learn.microsoft.com/azure/defender-for-cloud/plan-defender-for-servers-select-plan", "service": "Defender", "services": [ - "Subscriptions", - "Defender" + "Defender", + "Subscriptions" ], "severity": "High", "subcategory": "Operations", @@ -40928,8 +41800,8 @@ "link": "https://learn.microsoft.com/azure/defender-for-cloud/connect-azure-subscription", "service": "Defender", "services": [ - "Subscriptions", - "Defender" + "Defender", + "Subscriptions" ], "severity": "High", "subcategory": "Operations", @@ -40957,8 +41829,8 @@ "link": "https://learn.microsoft.com/azure/security-center/", "service": "VM", "services": [ - "Monitor", - "Defender" + "Defender", + "Monitor" ], "severity": "Medium", "subcategory": "Operations", @@ -41174,8 +42046,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/considerations/development-strategy-development-lifecycle#automated-builds", "service": "Key Vault", "services": [ - "AKV", - "VM" + "VM", + "AKV" ], "severity": "High", "subcategory": "DevOps Team Topologies", @@ -41276,8 +42148,8 @@ "link": "https://learn.microsoft.com/azure/azure-vmware/set-up-backup-server-for-azure-vmware-solution", "services": [ "Storage", - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Backup", @@ -41291,8 +42163,8 @@ "guid": "fc8af7a1-c724-e255-c18d-4ca22a6f27f0", "link": "https://docs.microsoft.com/azure/azure-vmware/set-up-backup-server-for-azure-vmware-solution", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -41306,9 +42178,9 @@ "guid": "be28860f-3d29-a79a-1a0e-36f1b23b36ae", "link": "Best practice to deploy backup in the same region as your AVS deployment", "services": [ - "AVS", "ASR", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -41350,8 +42222,8 @@ "guid": "f379436d-3051-daa0-01fb-dc4e0e04d677", "link": "https://docs.microsoft.com/azure/azure-vmware/disaster-recovery-using-vmware-site-recovery-manager", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -41365,8 +42237,8 @@ "guid": "367f71d8-3cf6-51a0-91a5-3db3d570cc19", "link": "https://docs.microsoft.com/azure/site-recovery/avs-tutorial-prepare-azure", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -41380,8 +42252,8 @@ "guid": "ee02ada0-1887-bb3a-b84c-423f45a09ef9", "link": "https://docs.microsoft.com/azure/site-recovery/avs-tutorial-prepare-azure", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -41395,8 +42267,8 @@ "guid": "0c2b74e5-9c28-780d-1df3-12d3de4aaa76", "link": "https://docs.microsoft.com/azure/azure-vmware/connect-multiple-private-clouds-same-region", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -41410,8 +42282,8 @@ "guid": "c2a34ec4-2933-4e6c-dc36-e20e67abbe3f", "link": "https://docs.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -41426,9 +42298,9 @@ "link": "This depends if you have multiple AVS Private Clouds. If so and they are in the same region then use AVS Interconnect. If they are in separate regions then use ExpressRoute Global Reach.", "services": [ "NVA", - "AVS", + "ASR", "ExpressRoute", - "ASR" + "AVS" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -41457,8 +42329,8 @@ "guid": "f62ce162-ba5a-429d-674e-fafa1af5f706", "link": "https://learn.microsoft.com/azure/azure-vmware/tutorial-expressroute-global-reach-private-cloud", "services": [ - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "ExpressRoute", @@ -41472,8 +42344,8 @@ "guid": "cf01c73b-1247-0a7a-740c-e1ea29bda340", "link": "https://learn.microsoft.com/azure/expressroute/expressroute-introduction", "services": [ - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "ExpressRoute", @@ -41487,8 +42359,8 @@ "guid": "aab216ee-8941-315e-eada-c7e1f2243bd1", "link": "https://learn.microsoft.com/azure/architecture/solution-ideas/articles/azure-vmware-solution-foundation-networking", "services": [ - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "ExpressRoute", @@ -41502,8 +42374,8 @@ "guid": "1f956e45-f62d-5c95-3a95-3bab718907f8", "link": "https://learn.microsoft.com/azure/architecture/solution-ideas/articles/azure-vmware-solution-foundation-networking", "services": [ - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "ExpressRoute", @@ -41532,9 +42404,9 @@ "guid": "58a027e2-f37f-b540-45d5-e44843aba26b", "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings", "services": [ - "AVS", - "ExpressRoute", "VPN", + "ExpressRoute", + "AVS", "VNet" ], "severity": "Medium", @@ -41549,9 +42421,9 @@ "guid": "d4806549-0913-3e79-b580-ac2d3706e65a", "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings", "services": [ - "AVS", - "ExpressRoute", "VPN", + "ExpressRoute", + "AVS", "VNet" ], "severity": "Medium", @@ -41566,9 +42438,9 @@ "guid": "864d7a8b-7016-c769-a717-61af6bfb73d2", "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings", "services": [ - "AVS", - "ExpressRoute", "VPN", + "ExpressRoute", + "AVS", "VNet" ], "severity": "Medium", @@ -41598,8 +42470,8 @@ "guid": "71e68ce3-982e-5e56-0191-01100ad0e66f", "link": "https://learn.microsoft.com/answers/questions/171195/how-to-create-jump-server-in-azure-not-bastion-paa.html", "services": [ - "Bastion", - "AVS" + "AVS", + "Bastion" ], "severity": "Medium", "subcategory": "Jumpbox & Bastion", @@ -41613,8 +42485,8 @@ "guid": "6f8e93a2-44b1-bb1d-28a1-4d5b3c2ea857", "link": "https://learn.microsoft.com/azure/bastion/tutorial-create-host-portal", "services": [ - "Bastion", "AVS", + "Bastion", "VNet" ], "severity": "Medium", @@ -41629,9 +42501,9 @@ "guid": "ba430d58-4541-085c-3641-068c00be9bc5", "link": "https://learn.microsoft.com/azure/virtual-network/network-security-groups-overview", "services": [ - "Bastion", + "VM", "AVS", - "VM" + "Bastion" ], "severity": "Medium", "subcategory": "Jumpbox & Bastion", @@ -41645,8 +42517,8 @@ "guid": "9988598f-2a9f-6b12-9b46-488415ceb325", "link": "https://learn.microsoft.com/azure/azure-vmware/configure-site-to-site-vpn-gateway", "services": [ - "AVS", - "VPN" + "VPN", + "AVS" ], "severity": "Medium", "subcategory": "VPN", @@ -41660,8 +42532,8 @@ "guid": "956ce5e9-a862-fe2b-a50d-a22923569357", "link": "https://www.omnicalculator.com/other/data-transfer#:~:text=To%20calculate%20the%20data%20transfer%20speed%3A%201%20Download,measured%20time%20to%20find%20the%20data%20transfer%20speed.", "services": [ - "AVS", - "VPN" + "VPN", + "AVS" ], "severity": "Medium", "subcategory": "VPN", @@ -41675,8 +42547,8 @@ "guid": "e095116f-0bdc-4b51-4d71-b9e469d56f59", "link": "https://learn.microsoft.com/azure/architecture/solution-ideas/articles/azure-vmware-solution-foundation-networking", "services": [ - "AVS", - "VPN" + "VPN", + "AVS" ], "severity": "Medium", "subcategory": "VPN", @@ -41706,8 +42578,8 @@ "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-point-to-site-portal", "services": [ "VWAN", - "AVS", - "VPN" + "VPN", + "AVS" ], "severity": "Medium", "subcategory": "vWAN hub", @@ -41722,8 +42594,8 @@ "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-expressroute-portal", "services": [ "VWAN", - "AVS", - "Firewall" + "Firewall", + "AVS" ], "severity": "Medium", "subcategory": "vWAN hub", @@ -41892,8 +42764,8 @@ "guid": "915cbcd7-0640-eb7c-4162-9f33775de559", "link": "Best practice", "services": [ - "AVS", "Monitor", + "AVS", "Entra" ], "severity": "Medium", @@ -41923,9 +42795,9 @@ "guid": "8f426fd0-d73b-d398-1f6f-df0cbe262a82", "link": "https://learn.microsoft.com/azure/azure-arc/vmware-vsphere/overview", "services": [ + "Arc", "VM", - "AVS", - "Arc" + "AVS" ], "severity": "Medium", "subcategory": "Operations", @@ -41939,9 +42811,9 @@ "guid": "11dbe773-e380-9191-1418-e886fa7a6fd0", "link": "https://docs.microsoft.com/azure/governance/policy/overview", "services": [ - "AzurePolicy", + "Monitor", "AVS", - "Monitor" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Operations", @@ -41998,8 +42870,8 @@ "guid": "e22a2d99-eb71-7d7c-07af-6d4cdb1d4443", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-alerts-for-azure-vmware-solution", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Alerts", @@ -42013,8 +42885,8 @@ "guid": "6d02f159-627d-79bf-a931-fab6d947eda2", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-alerts-for-azure-vmware-solution", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Alerts", @@ -42028,8 +42900,8 @@ "guid": "1cc97b39-2c7e-246f-6d73-789cfebfe951", "link": "https://www.virtualworkloads.com/2021/04/azure-vmware-solution-azure-service-health/", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Alerts", @@ -42043,11 +42915,11 @@ "guid": "0962606c-e3b4-62a9-5661-e4ffd62a4509", "link": "https://docs.microsoft.com/azure/azure-vmware/set-up-backup-server-for-azure-vmware-solution", "services": [ + "Monitor", "AVS", - "VM", "Backup", - "AzurePolicy", - "Monitor" + "VM", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Backup", @@ -42061,9 +42933,9 @@ "guid": "4ec7ccfb-795e-897e-4a84-fd31c04eadc6", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-alerts-for-azure-vmware-solution", "services": [ - "AzurePolicy", + "Monitor", "AVS", - "Monitor" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Capacity", @@ -42077,10 +42949,10 @@ "guid": "7f8f175d-13f4-5298-9e61-0bc7e9fcc279", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/govern", "services": [ - "AVS", - "Subscriptions", + "Cost", "Monitor", - "Cost" + "AVS", + "Subscriptions" ], "severity": "Medium", "subcategory": "Costs", @@ -42094,9 +42966,9 @@ "guid": "01e689e0-7c6c-b58f-37bd-4d6b9b1b9c74", "link": "https://docs.microsoft.com/azure/azure-portal/azure-portal-dashboards", "services": [ - "NetworkWatcher", + "Monitor", "AVS", - "Monitor" + "NetworkWatcher" ], "severity": "Medium", "subcategory": "Dashboard", @@ -42111,8 +42983,8 @@ "link": "https://docs.microsoft.com/azure/azure-vmware/configure-vmware-syslogs", "services": [ "Storage", - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Logs & Metrics", @@ -42126,8 +42998,8 @@ "guid": "7cbac8c3-4eda-d5d9-9bda-c6b5abba9fb6", "link": "Is vROPS or vRealize Network Insight going to be used? ", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Logs & Metrics", @@ -42142,8 +43014,8 @@ "link": "https://docs.microsoft.com/azure/azure-vmware/configure-vmware-syslogs", "services": [ "VM", - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Logs & Metrics", @@ -42157,11 +43029,11 @@ "guid": "2ca97d91-dd36-7229-b668-01036ccc3cd3", "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-create-using-portal", "services": [ + "ExpressRoute", "AVS", + "Monitor", "VPN", - "NetworkWatcher", - "ExpressRoute", - "Monitor" + "NetworkWatcher" ], "severity": "Medium", "subcategory": "Network", @@ -42175,9 +43047,9 @@ "guid": "99209143-60fe-19f0-5633-8b5671277ba5", "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-create-using-portal", "services": [ - "AVS", "ExpressRoute", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Network", @@ -42191,8 +43063,8 @@ "guid": "b9e5867c-57d3-036f-fb1b-3f0a71664efe", "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-create-using-portal", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Network", @@ -42206,8 +43078,8 @@ "guid": "4af7c5f7-e5e9-bedf-a8cf-314b81735962", "link": "Firewall logging and alerting rules are configured (Azure Firewall or 3rd party)", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Security", @@ -42221,8 +43093,8 @@ "guid": "74be60a3-cfac-f057-eda6-3ee087e805d5", "link": "https://docs.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-network-topology-connectivity", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Security", @@ -42236,8 +43108,8 @@ "guid": "a434b3b5-f258-0845-cd76-d7df6ef5890e", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-vmware-syslogs", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "VMWare", @@ -42252,8 +43124,8 @@ "link": "https://docs.microsoft.com/azure/azure-monitor/agents/agent-windows?tabs=setup-wizard", "services": [ "VM", - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "VMware", @@ -42296,8 +43168,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-network-topology-connectivity", "services": [ "NVA", - "AVS", - "ARS" + "ARS", + "AVS" ], "severity": "Medium", "subcategory": "Hub & Spoke", @@ -42311,8 +43183,8 @@ "guid": "ffb5c5ca-bd89-ff1b-8b73-8a54d503d506", "link": "https://learn.microsoft.com/azure/route-server/route-server-faq", "services": [ - "AVS", - "ARS" + "ARS", + "AVS" ], "severity": "Medium", "subcategory": "Hub & Spoke", @@ -42340,10 +43212,10 @@ "guid": "e942c03d-beaa-3d9f-0526-9b26cd5e9937", "link": "Research and choose optimal solution for each application", "services": [ - "AppGW", "NVA", - "AVS", - "FrontDoor" + "AppGW", + "FrontDoor", + "AVS" ], "severity": "Medium", "subcategory": "Internet", @@ -42357,8 +43229,8 @@ "guid": "e778a2ec-b4d7-1d27-574c-14476b167d37", "link": "https://docs.microsoft.com/azure/route-server/route-server-faq#route-server-limits", "services": [ - "AVS", - "ARS" + "ARS", + "AVS" ], "severity": "Medium", "subcategory": "Routing", @@ -42372,15 +43244,15 @@ "guid": "66c97b30-81b9-139a-cc76-dd1d94aef42a", "link": "https://docs.microsoft.com/azure/ddos-protection/manage-ddos-protection", "services": [ - "AppGW", - "AVS", - "VM", - "VPN", - "DDoS", "ExpressRoute", + "AVS", "LoadBalancer", + "FrontDoor", + "AppGW", + "VPN", "VNet", - "FrontDoor" + "VM", + "DDoS" ], "severity": "Medium", "subcategory": "Security", @@ -42423,8 +43295,8 @@ "link": "https://learn.microsoft.com/azure/architecture/networking/hub-spoke-vwan-architecture", "services": [ "VWAN", - "AVS", - "Firewall" + "Firewall", + "AVS" ], "severity": "Medium", "subcategory": "Virtual WAN", @@ -42468,9 +43340,9 @@ "guid": "7242c1de-da37-27f3-1ddd-565ccccb8ece", "link": "https://docs.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-platform-automation-and-devops#automated-scale", "services": [ - "AzurePolicy", "Storage", - "AVS" + "AVS", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -42526,8 +43398,8 @@ "guid": "7bd65a5e-7b5d-652d-dbea-fc6f73a42857", "link": "https://docs.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-management-and-monitoring", "services": [ - "AVS", - "Monitor" + "Monitor", + "AVS" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -42541,8 +43413,8 @@ "guid": "95e374af-8a2a-2672-7ab7-b4a1be43ada7", "link": "https://learn.microsoft.com/azure/private-link/private-link-overview", "services": [ - "AVS", - "PrivateLink" + "PrivateLink", + "AVS" ], "severity": "Medium", "subcategory": "Networking", @@ -42584,8 +43456,8 @@ "guid": "e52d1615-9cc6-565c-deb6-743ed7e90f4b", "link": "Internal policy or regulatory compliance", "services": [ - "AzurePolicy", - "AVS" + "AVS", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Pre-deployment", @@ -42742,8 +43614,8 @@ "guid": "f2b73c4f-3d46-32c9-5df1-5b8dfcd3947f", "link": "https://azure.microsoft.com/en-ca/pricing/details/azure-vmware/#:~:text=Azure%20VMware%20Solution%20%20%20%20Instance%20size,TB%20%28all%20NVMe%29%20%20%20N%2FA%20%2Fhour%20", "services": [ - "AVS", - "Cost" + "Cost", + "AVS" ], "severity": "Medium", "subcategory": "Pre-deployment", @@ -42757,8 +43629,8 @@ "guid": "94ac48ab-ade5-3fa7-f800-263feeb97070", "link": "https://docs.microsoft.com/azure/azure-vmware/concepts-storage#storage-policies-and-fault-tolerance", "services": [ - "AVS", - "ASR" + "ASR", + "AVS" ], "severity": "Medium", "subcategory": "Pre-deployment", @@ -42831,8 +43703,8 @@ "link": "https://docs.microsoft.com/azure/key-vault/general/authentication", "services": [ "AKV", - "AVS", - "ExpressRoute" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "Encryption", @@ -42875,8 +43747,8 @@ "guid": "f42b0b09-c591-238a-1580-2de3c485ebd2", "link": "https://learn.microsoft.com/azure/azure-vmware/azure-security-integration#prerequisites", "services": [ - "AVS", - "Defender" + "Defender", + "AVS" ], "severity": "Medium", "subcategory": "Security", @@ -42890,8 +43762,8 @@ "guid": "bcdd2348-3d0e-c6bb-1092-aa4cd1a66d6b", "link": "https://docs.microsoft.com/azure/azure-vmware/azure-security-integration", "services": [ - "AzurePolicy", - "AVS" + "AVS", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Security", @@ -43060,8 +43932,8 @@ "guid": "eb2f9313-afb2-ab35-aa24-6d97a3cb0611", "link": "3rd-Party tools", "services": [ - "VM", "Storage", + "VM", "AVS" ], "severity": "Medium", @@ -43076,8 +43948,8 @@ "guid": "3f2a5cff-c8a6-634a-1f1b-53ef9d321381", "link": "Contact VMware", "services": [ - "VM", "Storage", + "VM", "AVS" ], "severity": "Medium", @@ -43122,10 +43994,10 @@ "guid": "7628d446-6b10-9678-9cec-f407d990de43", "link": "https://learn.microsoft.com/azure/azure-vmware/concepts-storage#storage-policies-and-fault-tolerance", "services": [ - "AzurePolicy", "Storage", + "VM", "AVS", - "VM" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Storage", @@ -43139,10 +44011,10 @@ "guid": "37fef358-7ab9-43a9-542c-22673955200e", "link": "https://learn.microsoft.com/azure/azure-vmware/configure-storage-policy", "services": [ - "AzurePolicy", "Storage", + "VM", "AVS", - "VM" + "AzurePolicy" ], "severity": "Medium", "subcategory": "Storage", @@ -43156,9 +44028,9 @@ "guid": "ebebd109-9f9d-d85e-1b2f-d302012843b7", "link": "https://learn.microsoft.com/azure/azure-vmware/concepts-storage#storage-policies-and-fault-tolerance", "services": [ - "AzurePolicy", "Storage", - "AVS" + "AVS", + "AzurePolicy" ], "severity": "Medium", "subcategory": "Storage", @@ -43309,8 +44181,8 @@ "link": "https://learn.microsoft.com/azure/api-management/policy-fragments", "service": "APIM", "services": [ - "AzurePolicy", "ACR", + "AzurePolicy", "APIM" ], "severity": "Medium", @@ -43474,8 +44346,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region", "service": "APIM", "services": [ - "ASR", "ACR", + "ASR", "APIM" ], "severity": "Medium", @@ -43550,8 +44422,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-log-event-hubs", "service": "APIM", "services": [ - "AzurePolicy", "EventHubs", + "AzurePolicy", "APIM" ], "severity": "Low", @@ -43683,8 +44555,8 @@ "link": "https://learn.microsoft.com/azure/api-management/front-door-api-management", "service": "APIM", "services": [ - "Entra", "FrontDoor", + "Entra", "APIM" ], "severity": "Medium", @@ -43714,9 +44586,9 @@ "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#network-security-group-support", "service": "APIM", "services": [ - "Entra", "VNet", "Monitor", + "Entra", "APIM" ], "severity": "Medium", @@ -43731,9 +44603,9 @@ "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#azure-private-link", "service": "APIM", "services": [ - "Entra", - "PrivateLink", "VNet", + "PrivateLink", + "Entra", "APIM" ], "severity": "Medium", @@ -43920,9 +44792,9 @@ "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/api-management-security-baseline?toc=%2Fazure%2Fapi-management%2F&bc=%2Fazure%2Fapi-management%2Fbreadcrumb%2Ftoc.json#ns-6-deploy-web-application-firewall", "service": "APIM", "services": [ + "WAF", "AppGW", "Entra", - "WAF", "APIM" ], "severity": "High", @@ -43980,8 +44852,8 @@ "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#multiple-write-regions", "service": "CosmosDB", "services": [ - "CosmosDB", - "ACR" + "ACR", + "CosmosDB" ], "severity": "Medium", "subcategory": "High Availability", @@ -43996,8 +44868,8 @@ "link": "https://learn.microsoft.com/azure/cosmos-db/high-availability#slas", "service": "CosmosDB", "services": [ - "CosmosDB", - "ACR" + "ACR", + "CosmosDB" ], "severity": "Medium", "subcategory": "High Availability", @@ -44183,23 +45055,37 @@ "checklist": "DataBricks Review Checklist", "guid": "65285269-440c-44be-9d3e-0844276d4bdc", "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", "services": [], "severity": "High", "subcategory": "Best Practices", "text": "Reference Databricks HA/DR playbook", "waf": "Reliability" }, + { + "category": "Operations Management", + "checklist": "DataBricks Review Checklist", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "services": [], + "severity": "Low", + "subcategory": "Migration", + "text": "Use Databricks Sync", + "waf": "Reliability" + }, { "category": "Operations Management", "checklist": "DataBricks Review Checklist", "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", "services": [ "Backup" ], "severity": "Medium", "subcategory": "Backup", - "text": "Backup Your Workspace Configuration including ARM templates and Secret Scopes", + "text": "Backup your workspace configuration including ARM templates and secret scopes", "waf": "Reliability" }, { @@ -44207,13 +45093,14 @@ "checklist": "DataBricks Review Checklist", "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", "services": [ - "Backup", - "ACR" + "ACR", + "Backup" ], "severity": "Medium", "subcategory": "Backup", - "text": "Share MetaData Across different Databricks Workspaces using Hive External Metastore", + "text": "Share metaData across different Databricks workspaces using Hive external metastore", "waf": "Reliability" }, { @@ -44221,13 +45108,14 @@ "checklist": "DataBricks Review Checklist", "guid": "769e3969-0e78-428a-a936-657d03b0f466", "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", "services": [ "ASR", "Backup" ], "severity": "Medium", "subcategory": "Backup", - "text": "Plan Disaster Recovery Strategy in Databricks using the Hive External Metastore", + "text": "Plan Disaster Recovery strategy in Databricks using the Hive External Metastore", "waf": "Reliability" }, { @@ -44235,6 +45123,7 @@ "checklist": "DataBricks Review Checklist", "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", "services": [ "Backup" ], @@ -44246,9 +45135,10 @@ { "category": "Operations Management", "checklist": "DataBricks Review Checklist", - "description": "Download the blob using Secondary Endpoint in RAGRS Storage Account", + "description": "Download the blob using the secondary endpoint in RAGRS storage account", "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", "services": [ "Storage", "Backup" @@ -44263,6 +45153,7 @@ "checklist": "DataBricks Review Checklist", "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", "services": [ "Backup" ], @@ -44276,6 +45167,7 @@ "checklist": "DataBricks Review Checklist", "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", "services": [ "ASR" ], @@ -44290,6 +45182,7 @@ "description": "Migration package to log all Databricks resources for backup and/or migrating to another Databricks workspace", "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", "services": [ "Backup" ], @@ -44298,17 +45191,6 @@ "text": "Use Databricks Migration tools", "waf": "Reliability" }, - { - "category": "Operations Management", - "checklist": "DataBricks Review Checklist", - "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", - "link": "https://github.com/databrickslabs/databricks-sync", - "services": [], - "severity": "Low", - "subcategory": "Migration", - "text": "Use Databricks Sync", - "waf": "Reliability" - }, { "category": "Operations Management", "checklist": "Recovery Services Vault Checklist", @@ -44326,9 +45208,9 @@ "guid": "67b23587-05a1-4652-aded-fa8a488cdec4", "link": "https://learn.microsoft.com/azure/site-recovery/azure-to-azure-how-to-enable-policy", "services": [ - "AzurePolicy", "VM", - "ASR" + "ASR", + "AzurePolicy" ], "severity": "High", "subcategory": "Replication", diff --git a/checklists/databricks_checklist.en.json b/checklists/databricks_checklist.en.json index 6ea4f48e..de4ed20d 100644 --- a/checklists/databricks_checklist.en.json +++ b/checklists/databricks_checklist.en.json @@ -1,203 +1,203 @@ { - "items": [ - { - "category": "Operations Management", - "subcategory": "Best Practices", - "text": "Reference Databricks HA/DR playbook", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "65285269-440c-44be-9d3e-0844276d4bdc", - "id": "46.1", - "severity": "High", - "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx" - }, - { - "category": "Operations Management", - "subcategory": "Backup", - "text": "Backup your workspace configuration including ARM templates and secret scopes", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", - "id": "46.2", - "severity": "Medium", - "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes" - }, - { - "category": "Operations Management", - "subcategory": "Backup", - "text": "Share metaData across different Databricks workspaces using Hive external metastore", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", - "id": "46.3", - "severity": "Medium", - "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757" - }, - { - "category": "Operations Management", - "subcategory": "Backup", - "text": "Plan Disaster Recovery strategy in Databricks using the Hive External Metastore", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "769e3969-0e78-428a-a936-657d03b0f466", - "id": "46.4", - "severity": "Medium", - "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581" - }, - { - "category": "Operations Management", - "subcategory": "Backup", - "text": "Backup your data with deep and shallow clones", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", - "id": "46.5", - "severity": "Medium", - "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html" - }, - { - "category": "Operations Management", - "subcategory": "Backup", - "text": "Backup your data to Azure Storage RA-GRS", - "description": "Download the blob using the secondary endpoint in RAGRS storage account", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", - "id": "46.6", - "severity": "Medium", - "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750" - }, - { - "category": "Operations Management", - "subcategory": "Backup", - "text": "Backup your code with DevOps", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", - "id": "46.7", - "severity": "High", - "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd" - }, - { - "category": "Operations Management", - "subcategory": "Disaster Recovery", - "text": "Plan for Disaster recovery using Active/Active or Active/Passive Configuration", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", - "id": "46.8", - "severity": "High", - "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery" - }, - { - "category": "Operations Management", - "subcategory": "Migration", - "text": "Use Databricks Migration tools", - "description": "Migration package to log all Databricks resources for backup and/or migrating to another Databricks workspace", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", - "id": "46.9", - "severity": "Medium", - "link": "https://github.com/databrickslabs/migrate" - }, - { - "category": "Operations Management", - "subcategory": "Migration", - "text": "Use Databricks Sync", - "waf": "Reliability", - "service": "Azure Data Factory", - "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", - "id": "46.10", - "severity": "Low", - "link": "https://github.com/databrickslabs/databricks-sync" + "items": [ + { + "category": "Operations Management", + "subcategory": "Best Practices", + "text": "Reference Databricks HA/DR playbook", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "id": "46.1", + "severity": "High", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx" + }, + { + "category": "Operations Management", + "subcategory": "Migration", + "text": "Use Databricks Sync", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "id": "46.10", + "severity": "Low", + "link": "https://github.com/databrickslabs/databricks-sync" + }, + { + "category": "Operations Management", + "subcategory": "Backup", + "text": "Backup your workspace configuration including ARM templates and secret scopes", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "id": "46.2", + "severity": "Medium", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes" + }, + { + "category": "Operations Management", + "subcategory": "Backup", + "text": "Share metaData across different Databricks workspaces using Hive external metastore", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "id": "46.3", + "severity": "Medium", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757" + }, + { + "category": "Operations Management", + "subcategory": "Backup", + "text": "Plan Disaster Recovery strategy in Databricks using the Hive External Metastore", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "id": "46.4", + "severity": "Medium", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581" + }, + { + "category": "Operations Management", + "subcategory": "Backup", + "text": "Backup your data with deep and shallow clones", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "id": "46.5", + "severity": "Medium", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html" + }, + { + "category": "Operations Management", + "subcategory": "Backup", + "text": "Backup your data to Azure Storage RA-GRS", + "description": "Download the blob using the secondary endpoint in RAGRS storage account", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "id": "46.6", + "severity": "Medium", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750" + }, + { + "category": "Operations Management", + "subcategory": "Backup", + "text": "Backup your code with DevOps", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "id": "46.7", + "severity": "High", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd" + }, + { + "category": "Operations Management", + "subcategory": "Disaster Recovery", + "text": "Plan for Disaster recovery using Active/Active or Active/Passive Configuration", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "id": "46.8", + "severity": "High", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery" + }, + { + "category": "Operations Management", + "subcategory": "Migration", + "text": "Use Databricks Migration tools", + "description": "Migration package to log all Databricks resources for backup and/or migrating to another Databricks workspace", + "waf": "Reliability", + "service": "Azure Data Factory", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "id": "46.9", + "severity": "Medium", + "link": "https://github.com/databrickslabs/migrate" + } + ], + "categories": [ + { + "name": "Identity and Access Management" + }, + { + "name": "Network Topology and Connectivity" + }, + { + "name": "BC and DR" + }, + { + "name": "Governance and Security" + }, + { + "name": "Cost Governance" + }, + { + "name": "Operations Management" + }, + { + "name": "Application Deployment" + } + ], + "waf": [ + { + "name": "Reliability" + }, + { + "name": "Security" + }, + { + "name": "Cost" + }, + { + "name": "Operations" + }, + { + "name": "Performance" + } + ], + "yesno": [ + { + "name": "Yes" + }, + { + "name": "No" + } + ], + "status": [ + { + "name": "Not verified", + "description": "This check has not been looked at yet" + }, + { + "name": "Open", + "description": "There is an action item associated to this check" + }, + { + "name": "Fulfilled", + "description": "This check has been verified, and there are no further action items associated to it" + }, + { + "name": "Not required", + "description": "Recommendation understood, but not needed by current requirements" + }, + { + "name": "N/A", + "description": "Not applicable for current design" + } + ], + "severities": [ + { + "name": "High" + }, + { + "name": "Medium" + }, + { + "name": "Low" + } + ], + "metadata": { + "name": "DataBricks Review Checklist", + "state": "Preview", + "waf": "Reliability", + "timestamp": "October 21, 2024" } - ], - "categories": [ - { - "name": "Identity and Access Management" - }, - { - "name": "Network Topology and Connectivity" - }, - { - "name": "BC and DR" - }, - { - "name": "Governance and Security" - }, - { - "name": "Cost Governance" - }, - { - "name": "Operations Management" - }, - { - "name": "Application Deployment" - } - ], - "waf": [ - { - "name": "Reliability" - }, - { - "name": "Security" - }, - { - "name": "Cost" - }, - { - "name": "Operations" - }, - { - "name": "Performance" - } - ], - "yesno": [ - { - "name": "Yes" - }, - { - "name": "No" - } - ], - "status": [ - { - "name": "Not verified", - "description": "This check has not been looked at yet" - }, - { - "name": "Open", - "description": "There is an action item associated to this check" - }, - { - "name": "Fulfilled", - "description": "This check has been verified, and there are no further action items associated to it" - }, - { - "name": "Not required", - "description": "Recommendation understood, but not needed by current requirements" - }, - { - "name": "N/A", - "description": "Not applicable for current design" - } - ], - "severities": [ - { - "name": "High" - }, - { - "name": "Medium" - }, - { - "name": "Low" - } - ], - "metadata": { - "name": "DataBricks Review Checklist", - "state": "Preview", - "waf": "Reliability", - "timestamp": "April 19, 2024" - } -} +} \ No newline at end of file diff --git a/checklists/databricks_checklist.es.json b/checklists/databricks_checklist.es.json new file mode 100644 index 00000000..b1ffff96 --- /dev/null +++ b/checklists/databricks_checklist.es.json @@ -0,0 +1,203 @@ +{ + "categories": [ + { + "name": "Gestión de identidades y accesos" + }, + { + "name": "Topología de red y conectividad" + }, + { + "name": "BC y RD" + }, + { + "name": "Gobernabilidad y seguridad" + }, + { + "name": "Gobernanza de costos" + }, + { + "name": "Gestión de Operaciones" + }, + { + "name": "Implementación de aplicaciones" + } + ], + "items": [ + { + "category": "Gestión de Operaciones", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "id": "46.1", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "Alto", + "subcategory": "Prácticas recomendadas", + "text": "Referencia: Manual de estrategias de alta disponibilidad y recuperación ante desastres de Databricks", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "id": "46.10", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "Bajo", + "subcategory": "Migración", + "text": "Uso de Databricks Sync", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "id": "46.2", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "Medio", + "subcategory": "Copia de seguridad", + "text": "Copia de seguridad de la configuración del área de trabajo, incluidas las plantillas de ARM y los ámbitos secretos", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "id": "46.3", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "Medio", + "subcategory": "Copia de seguridad", + "text": "Compartir metadatos entre diferentes áreas de trabajo de Databricks mediante el metastore externo de Hive", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "id": "46.4", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "Medio", + "subcategory": "Copia de seguridad", + "text": "Planeación de la estrategia de recuperación ante desastres en Databricks mediante el metastore externo de Hive", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "id": "46.5", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "Medio", + "subcategory": "Copia de seguridad", + "text": "Haz una copia de seguridad de tus datos con clones profundos y superficiales", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "description": "Descargar el blob mediante el punto de conexión secundario en la cuenta de almacenamiento de RAGRS", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "id": "46.6", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "Medio", + "subcategory": "Copia de seguridad", + "text": "Copia de seguridad de los datos en Azure Storage RA-GRS", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "id": "46.7", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "Alto", + "subcategory": "Copia de seguridad", + "text": "Copia de seguridad de su código con DevOps", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "id": "46.8", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "Alto", + "subcategory": "Recuperación ante desastres", + "text": "Planeación de la recuperación ante desastres mediante la configuración activa/activa o activa/pasiva", + "waf": "Fiabilidad" + }, + { + "category": "Gestión de Operaciones", + "description": "Paquete de migración para registrar todos los recursos de Databricks para la copia de seguridad o la migración a otra área de trabajo de Databricks", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "id": "46.9", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "Medio", + "subcategory": "Migración", + "text": "Uso de las herramientas de migración de Databricks", + "waf": "Fiabilidad" + } + ], + "metadata": { + "name": "DataBricks Review Checklist", + "state": "Preview", + "timestamp": "October 21, 2024", + "waf": "Reliability" + }, + "severities": [ + { + "name": "Alto" + }, + { + "name": "Medio" + }, + { + "name": "Bajo" + } + ], + "status": [ + { + "description": "Esta comprobación aún no se ha examinado", + "name": "No verificado" + }, + { + "description": "Hay un elemento de acción asociado a esta comprobación", + "name": "Abrir" + }, + { + "description": "Esta comprobación se ha verificado y no hay más elementos de acción asociados a ella", + "name": "Cumplido" + }, + { + "description": "Recomendación comprendida, pero no necesaria por los requisitos actuales", + "name": "No es necesario" + }, + { + "description": "No aplicable para el diseño actual", + "name": "N/A" + } + ], + "waf": [ + { + "name": "Fiabilidad" + }, + { + "name": "Seguridad" + }, + { + "name": "Costar" + }, + { + "name": "Operaciones" + }, + { + "name": "Rendimiento" + } + ], + "yesno": [ + { + "name": "Sí" + }, + { + "name": "No" + } + ] +} \ No newline at end of file diff --git a/checklists/databricks_checklist.ja.json b/checklists/databricks_checklist.ja.json new file mode 100644 index 00000000..2f1f51ca --- /dev/null +++ b/checklists/databricks_checklist.ja.json @@ -0,0 +1,203 @@ +{ + "categories": [ + { + "name": "ID およびアクセス管理" + }, + { + "name": "ネットワーク トポロジと接続性" + }, + { + "name": "BC と DR" + }, + { + "name": "ガバナンスとセキュリティ" + }, + { + "name": "コストガバナンス" + }, + { + "name": "オペレーションマネジメント" + }, + { + "name": "アプリケーションのデプロイメント" + } + ], + "items": [ + { + "category": "オペレーションマネジメント", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "id": "46.1", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "高い", + "subcategory": "ベストプラクティス", + "text": "リファレンス Databricks HA/DR プレイブック", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "id": "46.10", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "低い", + "subcategory": "移動", + "text": "Databricks Sync を使用する", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "id": "46.2", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "中程度", + "subcategory": "バックアップ", + "text": "ARM テンプレートやシークレット スコープを含むワークスペース構成のバックアップ", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "id": "46.3", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "中程度", + "subcategory": "バックアップ", + "text": "Hive 外部メタストアを使用して、異なる Databricks ワークスペース間でメタデータを共有する", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "id": "46.4", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "中程度", + "subcategory": "バックアップ", + "text": "Hive 外部メタストアを使用した Databricks でのディザスター リカバリー戦略の計画", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "id": "46.5", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "中程度", + "subcategory": "バックアップ", + "text": "ディープクローンとシャロークローンでデータをバックアップ", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "description": "RAGRS ストレージ アカウントのセカンダリ エンドポイントを使用して BLOB をダウンロードする", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "id": "46.6", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "中程度", + "subcategory": "バックアップ", + "text": "Azure Storage RA-GRS にデータをバックアップする", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "id": "46.7", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "高い", + "subcategory": "バックアップ", + "text": "DevOps でコードをバックアップする", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "id": "46.8", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "高い", + "subcategory": "ディザスタリカバリ", + "text": "アクティブ/アクティブまたはアクティブ/パッシブ構成を使用した障害復旧の計画", + "waf": "確実" + }, + { + "category": "オペレーションマネジメント", + "description": "バックアップや別の Databricks ワークスペースへの移行のためにすべての Databricks リソースをログに記録する移行パッケージ", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "id": "46.9", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "中程度", + "subcategory": "移動", + "text": "Databricks 移行ツールを使用する", + "waf": "確実" + } + ], + "metadata": { + "name": "DataBricks Review Checklist", + "state": "Preview", + "timestamp": "October 21, 2024", + "waf": "Reliability" + }, + "severities": [ + { + "name": "高い" + }, + { + "name": "中程度" + }, + { + "name": "低い" + } + ], + "status": [ + { + "description": "このチェックはまだ見ていません", + "name": "未確認" + }, + { + "description": "このチェックにはアクションアイテムが関連付けられています", + "name": "開ける" + }, + { + "description": "このチェックは検証済みであり、これ以上のアクション アイテムは関連付けられていません", + "name": "達成" + }, + { + "description": "推奨事項は理解されているが、現在の要件では必要ではない", + "name": "必須ではありません" + }, + { + "description": "現在のデザインには適用されません", + "name": "該当なし" + } + ], + "waf": [ + { + "name": "確実" + }, + { + "name": "安全" + }, + { + "name": "費用" + }, + { + "name": "オペレーションズ" + }, + { + "name": "パフォーマンス" + } + ], + "yesno": [ + { + "name": "はい" + }, + { + "name": "いいえ" + } + ] +} \ No newline at end of file diff --git a/checklists/databricks_checklist.ko.json b/checklists/databricks_checklist.ko.json new file mode 100644 index 00000000..87ef8f51 --- /dev/null +++ b/checklists/databricks_checklist.ko.json @@ -0,0 +1,203 @@ +{ + "categories": [ + { + "name": "ID 및 액세스 관리" + }, + { + "name": "네트워크 토폴로지 및 연결" + }, + { + "name": "BC 및 DR" + }, + { + "name": "거버넌스 및 보안" + }, + { + "name": "비용 관리" + }, + { + "name": "운영 관리" + }, + { + "name": "응용 프로그램 배포" + } + ], + "items": [ + { + "category": "운영 관리", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "id": "46.1", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "높다", + "subcategory": "권장사항", + "text": "Databricks HA/DR 플레이북 참조", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "id": "46.10", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "낮다", + "subcategory": "이주", + "text": "Databricks Sync 사용", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "id": "46.2", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "보통", + "subcategory": "백업", + "text": "ARM 템플릿 및 비밀 범위를 포함한 작업 영역 구성 백업Backup your workspace configuration including ARM templates and secret scopes", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "id": "46.3", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "보통", + "subcategory": "백업", + "text": "Hive 외부 메타스토어를 사용하여 여러 Databricks 작업 영역에서 메타데이터 공유", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "id": "46.4", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "보통", + "subcategory": "백업", + "text": "Hive 외부 메타스토어를 사용하여 Databricks에서 재해 복구 전략 계획", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "id": "46.5", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "보통", + "subcategory": "백업", + "text": "깊고 얕은 클론으로 데이터 백업", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "description": "RAGRS 스토리지 계정의 보조 엔드포인트를 사용하여 Blob 다운로드Download the blob using the secondary endpoint in RAGRS storage account", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "id": "46.6", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "보통", + "subcategory": "백업", + "text": "Azure Storage RA-GRS에 데이터 백업", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "id": "46.7", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "높다", + "subcategory": "백업", + "text": "DevOps를 사용하여 코드 백업", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "id": "46.8", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "높다", + "subcategory": "재해 복구", + "text": "액티브/액티브 또는 액티브/패시브 구성을 사용한 재해 복구 계획Plan for Disaster recovery using Active/Active or Active/Passive Configuration", + "waf": "신뢰도" + }, + { + "category": "운영 관리", + "description": "백업 및/또는 다른 Databricks 작업 영역으로 마이그레이션하기 위해 모든 Databricks 리소스를 기록하는 마이그레이션 패키지", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "id": "46.9", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "보통", + "subcategory": "이주", + "text": "Databricks 마이그레이션 도구 사용", + "waf": "신뢰도" + } + ], + "metadata": { + "name": "DataBricks Review Checklist", + "state": "Preview", + "timestamp": "October 21, 2024", + "waf": "Reliability" + }, + "severities": [ + { + "name": "높다" + }, + { + "name": "보통" + }, + { + "name": "낮다" + } + ], + "status": [ + { + "description": "이 검사는 아직 검토되지 않았습니다", + "name": "확인되지 않음" + }, + { + "description": "이 검사와 연관된 작업 항목이 있습니다", + "name": "열다" + }, + { + "description": "이 검사는 확인되었으며 이와 관련된 추가 작업 항목이 없습니다", + "name": "성취" + }, + { + "description": "권장 사항을 이해했지만 현재 요구 사항에 필요하지 않음", + "name": "필요 없음" + }, + { + "description": "현재 설계에는 적용되지 않습니다.", + "name": "해당 없음" + } + ], + "waf": [ + { + "name": "신뢰도" + }, + { + "name": "안전" + }, + { + "name": "비용" + }, + { + "name": "작업" + }, + { + "name": "공연" + } + ], + "yesno": [ + { + "name": "예" + }, + { + "name": "아니요" + } + ] +} \ No newline at end of file diff --git a/checklists/databricks_checklist.pt.json b/checklists/databricks_checklist.pt.json new file mode 100644 index 00000000..8787a1a1 --- /dev/null +++ b/checklists/databricks_checklist.pt.json @@ -0,0 +1,203 @@ +{ + "categories": [ + { + "name": "Gerenciamento de identidade e acesso" + }, + { + "name": "Topologia e conectividade de rede" + }, + { + "name": "BC e DR" + }, + { + "name": "Governança e segurança" + }, + { + "name": "Governança de custos" + }, + { + "name": "Gestão de Operações" + }, + { + "name": "Implantação de aplicativos" + } + ], + "items": [ + { + "category": "Gestão de Operações", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "id": "46.1", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "Alto", + "subcategory": "Melhores práticas", + "text": "Guia estratégico de HA/DR do Databricks de referência", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "id": "46.10", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "Baixo", + "subcategory": "Migração", + "text": "Usar a Sincronização do Databricks", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "id": "46.2", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "Média", + "subcategory": "Backup", + "text": "Faça backup da configuração do workspace, incluindo modelos do ARM e escopos secretos", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "id": "46.3", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "Média", + "subcategory": "Backup", + "text": "Compartilhar metadados em diferentes workspaces do Databricks usando o metastore externo do Hive", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "id": "46.4", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "Média", + "subcategory": "Backup", + "text": "Planejar a estratégia de recuperação de desastre no Databricks usando o Metastore Externo do Hive", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "id": "46.5", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "Média", + "subcategory": "Backup", + "text": "Faça backup de seus dados com clones profundos e superficiais", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "description": "Baixar o blob usando o ponto de extremidade secundário na conta de armazenamento RAGRS", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "id": "46.6", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "Média", + "subcategory": "Backup", + "text": "Faça backup de seus dados no RA-GRS do Armazenamento do Azure", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "id": "46.7", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "Alto", + "subcategory": "Backup", + "text": "Faça backup do seu código com DevOps", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "id": "46.8", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "Alto", + "subcategory": "Recuperação de desastres", + "text": "Planejar a recuperação de desastres usando a configuração ativa/ativa ou ativa/passiva", + "waf": "Fiabilidade" + }, + { + "category": "Gestão de Operações", + "description": "Pacote de migração para registrar todos os recursos do Databricks para backup e/ou migração para outro workspace do Databricks", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "id": "46.9", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "Média", + "subcategory": "Migração", + "text": "Usar as ferramentas de migração do Databricks", + "waf": "Fiabilidade" + } + ], + "metadata": { + "name": "DataBricks Review Checklist", + "state": "Preview", + "timestamp": "October 21, 2024", + "waf": "Reliability" + }, + "severities": [ + { + "name": "Alto" + }, + { + "name": "Média" + }, + { + "name": "Baixo" + } + ], + "status": [ + { + "description": "Esta verificação ainda não foi analisada", + "name": "Não verificado" + }, + { + "description": "Há um item de ação associado a essa verificação", + "name": "Abrir" + }, + { + "description": "Essa verificação foi verificada e não há mais itens de ação associados a ela", + "name": "Cumprido" + }, + { + "description": "Recomendação compreendida, mas não necessária pelos requisitos atuais", + "name": "Não é necessário" + }, + { + "description": "Não aplicável para o projeto atual", + "name": "N/A" + } + ], + "waf": [ + { + "name": "Fiabilidade" + }, + { + "name": "Segurança" + }, + { + "name": "Custar" + }, + { + "name": "Operações" + }, + { + "name": "Desempenho" + } + ], + "yesno": [ + { + "name": "Sim" + }, + { + "name": "Não" + } + ] +} \ No newline at end of file diff --git a/checklists/databricks_checklist.zh-Hant.json b/checklists/databricks_checklist.zh-Hant.json new file mode 100644 index 00000000..d55fbea6 --- /dev/null +++ b/checklists/databricks_checklist.zh-Hant.json @@ -0,0 +1,203 @@ +{ + "categories": [ + { + "name": "身份和訪問管理" + }, + { + "name": "網路拓撲和連接" + }, + { + "name": "BC 和DR" + }, + { + "name": "治理和安全" + }, + { + "name": "成本治理" + }, + { + "name": "運營管理" + }, + { + "name": "應用程式部署" + } + ], + "items": [ + { + "category": "運營管理", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "id": "46.1", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "高", + "subcategory": "最佳實踐", + "text": "參考 Databricks HA/DR playbook", + "waf": "可靠性" + }, + { + "category": "運營管理", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "id": "46.10", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "低", + "subcategory": "遷移", + "text": "使用 Databricks Sync", + "waf": "可靠性" + }, + { + "category": "運營管理", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "id": "46.2", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "中等", + "subcategory": "備份", + "text": "備份工作區配置,包括ARM範本和機密範圍", + "waf": "可靠性" + }, + { + "category": "運營管理", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "id": "46.3", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "中等", + "subcategory": "備份", + "text": "使用Hive外部元存儲在不同的 Databricks 工作區之間共用元數據", + "waf": "可靠性" + }, + { + "category": "運營管理", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "id": "46.4", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "中等", + "subcategory": "備份", + "text": "使用Hive外部元存儲在 Databricks 中規劃災難恢復策略", + "waf": "可靠性" + }, + { + "category": "運營管理", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "id": "46.5", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "中等", + "subcategory": "備份", + "text": "使用深層和淺層克隆備份數據", + "waf": "可靠性" + }, + { + "category": "運營管理", + "description": "使用RAGRS儲存帳戶中的輔助終結點下載 blob", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "id": "46.6", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "中等", + "subcategory": "備份", + "text": "將數據備份到 Azure 儲存 RA-GRS", + "waf": "可靠性" + }, + { + "category": "運營管理", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "id": "46.7", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "高", + "subcategory": "備份", + "text": "使用DevOps備份代碼", + "waf": "可靠性" + }, + { + "category": "運營管理", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "id": "46.8", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "高", + "subcategory": "災難恢復", + "text": "使用主動/主動或主動/被動配置規劃災難恢復", + "waf": "可靠性" + }, + { + "category": "運營管理", + "description": "遷移包,用於記錄所有 Databricks 資源,以便備份和/或遷移到另一個 Databricks 工作區", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "id": "46.9", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "中等", + "subcategory": "遷移", + "text": "使用 Databricks 遷移工具", + "waf": "可靠性" + } + ], + "metadata": { + "name": "DataBricks Review Checklist", + "state": "Preview", + "timestamp": "October 21, 2024", + "waf": "Reliability" + }, + "severities": [ + { + "name": "高" + }, + { + "name": "中等" + }, + { + "name": "低" + } + ], + "status": [ + { + "description": "尚未查看此檢查", + "name": "未驗證" + }, + { + "description": "存在與此檢查關聯的操作項", + "name": "打開" + }, + { + "description": "此檢查已經過驗證,沒有與之關聯的其他操作項", + "name": "實現" + }, + { + "description": "建議已理解,但當前要求不需要", + "name": "不需要" + }, + { + "description": "不適用於當前設計", + "name": "不適用" + } + ], + "waf": [ + { + "name": "可靠性" + }, + { + "name": "安全" + }, + { + "name": "成本" + }, + { + "name": "操作" + }, + { + "name": "性能" + } + ], + "yesno": [ + { + "name": "是的" + }, + { + "name": "不" + } + ] +} \ No newline at end of file diff --git a/checklists/waf_checklist.en.json b/checklists/waf_checklist.en.json index 096f1a7d..5290d06e 100644 --- a/checklists/waf_checklist.en.json +++ b/checklists/waf_checklist.en.json @@ -8050,6 +8050,17 @@ "text": "Store passwords, secerts and keys in Azure key vault", "waf": "Security" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "You can store credentials or secret values in an Azure Key Vault and use them during pipeline execution to pass to your activities.", + "guid": "a3aec2c4-e243-46b0-936d-b55e17960eee", + "link": "https://learn.microsoft.com/azure/data-factory/how-to-use-azure-key-vault-secrets-pipeline-activities", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Use Azure Key Vault secrets in pipeline activities", + "waf": "Security" + }, { "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", @@ -8081,6 +8092,15 @@ "text": "Separate and limit highly privileged/administrative users and enable MFA and conditional policies", "waf": "Security" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "guid": "4e4f1854-287d-45cd-a126-cc032af5b1fc", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Disable access over public internet and configure either firewall rules or trusted services rules", + "waf": "Security" + }, { "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", @@ -8111,6 +8131,17 @@ "text": "Configure managed private endpoints to connect to resources using managed azure IR", "waf": "Security" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "By using Azure Private Link, you can connect to various platform as a service (PaaS) deployments in Azure via a private endpoint. A private endpoint is a private IP address within a specific virtual network and subnet", + "guid": "b47a393a-0804-4272-a479-8b1578b219a4", + "link": "https://learn.microsoft.com/azure/data-factory/data-factory-private-link", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Configure Private Links to connect to sources in customer Vnet and data factory", + "waf": "Security" + }, { "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", @@ -8152,6 +8183,28 @@ "text": "Store passwords, secrets in Azure Key Vault", "waf": "Security" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "You can store credentials or secret values in an Azure Key Vault and use them during pipeline execution to pass to your activities.", + "guid": "6f4a1652-bddd-4ea8-a487-cdec4861bc3b", + "link": "https://learn.microsoft.com/azure/data-factory/how-to-use-azure-key-vault-secrets-pipeline-activities", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Use Azure Key Vault secrets in pipeline activities", + "waf": "Security" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "You can encrypt and store credentials for any of your on-premises data stores (linked services with sensitive information) on a machine with self-hosted integration runtime.", + "guid": "c14aeb7e-66e8-4d9a-9bec-218e6436b173", + "link": "https://learn.microsoft.com/azure/data-factory/encrypt-credentials-self-hosted-integration-runtime", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Encrypt credentials for on-premises using SHIR data stores in Azure Data Factory", + "waf": "Security" + }, { "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", "guid": "6db55f57-9603-4334-adf9-cc23418db612", @@ -8416,6 +8469,17 @@ "text": "Limit cluster creation rights.", "waf": "Security" }, + { + "arm-service": "Microsoft.Databricks/workspaces", + "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", + "description": "Account admins can configure a workspace setting called RestrictWorkspaceAdmins to restrict workspace admins to only change a job owner to themselves and the job run as setting to a service principal that they have the Service Principal User role on.", + "guid": "6b57dfc6-5546-41e1-a3e3-453a3c863964", + "link": "https://learn.microsoft.com/azure/databricks/admin/workspace-settings/restrict-workspace-admins", + "service": "Azure Databricks", + "severity": "High", + "text": "Restrict workspace admins", + "waf": "Security" + }, { "arm-service": "Microsoft.Databricks/workspaces", "checklist": "Use the 'Import latest checklist' button to get the latest version of a review checklist", @@ -11666,6 +11730,108 @@ "text": "If deploying to an Isolated environment, use or migrate to App Service Environment (ASE) v3", "waf": "Reliability" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "High", + "text": "Reference Databricks HA/DR playbook", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "Low", + "text": "Use Databricks Sync", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Backup your workspace configuration including ARM templates and secret scopes", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Share metaData across different Databricks workspaces using Hive external metastore", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Plan Disaster Recovery strategy in Databricks using the Hive External Metastore", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Backup your data with deep and shallow clones", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "Download the blob using the secondary endpoint in RAGRS storage account", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Backup your data to Azure Storage RA-GRS", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "High", + "text": "Backup your code with DevOps", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "High", + "text": "Plan for Disaster recovery using Active/Active or Active/Passive Configuration", + "waf": "Reliability" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "Migration package to log all Databricks resources for backup and/or migrating to another Databricks workspace", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "Medium", + "text": "Use Databricks Migration tools", + "waf": "Reliability" + }, { "checklist": "Identity Review Checklist", "guid": "bb235c70-5e17-496f-bedf-a8a4c8cdec4c", diff --git a/checklists/waf_checklist.es.json b/checklists/waf_checklist.es.json index f39a2762..4ae10997 100644 --- a/checklists/waf_checklist.es.json +++ b/checklists/waf_checklist.es.json @@ -1472,6 +1472,108 @@ "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations", "waf": "Seguridad" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "Alto", + "text": "Referencia: Manual de estrategias de alta disponibilidad y recuperación ante desastres de Databricks", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "Bajo", + "text": "Uso de Databricks Sync", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "Medio", + "text": "Copia de seguridad de la configuración del área de trabajo, incluidas las plantillas de ARM y los ámbitos secretos", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "Medio", + "text": "Compartir metadatos entre diferentes áreas de trabajo de Databricks mediante el metastore externo de Hive", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "Medio", + "text": "Planeación de la estrategia de recuperación ante desastres en Databricks mediante el metastore externo de Hive", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "Medio", + "text": "Haz una copia de seguridad de tus datos con clones profundos y superficiales", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "Descargar el blob mediante el punto de conexión secundario en la cuenta de almacenamiento de RAGRS", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "Medio", + "text": "Copia de seguridad de los datos en Azure Storage RA-GRS", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "Alto", + "text": "Copia de seguridad de su código con DevOps", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "Alto", + "text": "Planeación de la recuperación ante desastres mediante la configuración activa/activa o activa/pasiva", + "waf": "Fiabilidad" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "Paquete de migración para registrar todos los recursos de Databricks para la copia de seguridad o la migración a otra área de trabajo de Databricks", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "Medio", + "text": "Uso de las herramientas de migración de Databricks", + "waf": "Fiabilidad" + }, { "arm-service": "Microsoft.AVS/privateClouds", "checklist": "Azure VMware Solution Design Review", diff --git a/checklists/waf_checklist.ja.json b/checklists/waf_checklist.ja.json index 60e36bcd..15eefbd5 100644 --- a/checklists/waf_checklist.ja.json +++ b/checklists/waf_checklist.ja.json @@ -5483,6 +5483,108 @@ "text": "RBAC は、キー コンテナーへのアクセスを制御するために推奨されます。Key Vault のアクセス制御ガイダンスについて理解しておいてください。", "waf": "安全" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "高い", + "text": "リファレンス Databricks HA/DR プレイブック", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "低い", + "text": "Databricks Sync を使用する", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "中程度", + "text": "ARM テンプレートやシークレット スコープを含むワークスペース構成のバックアップ", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "中程度", + "text": "Hive 外部メタストアを使用して、異なる Databricks ワークスペース間でメタデータを共有する", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "中程度", + "text": "Hive 外部メタストアを使用した Databricks でのディザスター リカバリー戦略の計画", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "中程度", + "text": "ディープクローンとシャロークローンでデータをバックアップ", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "RAGRS ストレージ アカウントのセカンダリ エンドポイントを使用して BLOB をダウンロードする", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "中程度", + "text": "Azure Storage RA-GRS にデータをバックアップする", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "高い", + "text": "DevOps でコードをバックアップする", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "高い", + "text": "アクティブ/アクティブまたはアクティブ/パッシブ構成を使用した障害復旧の計画", + "waf": "確実" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "バックアップや別の Databricks ワークスペースへの移行のためにすべての Databricks リソースをログに記録する移行パッケージ", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "中程度", + "text": "Databricks 移行ツールを使用する", + "waf": "確実" + }, { "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "Azure Data Factory Review Checklist", diff --git a/checklists/waf_checklist.ko.json b/checklists/waf_checklist.ko.json index 14560dac..70ac0f31 100644 --- a/checklists/waf_checklist.ko.json +++ b/checklists/waf_checklist.ko.json @@ -8801,6 +8801,108 @@ "text": "Keyvault 통합을 사용하는 경우 Keyvault의 SLA를 사용하여 가용성을 파악합니다", "waf": "신뢰도" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "높다", + "text": "Databricks HA/DR 플레이북 참조", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "낮다", + "text": "Databricks Sync 사용", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "보통", + "text": "ARM 템플릿 및 비밀 범위를 포함한 작업 영역 구성 백업Backup your workspace configuration including ARM templates and secret scopes", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "보통", + "text": "Hive 외부 메타스토어를 사용하여 여러 Databricks 작업 영역에서 메타데이터 공유", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "보통", + "text": "Hive 외부 메타스토어를 사용하여 Databricks에서 재해 복구 전략 계획", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "보통", + "text": "깊고 얕은 클론으로 데이터 백업", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "RAGRS 스토리지 계정의 보조 엔드포인트를 사용하여 Blob 다운로드Download the blob using the secondary endpoint in RAGRS storage account", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "보통", + "text": "Azure Storage RA-GRS에 데이터 백업", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "높다", + "text": "DevOps를 사용하여 코드 백업", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "높다", + "text": "액티브/액티브 또는 액티브/패시브 구성을 사용한 재해 복구 계획Plan for Disaster recovery using Active/Active or Active/Passive Configuration", + "waf": "신뢰도" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "백업 및/또는 다른 Databricks 작업 영역으로 마이그레이션하기 위해 모든 Databricks 리소스를 기록하는 마이그레이션 패키지", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "보통", + "text": "Databricks 마이그레이션 도구 사용", + "waf": "신뢰도" + }, { "arm-service": "Microsoft.ApiManagement/service", "checklist": "Azure API Management Review", diff --git a/checklists/waf_checklist.pt.json b/checklists/waf_checklist.pt.json index b9ee7f3d..777ed2fc 100644 --- a/checklists/waf_checklist.pt.json +++ b/checklists/waf_checklist.pt.json @@ -1139,6 +1139,108 @@ "text": "Backup e restauração de um índice de pesquisa cognitiva do Azure. Use este código de exemplo para fazer backup da definição de índice e instantâneo em uma série de arquivos Json", "waf": "Fiabilidade" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "Alto", + "text": "Guia estratégico de HA/DR do Databricks de referência", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "Baixo", + "text": "Usar a Sincronização do Databricks", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "Média", + "text": "Faça backup da configuração do workspace, incluindo modelos do ARM e escopos secretos", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "Média", + "text": "Compartilhar metadados em diferentes workspaces do Databricks usando o metastore externo do Hive", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "Média", + "text": "Planejar a estratégia de recuperação de desastre no Databricks usando o Metastore Externo do Hive", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "Média", + "text": "Faça backup de seus dados com clones profundos e superficiais", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "Baixar o blob usando o ponto de extremidade secundário na conta de armazenamento RAGRS", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "Média", + "text": "Faça backup de seus dados no RA-GRS do Armazenamento do Azure", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "Alto", + "text": "Faça backup do seu código com DevOps", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "Alto", + "text": "Planejar a recuperação de desastres usando a configuração ativa/ativa ou ativa/passiva", + "waf": "Fiabilidade" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "Pacote de migração para registrar todos os recursos do Databricks para backup e/ou migração para outro workspace do Databricks", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "Média", + "text": "Usar as ferramentas de migração do Databricks", + "waf": "Fiabilidade" + }, { "arm-service": "Microsoft.DataFactory/datafactories", "checklist": "Azure Data Factory Review Checklist", diff --git a/checklists/waf_checklist.zh-Hant.json b/checklists/waf_checklist.zh-Hant.json index d0abd21b..6312a16d 100644 --- a/checklists/waf_checklist.zh-Hant.json +++ b/checklists/waf_checklist.zh-Hant.json @@ -4404,6 +4404,108 @@ "text": "Azure 機器人服務在全域和區域服務的主動-主動模式下運行。發生中斷時,無需檢測錯誤或管理服務。Azure 機器人服務在多區域地理體系結構中自動執行自動故障轉移和自動恢復。對於歐盟機器人區域服務,Azure 機器人服務在歐洲境內提供兩個完整區域,並提供主動/主動複製,以確保冗餘。對於全球機器人服務,所有可用的區域/地理位置都可以作為全球足跡。", "waf": "可靠性" }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "65285269-440c-44be-9d3e-0844276d4bdc", + "link": "https://github.com/Azure/fta-resiliencyplaybooks/blob/main/pass-foudations-playbooks-ADB_v1.docx", + "service": "Azure Data Factory", + "severity": "高", + "text": "參考 Databricks HA/DR playbook", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a0e6c465-89d5-458b-a37d-3974d1112dbd", + "link": "https://github.com/databrickslabs/databricks-sync", + "service": "Azure Data Factory", + "severity": "低", + "text": "使用 Databricks Sync", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "89d558b9-37d3-4974-b111-2dbd7aaf12e6", + "link": "https://learn.microsoft.com/azure/databricks/security/secrets/secret-scopes", + "service": "Azure Data Factory", + "severity": "中等", + "text": "備份工作區配置,包括ARM範本和機密範圍", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "b94ee5ef-47d2-4d92-a81b-1cd6d1f54b29", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/sharing-metadata-across-different-databricks-workspaces-using/ba-p/3679757", + "service": "Azure Data Factory", + "severity": "中等", + "text": "使用Hive外部元存儲在不同的 Databricks 工作區之間共用元數據", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "769e3969-0e78-428a-a936-657d03b0f466", + "link": "https://techcommunity.microsoft.com/t5/fasttrack-for-azure/disaster-recovery-strategy-in-azure-databricks-using-the-hive/ba-p/3684581", + "service": "Azure Data Factory", + "severity": "中等", + "text": "使用Hive外部元存儲在 Databricks 中規劃災難恢復策略", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "4b1d944a-3598-437e-b79d-6c6d3a364a5b", + "link": "https://www.databricks.com/blog/2021/04/20/attack-of-the-delta-clones-against-disaster-recovery-availability-complexity.html", + "service": "Azure Data Factory", + "severity": "中等", + "text": "使用深層和淺層克隆備份數據", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "使用RAGRS儲存帳戶中的輔助終結點下載 blob", + "guid": "7abae48a-bd54-4cd7-ae2e-86768357c559", + "link": "https://techcommunity.microsoft.com/t5/azure-paas-blog/download-the-blob-using-secondary-endpoint-in-ragrs-storage/ba-p/2403750", + "service": "Azure Data Factory", + "severity": "中等", + "text": "將數據備份到 Azure 儲存 RA-GRS", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "675c5ee8-5b85-49c7-944c-e3b1a28b875a", + "link": "https://learn.microsoft.com/azure/databricks/dev-tools/index-ci-cd", + "service": "Azure Data Factory", + "severity": "高", + "text": "使用DevOps備份代碼", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "guid": "a1bf1038-9f03-4a4d-8ce4-63dbbbc8682a", + "link": "https://learn.microsoft.com/azure/databricks/administration-guide/disaster-recovery", + "service": "Azure Data Factory", + "severity": "高", + "text": "使用主動/主動或主動/被動配置規劃災難恢復", + "waf": "可靠性" + }, + { + "arm-service": "Microsoft.DataFactory/datafactories", + "checklist": "DataBricks Review Checklist", + "description": "遷移包,用於記錄所有 Databricks 資源,以便備份和/或遷移到另一個 Databricks 工作區", + "guid": "5abc92a4-eda1-4dae-8cc8-5c47c6b781cc", + "link": "https://github.com/databrickslabs/migrate", + "service": "Azure Data Factory", + "severity": "中等", + "text": "使用 Databricks 遷移工具", + "waf": "可靠性" + }, { "arm-service": "Microsoft.Web/sites", "checklist": "Logic Apps checklist", diff --git a/spreadsheet/macrofree/checklist.en.master.xlsx b/spreadsheet/macrofree/checklist.en.master.xlsx index d5c09cd6..aa01a702 100644 Binary files a/spreadsheet/macrofree/checklist.en.master.xlsx and b/spreadsheet/macrofree/checklist.en.master.xlsx differ diff --git a/spreadsheet/macrofree/databricks_checklist.en.xlsx b/spreadsheet/macrofree/databricks_checklist.en.xlsx new file mode 100644 index 00000000..1f24bd7a Binary files /dev/null and b/spreadsheet/macrofree/databricks_checklist.en.xlsx differ diff --git a/spreadsheet/macrofree/databricks_checklist.es.xlsx b/spreadsheet/macrofree/databricks_checklist.es.xlsx new file mode 100644 index 00000000..3730b75a Binary files /dev/null and b/spreadsheet/macrofree/databricks_checklist.es.xlsx differ diff --git a/spreadsheet/macrofree/databricks_checklist.ja.xlsx b/spreadsheet/macrofree/databricks_checklist.ja.xlsx new file mode 100644 index 00000000..23ae4c28 Binary files /dev/null and b/spreadsheet/macrofree/databricks_checklist.ja.xlsx differ diff --git a/spreadsheet/macrofree/databricks_checklist.ko.xlsx b/spreadsheet/macrofree/databricks_checklist.ko.xlsx new file mode 100644 index 00000000..c4b79a5f Binary files /dev/null and b/spreadsheet/macrofree/databricks_checklist.ko.xlsx differ diff --git a/spreadsheet/macrofree/databricks_checklist.pt.xlsx b/spreadsheet/macrofree/databricks_checklist.pt.xlsx new file mode 100644 index 00000000..65e48b8d Binary files /dev/null and b/spreadsheet/macrofree/databricks_checklist.pt.xlsx differ diff --git a/spreadsheet/macrofree/databricks_checklist.zh-Hant.xlsx b/spreadsheet/macrofree/databricks_checklist.zh-Hant.xlsx new file mode 100644 index 00000000..bdb856a2 Binary files /dev/null and b/spreadsheet/macrofree/databricks_checklist.zh-Hant.xlsx differ diff --git a/spreadsheet/macrofree/waf_checklist.en.xlsx b/spreadsheet/macrofree/waf_checklist.en.xlsx index 460a744f..5eb0345f 100644 Binary files a/spreadsheet/macrofree/waf_checklist.en.xlsx and b/spreadsheet/macrofree/waf_checklist.en.xlsx differ diff --git a/spreadsheet/macrofree/waf_checklist.es.xlsx b/spreadsheet/macrofree/waf_checklist.es.xlsx index da2c81d2..92440040 100644 Binary files a/spreadsheet/macrofree/waf_checklist.es.xlsx and b/spreadsheet/macrofree/waf_checklist.es.xlsx differ diff --git a/spreadsheet/macrofree/waf_checklist.ja.xlsx b/spreadsheet/macrofree/waf_checklist.ja.xlsx index 44703312..538306c9 100644 Binary files a/spreadsheet/macrofree/waf_checklist.ja.xlsx and b/spreadsheet/macrofree/waf_checklist.ja.xlsx differ diff --git a/spreadsheet/macrofree/waf_checklist.ko.xlsx b/spreadsheet/macrofree/waf_checklist.ko.xlsx index 4007a99c..261c714b 100644 Binary files a/spreadsheet/macrofree/waf_checklist.ko.xlsx and b/spreadsheet/macrofree/waf_checklist.ko.xlsx differ diff --git a/spreadsheet/macrofree/waf_checklist.pt.xlsx b/spreadsheet/macrofree/waf_checklist.pt.xlsx index 390829a7..b7b49957 100644 Binary files a/spreadsheet/macrofree/waf_checklist.pt.xlsx and b/spreadsheet/macrofree/waf_checklist.pt.xlsx differ diff --git a/spreadsheet/macrofree/waf_checklist.zh-Hant.xlsx b/spreadsheet/macrofree/waf_checklist.zh-Hant.xlsx index 6eee1f28..291ef9f0 100644 Binary files a/spreadsheet/macrofree/waf_checklist.zh-Hant.xlsx and b/spreadsheet/macrofree/waf_checklist.zh-Hant.xlsx differ diff --git a/workbooks/alz_checklist.en_network_counters.json b/workbooks/alz_checklist.en_network_counters.json index 6d2080e5..a2d9a280 100644 --- a/workbooks/alz_checklist.en_network_counters.json +++ b/workbooks/alz_checklist.en_network_counters.json @@ -1085,7 +1085,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query26Stats:$.Success}" + "resultVal": "{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}" } } ] @@ -1104,7 +1104,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query26Stats:$.Total}" + "resultVal": "{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}" } } ] @@ -1142,7 +1142,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}" + "resultVal": "{Query9Stats:$.Success}" } } ] @@ -1161,7 +1161,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}" + "resultVal": "{Query9Stats:$.Total}" } } ] @@ -1199,7 +1199,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}" + "resultVal": "{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}" } } ] @@ -1218,7 +1218,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}" + "resultVal": "{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}" } } ] @@ -1256,7 +1256,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query9Stats:$.Success}" + "resultVal": "{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}" } } ] @@ -1275,7 +1275,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query9Stats:$.Total}" + "resultVal": "{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}" } } ] @@ -1370,7 +1370,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}" + "resultVal": "{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}" } } ] @@ -1389,7 +1389,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}" + "resultVal": "{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}" } } ] @@ -1427,7 +1427,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}" + "resultVal": "{Query26Stats:$.Success}" } } ] @@ -1446,7 +1446,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}" + "resultVal": "{Query26Stats:$.Total}" } } ] @@ -1541,7 +1541,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query26Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}+{Query9Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}" + "resultVal": "{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}+{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}+{Query26Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}" } } ] @@ -1560,7 +1560,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query26Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}+{Query9Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}" + "resultVal": "{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}+{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}+{Query26Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}" } } ] @@ -1634,43 +1634,43 @@ "style": "tabs", "links": [ { - "id": "14d2ae59-3c95-484c-90c1-265cdc04e147", + "id": "2c0e44ad-1cba-4338-bdd1-5bff5f71a8cd", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS ({Tab0Success:value}/{Tab0Total:value})", + "linkLabel": "Virtual WAN ({Tab0Success:value}/{Tab0Total:value})", "subTarget": "tab0", - "preText": "PaaS", + "preText": "Virtual WAN", "style": "primary" }, { - "id": "a0c636d7-9e89-4051-9c87-668f37323219", + "id": "e4b5938a-4c84-436b-9a95-db3e502666b9", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Firewall ({Tab1Success:value}/{Tab1Total:value})", + "linkLabel": "Internet ({Tab1Success:value}/{Tab1Total:value})", "subTarget": "tab1", - "preText": "Firewall", + "preText": "Internet", "style": "primary" }, { - "id": "e0aedecb-88cb-4843-89c8-05555564d4a5", + "id": "487ed80f-4ded-4dcb-b0e2-0227549a6375", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN ({Tab2Success:value}/{Tab2Total:value})", + "linkLabel": "Hybrid ({Tab2Success:value}/{Tab2Total:value})", "subTarget": "tab2", - "preText": "Virtual WAN", + "preText": "Hybrid", "style": "primary" }, { - "id": "718547ab-9547-473f-99e5-7006e1801e2e", + "id": "4a151264-3650-4c93-bc8b-ab3a7fe7aa62", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Internet ({Tab3Success:value}/{Tab3Total:value})", + "linkLabel": "Firewall ({Tab3Success:value}/{Tab3Total:value})", "subTarget": "tab3", - "preText": "Internet", + "preText": "Firewall", "style": "primary" }, { - "id": "dcbf97ee-db34-4d75-88d2-0fa493646a70", + "id": "d850cdff-f789-4ec2-91db-26cf7f6c6e62", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "IP plan ({Tab4Success:value}/{Tab4Total:value})", @@ -1679,25 +1679,25 @@ "style": "primary" }, { - "id": "0bc9b16b-c1c4-4845-ba62-32ec7b988ccc", + "id": "44651f66-0386-4e11-ab22-0853e151d297", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hybrid ({Tab5Success:value}/{Tab5Total:value})", + "linkLabel": "Segmentation ({Tab5Success:value}/{Tab5Total:value})", "subTarget": "tab5", - "preText": "Hybrid", + "preText": "Segmentation", "style": "primary" }, { - "id": "3f972b4e-3984-4c8e-8913-6b7c8767e53d", + "id": "e8401296-627b-410a-981d-3692ea262349", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Segmentation ({Tab6Success:value}/{Tab6Total:value})", + "linkLabel": "PaaS ({Tab6Success:value}/{Tab6Total:value})", "subTarget": "tab6", - "preText": "Segmentation", + "preText": "PaaS", "style": "primary" }, { - "id": "e22702e8-99df-41c6-bf68-98c527fc8d9e", + "id": "e8fe57da-94d7-414e-9595-d5f1181d3a8e", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Hub and spoke ({Tab7Success:value}/{Tab7Total:value})", @@ -1718,22 +1718,22 @@ { "type": 1, "content": { - "json": "## PaaS" + "json": "## Virtual WAN" }, "name": "tab0title" }, { "type": 1, "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." + "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext26" + "name": "querytext32" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1782,42 +1782,20 @@ ] } }, - "name": "query26" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab0" - }, - "name": "tab0" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Firewall" - }, - "name": "tab1title" + "name": "query32" }, { "type": 1, "content": { - "json": "Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." }, - "name": "querytext17" + "name": "querytext33" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1866,20 +1844,20 @@ ] } }, - "name": "query17" + "name": "query33" }, { "type": 1, "content": { - "json": "Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." + "json": "Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." }, - "name": "querytext18" + "name": "querytext34" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1928,20 +1906,20 @@ ] } }, - "name": "query18" + "name": "query34" }, { "type": 1, "content": { - "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information." + "json": "Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." }, - "name": "querytext19" + "name": "querytext35" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1990,20 +1968,42 @@ ] } }, - "name": "query19" + "name": "query35" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Internet" + }, + "name": "tab1title" }, { "type": 1, "content": { - "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." + "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this." }, - "name": "querytext20" + "name": "querytext9" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2052,20 +2052,42 @@ ] } }, - "name": "query20" + "name": "query9" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab1" + }, + "name": "tab1" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hybrid" + }, + "name": "tab2title" }, { "type": 1, "content": { - "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." + "json": "Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext21" + "name": "querytext10" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2114,20 +2136,20 @@ ] } }, - "name": "query21" + "name": "query10" }, { "type": 1, "content": { - "json": "Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this." + "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext23" + "name": "querytext11" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2176,20 +2198,20 @@ ] } }, - "name": "query23" + "name": "query11" }, { "type": 1, "content": { - "json": "Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this." + "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext24" + "name": "querytext12" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2238,20 +2260,20 @@ ] } }, - "name": "query24" + "name": "query12" }, { "type": 1, "content": { - "json": "Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information." + "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext25" + "name": "querytext13" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2300,42 +2322,20 @@ ] } }, - "name": "query25" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab1" - }, - "name": "tab1" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Virtual WAN" - }, - "name": "tab2title" + "name": "query13" }, { "type": 1, "content": { - "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." }, - "name": "querytext32" + "name": "querytext14" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2384,20 +2384,20 @@ ] } }, - "name": "query32" + "name": "query14" }, { "type": 1, "content": { - "json": "Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext33" + "name": "querytext15" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2446,20 +2446,20 @@ ] } }, - "name": "query33" + "name": "query15" }, { "type": 1, "content": { - "json": "Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information." }, - "name": "querytext34" + "name": "querytext16" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2508,20 +2508,42 @@ ] } }, - "name": "query34" + "name": "query16" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab2" + }, + "name": "tab2" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Firewall" + }, + "name": "tab3title" }, { "type": 1, "content": { - "json": "Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext35" + "name": "querytext17" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2570,42 +2592,20 @@ ] } }, - "name": "query35" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab2" - }, - "name": "tab2" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Internet" - }, - "name": "tab3title" + "name": "query17" }, { "type": 1, "content": { - "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this." + "json": "Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." }, - "name": "querytext9" + "name": "querytext18" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2654,42 +2654,20 @@ ] } }, - "name": "query9" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab3" - }, - "name": "tab3" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## IP plan" - }, - "name": "tab4title" + "name": "query18" }, { "type": 1, "content": { - "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information." }, - "name": "querytext6" + "name": "querytext19" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2738,20 +2716,20 @@ ] } }, - "name": "query6" + "name": "query19" }, { "type": 1, "content": { - "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." }, - "name": "querytext7" + "name": "querytext20" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2800,20 +2778,20 @@ ] } }, - "name": "query7" + "name": "query20" }, { "type": 1, "content": { - "json": "Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this." + "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." }, - "name": "querytext8" + "name": "querytext21" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2862,42 +2840,20 @@ ] } }, - "name": "query8" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab4" - }, - "name": "tab4" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Hybrid" - }, - "name": "tab5title" + "name": "query21" }, { "type": 1, "content": { - "json": "Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this." }, - "name": "querytext10" + "name": "querytext23" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2946,20 +2902,20 @@ ] } }, - "name": "query10" + "name": "query23" }, { "type": 1, "content": { - "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this." }, - "name": "querytext11" + "name": "querytext24" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3008,20 +2964,20 @@ ] } }, - "name": "query11" + "name": "query24" }, { "type": 1, "content": { - "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information." }, - "name": "querytext12" + "name": "querytext25" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3070,20 +3026,42 @@ ] } }, - "name": "query12" + "name": "query25" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab3" + }, + "name": "tab3" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## IP plan" + }, + "name": "tab4title" }, { "type": 1, "content": { - "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext13" + "name": "querytext6" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3132,20 +3110,20 @@ ] } }, - "name": "query13" + "name": "query6" }, { "type": 1, "content": { - "json": "Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." + "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext14" + "name": "querytext7" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3194,20 +3172,20 @@ ] } }, - "name": "query14" + "name": "query7" }, { "type": 1, "content": { - "json": "Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this." }, - "name": "querytext15" + "name": "querytext8" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3256,20 +3234,42 @@ ] } }, - "name": "query15" + "name": "query8" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab4" + }, + "name": "tab4" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Segmentation" + }, + "name": "tab5title" }, { "type": 1, "content": { - "json": "If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information." + "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." }, - "name": "querytext16" + "name": "querytext22" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3318,42 +3318,20 @@ ] } }, - "name": "query16" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab5" - }, - "name": "tab5" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Segmentation" - }, - "name": "tab6title" + "name": "query22" }, { "type": 1, "content": { - "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." + "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." }, - "name": "querytext22" + "name": "querytext27" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3402,20 +3380,20 @@ ] } }, - "name": "query22" + "name": "query27" }, { "type": 1, "content": { - "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." + "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." }, - "name": "querytext27" + "name": "querytext28" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3464,20 +3442,20 @@ ] } }, - "name": "query27" + "name": "query28" }, { "type": 1, "content": { - "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." + "json": "Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." }, - "name": "querytext28" + "name": "querytext29" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3526,20 +3504,20 @@ ] } }, - "name": "query28" + "name": "query29" }, { "type": 1, "content": { - "json": "Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." + "json": "Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this." }, - "name": "querytext29" + "name": "querytext30" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3588,20 +3566,20 @@ ] } }, - "name": "query29" + "name": "query30" }, { "type": 1, "content": { - "json": "Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this." + "json": "Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this." }, - "name": "querytext30" + "name": "querytext31" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3650,20 +3628,42 @@ ] } }, - "name": "query30" + "name": "query31" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab5" + }, + "name": "tab5" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## PaaS" + }, + "name": "tab6title" }, { "type": 1, "content": { - "json": "Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this." + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." }, - "name": "querytext31" + "name": "querytext26" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3712,7 +3712,7 @@ ] } }, - "name": "query31" + "name": "query26" } ] }, diff --git a/workbooks/alz_checklist.en_network_counters_template.json b/workbooks/alz_checklist.en_network_counters_template.json index 3d514da6..82ad9a50 100644 --- a/workbooks/alz_checklist.en_network_counters_template.json +++ b/workbooks/alz_checklist.en_network_counters_template.json @@ -41,7 +41,7 @@ "dependsOn": [], "properties": { "displayName": "[parameters('workbookDisplayName')]", - "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"value::all\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses))| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query9Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query10Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query11Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query12Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query13Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query14Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query15Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation))| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query16Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query17Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query18Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query19Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query20Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query21Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query22Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query23Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false'| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query24Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled'| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query25Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query26Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query27Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query28Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query28FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query28Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query29Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query29FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query29Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query30Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query30FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query30Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query31Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query31FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query31Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query32Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query32FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query32Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query33Stats\",\n \"type\": 1,\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query33FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query33Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query34Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query34FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query34Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query35Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query35FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query35Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab2Success}/{Tab2Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab3Success}/{Tab3Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab4Success}/{Tab4Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab5Success}/{Tab5Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab6Success}/{Tab6Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab7Success}/{Tab7Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookTotal\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}+{Query9Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookSuccess\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}+{Query9Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookPercent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{WorkbookSuccess}/{WorkbookTotal})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"InvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"50\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"WorkbookPercent\\\\\\\": \\\\\\\"{WorkbookPercent}\\\\\\\", \\\\\\\"SubTitle\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 4,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"WorkbookPercent\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"SubTitle\",\n \"formatter\": 1\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"ProgressTile\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"14d2ae59-3c95-484c-90c1-265cdc04e147\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS ({Tab0Success:value}/{Tab0Total:value})\",\n \"subTarget\": \"tab0\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"a0c636d7-9e89-4051-9c87-668f37323219\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Firewall ({Tab1Success:value}/{Tab1Total:value})\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Firewall\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"e0aedecb-88cb-4843-89c8-05555564d4a5\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN ({Tab2Success:value}/{Tab2Total:value})\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"718547ab-9547-473f-99e5-7006e1801e2e\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet ({Tab3Success:value}/{Tab3Total:value})\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"dcbf97ee-db34-4d75-88d2-0fa493646a70\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan ({Tab4Success:value}/{Tab4Total:value})\",\n \"subTarget\": \"tab4\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"0bc9b16b-c1c4-4845-ba62-32ec7b988ccc\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid ({Tab5Success:value}/{Tab5Total:value})\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"3f972b4e-3984-4c8e-8913-6b7c8767e53d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation ({Tab6Success:value}/{Tab6Total:value})\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"e22702e8-99df-41c6-bf68-98c527fc8d9e\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke ({Tab7Success:value}/{Tab7Total:value})\",\n \"subTarget\": \"tab7\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Firewall\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext32\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query32\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext33\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query33\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext34\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query34\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext35\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query35\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab3title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"name\": \"tab4title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"name\": \"tab5title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext28\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query28\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext29\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query29\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext30\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query30\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this.\"\n },\n \"name\": \"querytext31\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query31\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"name\": \"tab7title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-route-server/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Limit the number of routes per route table to 400. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", + "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"value::all\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses))| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query9Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query10Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query11Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query12Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query13Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query14Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query15Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation))| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query16Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query17Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query18Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query19Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query20Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query21Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query22Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query23Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false'| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query24Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled'| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query25Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query26Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query27Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query28Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query28FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query28Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query29Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query29FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query29Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query30Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query30FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query30Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query31Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query31FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query31Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query32Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query32FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query32Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query33Stats\",\n \"type\": 1,\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query33FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query33Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query34Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query34FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query34Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query35Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query35FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query35Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab2Success}/{Tab2Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab3Success}/{Tab3Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab4Success}/{Tab4Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab5Success}/{Tab5Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab6Success}/{Tab6Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab7Success}/{Tab7Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookTotal\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}+{Query9Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}+{Query26Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookSuccess\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}+{Query9Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}+{Query26Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookPercent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{WorkbookSuccess}/{WorkbookTotal})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"InvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"50\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"WorkbookPercent\\\\\\\": \\\\\\\"{WorkbookPercent}\\\\\\\", \\\\\\\"SubTitle\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 4,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"WorkbookPercent\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"SubTitle\",\n \"formatter\": 1\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"ProgressTile\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"2c0e44ad-1cba-4338-bdd1-5bff5f71a8cd\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN ({Tab0Success:value}/{Tab0Total:value})\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"e4b5938a-4c84-436b-9a95-db3e502666b9\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet ({Tab1Success:value}/{Tab1Total:value})\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"487ed80f-4ded-4dcb-b0e2-0227549a6375\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid ({Tab2Success:value}/{Tab2Total:value})\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"4a151264-3650-4c93-bc8b-ab3a7fe7aa62\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Firewall ({Tab3Success:value}/{Tab3Total:value})\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Firewall\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"d850cdff-f789-4ec2-91db-26cf7f6c6e62\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan ({Tab4Success:value}/{Tab4Total:value})\",\n \"subTarget\": \"tab4\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"44651f66-0386-4e11-ab22-0853e151d297\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation ({Tab5Success:value}/{Tab5Total:value})\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"e8401296-627b-410a-981d-3692ea262349\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS ({Tab6Success:value}/{Tab6Total:value})\",\n \"subTarget\": \"tab6\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"e8fe57da-94d7-414e-9595-d5f1181d3a8e\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke ({Tab7Success:value}/{Tab7Total:value})\",\n \"subTarget\": \"tab7\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext32\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query32\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext33\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query33\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext34\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query34\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext35\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query35\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Firewall\"\n },\n \"name\": \"tab3title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"name\": \"tab4title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"name\": \"tab5title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext28\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query28\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext29\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query29\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext30\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query30\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this.\"\n },\n \"name\": \"querytext31\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query31\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"name\": \"tab7title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-route-server/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Limit the number of routes per route table to 400. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", "version": "1.0", "sourceId": "[parameters('workbookSourceId')]", "category": "[parameters('workbookType')]" diff --git a/workbooks/alz_checklist.en_network_tabcounters.json b/workbooks/alz_checklist.en_network_tabcounters.json index 48b377e4..7d6cdda7 100644 --- a/workbooks/alz_checklist.en_network_tabcounters.json +++ b/workbooks/alz_checklist.en_network_tabcounters.json @@ -70,7 +70,7 @@ "style": "tabs", "links": [ { - "id": "fbc281ef-f267-4caa-9175-e0020134b644", + "id": "28e753d7-7a7c-4571-9461-727a7491e40c", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Segmentation", @@ -79,7 +79,7 @@ "style": "primary" }, { - "id": "e2257931-f963-455c-9f7a-ad6403c8d96f", + "id": "0d078392-5b10-400f-8cfe-5f102cfe432f", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Internet", @@ -88,7 +88,7 @@ "style": "primary" }, { - "id": "f7cb96d2-b731-4452-80d6-0f164b82fe4a", + "id": "a4ae31cf-9d91-4adf-b04f-7bf0c4fb6461", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Hybrid", @@ -97,7 +97,7 @@ "style": "primary" }, { - "id": "01360cd1-e5dd-45e5-a226-67c03dc0dccf", + "id": "44466922-4038-42c0-a640-3fa602c89f62", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Firewall", @@ -106,39 +106,39 @@ "style": "primary" }, { - "id": "3907955b-f4d7-41c3-aed7-fcfdbb74a516", + "id": "998e7504-5f1e-41d6-8f61-331ec12599f3", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS", + "linkLabel": "Virtual WAN", "subTarget": "tab4", - "preText": "PaaS", + "preText": "Virtual WAN", "style": "primary" }, { - "id": "8cc858d6-a2a3-4e87-bd9e-dbb987dc89ca", + "id": "4ab66f39-b8f1-4838-a5f1-1e8a8b700c9c", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "IP plan", + "linkLabel": "Hub and spoke", "subTarget": "tab5", - "preText": "IP plan", + "preText": "Hub and spoke", "style": "primary" }, { - "id": "ec217b09-fef2-4a35-a7ea-a53ca431357d", + "id": "445ec745-fcd6-4480-aa47-788f7558a7b5", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hub and spoke", + "linkLabel": "IP plan", "subTarget": "tab6", - "preText": "Hub and spoke", + "preText": "IP plan", "style": "primary" }, { - "id": "01e7565a-60c5-4ab0-bf8b-3c186d62ead1", + "id": "ee86cf1f-6a90-4dc3-8221-c81f11bf450b", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN", + "linkLabel": "PaaS", "subTarget": "tab7", - "preText": "Virtual WAN", + "preText": "PaaS", "style": "primary" } ] @@ -2654,9 +2654,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query26Stats", + "name": "Query32Stats", "type": 1, - "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2670,9 +2670,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query26FullyCompliant", + "name": "Query32FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query26Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query32Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2682,199 +2682,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab4Success", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "{Query26Stats:$.Success}" - } - } - ] - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Tab4Total", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "{Query26Stats:$.Total}" - } - } - ] - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Tab4Percent", - "type": 1, - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "round(100*{Tab4Success}/{Tab4Total})" - } - } - ] - } - ], - "style": "pills", - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - "name": "TabInvisibleParameters" - }, - { - "type": 1, - "content": { - "json": "## PaaS" - }, - "customWidth": "50", - "name": "tab4title" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab4Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", - "size": 3, - "queryType": 8, - "visualization": "tiles", - "tileSettings": { - "titleContent": { - "columnMatch": "Column1", - "formatter": 4, - "formatOptions": { - "min": 0, - "max": 100, - "palette": "redGreen" - }, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" - } - } - }, - "subtitleContent": { - "columnMatch": "Column2" - }, - "showBorder": true - } - }, - "customWidth": "50", - "name": "TabPercentTile" - }, - { - "type": 1, - "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." - }, - "name": "querytext26" - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", - "size": 4, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources", - "crossComponentResources": [ - "{Subscription}" - ], - "gridSettings": { - "formatters": [ - { - "columnMatch": "id", - "formatter": 0, - "numberFormat": { - "unit": 0, - "options": { - "style": "decimal" - } - } - }, - { - "columnMatch": "compliant", - "formatter": 18, - "formatOptions": { - "thresholdsOptions": "icons", - "thresholdsGrid": [ - { - "operator": "==", - "thresholdValue": "1", - "representation": "success", - "text": "Success" - }, - { - "operator": "==", - "thresholdValue": "0", - "representation": "failed", - "text": "Failed" - }, - { - "operator": "Default", - "thresholdValue": null, - "representation": "unknown", - "text": "Unknown" - } - ] - } - } - ] - } - }, - "name": "query26" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab4" - }, - "name": "tab4" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 9, - "content": { - "version": "KqlParameterItem/1.0", - "crossComponentResources": [ - "{Subscription}" - ], - "parameters": [ - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query6Stats", + "name": "Query33Stats", "type": 1, - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2888,9 +2698,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query6FullyCompliant", + "name": "Query33FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query6Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query33Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2900,9 +2710,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query7Stats", + "name": "Query34Stats", "type": 1, - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2916,9 +2726,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query7FullyCompliant", + "name": "Query34FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query7Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query34Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2928,9 +2738,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query8Stats", + "name": "Query35Stats", "type": 1, - "query": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -2944,9 +2754,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query8FullyCompliant", + "name": "Query35FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query8Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query35Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2956,7 +2766,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab5Success", + "name": "Tab4Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -2967,7 +2777,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}" + "resultVal": "{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}" } } ] @@ -2975,7 +2785,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab5Total", + "name": "Tab4Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -2986,7 +2796,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}" + "resultVal": "{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}" } } ] @@ -2994,7 +2804,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab5Percent", + "name": "Tab4Percent", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -3005,7 +2815,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab5Success}/{Tab5Total})" + "resultVal": "round(100*{Tab4Success}/{Tab4Total})" } } ] @@ -3020,16 +2830,16 @@ { "type": 1, "content": { - "json": "## IP plan" + "json": "## Virtual WAN" }, "customWidth": "50", - "name": "tab5title" + "name": "tab4title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab5Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab4Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", "size": 3, "queryType": 8, "visualization": "tiles", @@ -3061,15 +2871,15 @@ { "type": 1, "content": { - "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext6" + "name": "querytext32" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3118,20 +2928,20 @@ ] } }, - "name": "query6" + "name": "query32" }, { "type": 1, "content": { - "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." }, - "name": "querytext7" + "name": "querytext33" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3180,20 +2990,20 @@ ] } }, - "name": "query7" + "name": "query33" }, { "type": 1, "content": { - "json": "Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this." + "json": "Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." }, - "name": "querytext8" + "name": "querytext34" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -3242,16 +3052,78 @@ ] } }, - "name": "query8" + "name": "query34" + }, + { + "type": 1, + "content": { + "json": "Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + }, + "name": "querytext35" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "size": 4, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", + "crossComponentResources": [ + "{Subscription}" + ], + "gridSettings": { + "formatters": [ + { + "columnMatch": "id", + "formatter": 0, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } + }, + { + "columnMatch": "compliant", + "formatter": 18, + "formatOptions": { + "thresholdsOptions": "icons", + "thresholdsGrid": [ + { + "operator": "==", + "thresholdValue": "1", + "representation": "success", + "text": "Success" + }, + { + "operator": "==", + "thresholdValue": "0", + "representation": "failed", + "text": "Failed" + }, + { + "operator": "Default", + "thresholdValue": null, + "representation": "unknown", + "text": "Unknown" + } + ] + } + } + ] + } + }, + "name": "query35" } ] }, "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab5" + "value": "tab4" }, - "name": "tab5" + "name": "tab4" }, { "type": 12, @@ -3438,7 +3310,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab6Success", + "name": "Tab5Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -3457,7 +3329,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab6Total", + "name": "Tab5Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -3476,7 +3348,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab6Percent", + "name": "Tab5Percent", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -3487,7 +3359,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab6Success}/{Tab6Total})" + "resultVal": "round(100*{Tab5Success}/{Tab5Total})" } } ] @@ -3505,13 +3377,13 @@ "json": "## Hub and spoke" }, "customWidth": "50", - "name": "tab6title" + "name": "tab5title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab6Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab5Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", "size": 3, "queryType": 8, "visualization": "tiles", @@ -3917,9 +3789,9 @@ "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab6" + "value": "tab5" }, - "name": "tab6" + "name": "tab5" }, { "type": 12, @@ -3938,37 +3810,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query32Stats", - "type": 1, - "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query32FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query32Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query33Stats", + "name": "Query6Stats", "type": 1, - "query": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -3982,9 +3826,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query33FullyCompliant", + "name": "Query6FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query33Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query6Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -3994,9 +3838,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query34Stats", + "name": "Query7Stats", "type": 1, - "query": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -4010,9 +3854,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query34FullyCompliant", + "name": "Query7FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query34Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query7Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -4022,9 +3866,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query35Stats", + "name": "Query8Stats", "type": 1, - "query": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "query": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", "crossComponentResources": [ "{Subscription}" ], @@ -4038,9 +3882,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query35FullyCompliant", + "name": "Query8FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query35Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query8Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -4050,7 +3894,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab7Success", + "name": "Tab6Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -4061,7 +3905,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}" + "resultVal": "{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}" } } ] @@ -4069,7 +3913,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab7Total", + "name": "Tab6Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -4080,7 +3924,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}" + "resultVal": "{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}" } } ] @@ -4088,7 +3932,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab7Percent", + "name": "Tab6Percent", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -4099,7 +3943,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab7Success}/{Tab7Total})" + "resultVal": "round(100*{Tab6Success}/{Tab6Total})" } } ] @@ -4114,16 +3958,16 @@ { "type": 1, "content": { - "json": "## Virtual WAN" + "json": "## IP plan" }, "customWidth": "50", - "name": "tab7title" + "name": "tab6title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab7Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab6Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", "size": 3, "queryType": 8, "visualization": "tiles", @@ -4155,15 +3999,15 @@ { "type": 1, "content": { - "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext32" + "name": "querytext6" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -4212,20 +4056,20 @@ ] } }, - "name": "query32" + "name": "query6" }, { "type": 1, "content": { - "json": "Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext33" + "name": "querytext7" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -4274,20 +4118,20 @@ ] } }, - "name": "query33" + "name": "query7" }, { "type": 1, "content": { - "json": "Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this." }, - "name": "querytext34" + "name": "querytext8" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -4336,20 +4180,176 @@ ] } }, - "name": "query34" + "name": "query8" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab6" + }, + "name": "tab6" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "crossComponentResources": [ + "{Subscription}" + ], + "parameters": [ + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query26Stats", + "type": 1, + "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query26FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query26Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab7Success", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "{Query26Stats:$.Success}" + } + } + ] + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab7Total", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "{Query26Stats:$.Total}" + } + } + ] + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab7Percent", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "round(100*{Tab7Success}/{Tab7Total})" + } + } + ] + } + ], + "style": "pills", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + "name": "TabInvisibleParameters" }, { "type": 1, "content": { - "json": "Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "## PaaS" }, - "name": "querytext35" + "customWidth": "50", + "name": "tab7title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab7Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", + "size": 3, + "queryType": 8, + "visualization": "tiles", + "tileSettings": { + "titleContent": { + "columnMatch": "Column1", + "formatter": 4, + "formatOptions": { + "min": 0, + "max": 100, + "palette": "redGreen" + }, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } + }, + "subtitleContent": { + "columnMatch": "Column2" + }, + "showBorder": true + } + }, + "customWidth": "50", + "name": "TabPercentTile" + }, + { + "type": 1, + "content": { + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." + }, + "name": "querytext26" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -4398,7 +4398,7 @@ ] } }, - "name": "query35" + "name": "query26" } ] }, diff --git a/workbooks/alz_checklist.en_network_tabcounters_template.json b/workbooks/alz_checklist.en_network_tabcounters_template.json index d77c2933..7c08c8d3 100644 --- a/workbooks/alz_checklist.en_network_tabcounters_template.json +++ b/workbooks/alz_checklist.en_network_tabcounters_template.json @@ -41,7 +41,7 @@ "dependsOn": [], "properties": { "displayName": "[parameters('workbookDisplayName')]", - "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"fbc281ef-f267-4caa-9175-e0020134b644\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"e2257931-f963-455c-9f7a-ad6403c8d96f\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"f7cb96d2-b731-4452-80d6-0f164b82fe4a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"01360cd1-e5dd-45e5-a226-67c03dc0dccf\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Firewall\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Firewall\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"3907955b-f4d7-41c3-aed7-fcfdbb74a516\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab4\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"8cc858d6-a2a3-4e87-bd9e-dbb987dc89ca\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab5\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ec217b09-fef2-4a35-a7ea-a53ca431357d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"01e7565a-60c5-4ab0-bf8b-3c186d62ead1\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab7\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query22Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query27Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query28Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query28FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query28Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query29Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query29FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query29Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query30Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query30FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query30Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query31Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query31FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query31Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab0title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab0Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext28\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query28\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext29\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query29\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext30\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query30\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this.\"\n },\n \"name\": \"querytext31\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query31\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query9Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab1title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab1Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query10Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query11Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query12Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query13Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query14Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query15Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation))| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query16Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab2Success}/{Tab2Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab2title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab2Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query17Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query18Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query19Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query20Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query21Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query23Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false'| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query24Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled'| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query25Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab3Success}/{Tab3Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Firewall\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab3title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab3Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query26Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab4Success}/{Tab4Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab4title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab4Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab5Success}/{Tab5Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab5title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab5Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses))| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab6Success}/{Tab6Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab6title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab6Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-route-server/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Limit the number of routes per route table to 400. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query32Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query32FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query32Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query33Stats\",\n \"type\": 1,\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query33FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query33Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query34Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query34FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query34Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query35Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query35FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query35Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab7Success}/{Tab7Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab7title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab7Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext32\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query32\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext33\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query33\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext34\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query34\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext35\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query35\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", + "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"28e753d7-7a7c-4571-9461-727a7491e40c\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"0d078392-5b10-400f-8cfe-5f102cfe432f\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"a4ae31cf-9d91-4adf-b04f-7bf0c4fb6461\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"44466922-4038-42c0-a640-3fa602c89f62\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Firewall\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Firewall\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"998e7504-5f1e-41d6-8f61-331ec12599f3\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"4ab66f39-b8f1-4838-a5f1-1e8a8b700c9c\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"445ec745-fcd6-4480-aa47-788f7558a7b5\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab6\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ee86cf1f-6a90-4dc3-8221-c81f11bf450b\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab7\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query22FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query22Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query27FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query27Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query28Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query28FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query28Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query29Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query29FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query29Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query30Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query30FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query30Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query31Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query31FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query31Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Success}+{Query27Stats:$.Success}+{Query28Stats:$.Success}+{Query29Stats:$.Success}+{Query30Stats:$.Success}+{Query31Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query22Stats:$.Total}+{Query27Stats:$.Total}+{Query28Stats:$.Total}+{Query29Stats:$.Total}+{Query30Stats:$.Total}+{Query31Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab0title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab0Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext28\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query28\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext29\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query29\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext30\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query30\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this.\"\n },\n \"name\": \"querytext31\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query31\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query9FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query9Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query9Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab1title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab1Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query10FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query10Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query11FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query11Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query12FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query12Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13Stats\",\n \"type\": 1,\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query13FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query13Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query14FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query14Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query15FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query15Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation))| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query16FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query16Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab2Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab2Success}/{Tab2Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab2title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab2Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query17FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query17Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query18FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query18Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query19FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query19Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query20FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query20Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query21FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query21Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query23FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query23Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false'| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query24FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query24Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled'| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query25FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query25Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query17Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query23Stats:$.Success}+{Query24Stats:$.Success}+{Query25Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query17Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query23Stats:$.Total}+{Query24Stats:$.Total}+{Query25Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab3Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab3Success}/{Tab3Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Firewall\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab3title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab3Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query32Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query32FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query32Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query33Stats\",\n \"type\": 1,\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query33FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query33Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query34Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query34FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query34Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query35Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query35FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query35Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Success}+{Query33Stats:$.Success}+{Query34Stats:$.Success}+{Query35Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query32Stats:$.Total}+{Query33Stats:$.Total}+{Query34Stats:$.Total}+{Query35Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab4Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab4Success}/{Tab4Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab4title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab4Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext32\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query32\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext33\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query33\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext34\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query34\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext35\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query35\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses))| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab5Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab5Success}/{Tab5Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab5title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab5Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-route-server/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Limit the number of routes per route table to 400. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az)| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab6Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab6Success}/{Tab6Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab6title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab6Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query26FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query26Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query26Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab7Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab7Success}/{Tab7Total})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"TabInvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"customWidth\": \"50\",\n \"name\": \"tab7title\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"Column1\\\\\\\": \\\\\\\"{Tab7Percent}\\\\\\\", \\\\\\\"Column2\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 3,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"Column1\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n },\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"Column2\"\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"TabPercentTile\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", "version": "1.0", "sourceId": "[parameters('workbookSourceId')]", "category": "[parameters('workbookType')]" diff --git a/workbooks/alz_checklist.en_network_workbook.json b/workbooks/alz_checklist.en_network_workbook.json index 2bd51d73..912efe1f 100644 --- a/workbooks/alz_checklist.en_network_workbook.json +++ b/workbooks/alz_checklist.en_network_workbook.json @@ -70,52 +70,52 @@ "style": "tabs", "links": [ { - "id": "cb861f33-a7a7-41cf-9649-d7afabba7566", + "id": "e2ba09ba-9340-4b67-8d5e-c450fbbefb85", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hybrid", + "linkLabel": "IP plan", "subTarget": "tab0", - "preText": "Hybrid", + "preText": "IP plan", "style": "primary" }, { - "id": "8cb6fd2e-540e-4ff1-b903-66521253c65f", + "id": "96eaa1ff-69db-4816-ad3d-522d2d62ad4b", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS", + "linkLabel": "Virtual WAN", "subTarget": "tab1", - "preText": "PaaS", + "preText": "Virtual WAN", "style": "primary" }, { - "id": "1b0c84fc-c1d0-4471-9a1f-c7ccee85adf9", + "id": "b1df5234-6b66-48c6-ac3b-2392e96eae51", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "IP plan", + "linkLabel": "Segmentation", "subTarget": "tab2", - "preText": "IP plan", + "preText": "Segmentation", "style": "primary" }, { - "id": "30083dca-4639-4773-ba6a-d6f817b74a60", + "id": "1b12900e-60ba-435e-86bc-b2ae7d4c6895", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Firewall", + "linkLabel": "Hybrid", "subTarget": "tab3", - "preText": "Firewall", + "preText": "Hybrid", "style": "primary" }, { - "id": "f3a83fc0-a2f7-4e2f-bae8-8a3bb7d30ac6", + "id": "0ea6fe14-9eca-4df0-8f43-528cb43bf21a", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hub and spoke", + "linkLabel": "PaaS", "subTarget": "tab4", - "preText": "Hub and spoke", + "preText": "PaaS", "style": "primary" }, { - "id": "8b629670-7571-4f12-be6d-a0d9202b30e7", + "id": "ac6fe09c-e2c7-44fd-a78a-e8092215e691", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Internet", @@ -124,21 +124,21 @@ "style": "primary" }, { - "id": "ea0b7755-f79a-4e0a-a8a8-66603320cfc0", + "id": "5fc57124-054d-415b-b266-603d5994bae8", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Segmentation", + "linkLabel": "Hub and spoke", "subTarget": "tab6", - "preText": "Segmentation", + "preText": "Hub and spoke", "style": "primary" }, { - "id": "06180d64-902f-4879-90e9-52d18661da52", + "id": "6bed81f0-d5e6-42e0-8094-027a7b55ea30", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN", + "linkLabel": "Firewall", "subTarget": "tab7", - "preText": "Virtual WAN", + "preText": "Firewall", "style": "primary" } ] @@ -154,22 +154,22 @@ { "type": 1, "content": { - "json": "## Hybrid" + "json": "## IP plan" }, "name": "tab0title" }, { "type": 1, "content": { - "json": "Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext10" + "name": "querytext6" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -218,20 +218,20 @@ ] } }, - "name": "query10" + "name": "query6" }, { "type": 1, "content": { - "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." }, - "name": "querytext11" + "name": "querytext7" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -280,20 +280,20 @@ ] } }, - "name": "query11" + "name": "query7" }, { "type": 1, "content": { - "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this." }, - "name": "querytext12" + "name": "querytext8" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -342,20 +342,42 @@ ] } }, - "name": "query12" + "name": "query8" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Virtual WAN" + }, + "name": "tab1title" }, { "type": 1, "content": { - "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext13" + "name": "querytext32" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -404,20 +426,20 @@ ] } }, - "name": "query13" + "name": "query32" }, { "type": 1, "content": { - "json": "Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." + "json": "Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." }, - "name": "querytext14" + "name": "querytext33" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -466,20 +488,20 @@ ] } }, - "name": "query14" + "name": "query33" }, { "type": 1, "content": { - "json": "Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." }, - "name": "querytext15" + "name": "querytext34" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -528,20 +550,20 @@ ] } }, - "name": "query15" + "name": "query34" }, { "type": 1, "content": { - "json": "If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information." + "json": "Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." }, - "name": "querytext16" + "name": "querytext35" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -590,16 +612,16 @@ ] } }, - "name": "query16" + "name": "query35" } ] }, "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab0" + "value": "tab1" }, - "name": "tab0" + "name": "tab1" }, { "type": 12, @@ -610,22 +632,22 @@ { "type": 1, "content": { - "json": "## PaaS" + "json": "## Segmentation" }, - "name": "tab1title" + "name": "tab2title" }, { "type": 1, "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." + "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." }, - "name": "querytext26" + "name": "querytext22" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -674,42 +696,20 @@ ] } }, - "name": "query26" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab1" - }, - "name": "tab1" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## IP plan" - }, - "name": "tab2title" + "name": "query22" }, { "type": 1, "content": { - "json": "Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." }, - "name": "querytext6" + "name": "querytext27" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -758,20 +758,20 @@ ] } }, - "name": "query6" + "name": "query27" }, { "type": 1, "content": { - "json": "Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this." + "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." }, - "name": "querytext7" + "name": "querytext28" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -820,20 +820,20 @@ ] } }, - "name": "query7" + "name": "query28" }, { "type": 1, "content": { - "json": "Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this." + "json": "Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." }, - "name": "querytext8" + "name": "querytext29" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -882,42 +882,20 @@ ] } }, - "name": "query8" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab2" - }, - "name": "tab2" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Firewall" - }, - "name": "tab3title" + "name": "query29" }, { "type": 1, "content": { - "json": "Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this." }, - "name": "querytext17" + "name": "querytext30" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -966,20 +944,20 @@ ] } }, - "name": "query17" + "name": "query30" }, { "type": 1, "content": { - "json": "Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." + "json": "Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this." }, - "name": "querytext18" + "name": "querytext31" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1028,20 +1006,42 @@ ] } }, - "name": "query18" + "name": "query31" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab2" + }, + "name": "tab2" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hybrid" + }, + "name": "tab3title" }, { "type": 1, "content": { - "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information." + "json": "Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext19" + "name": "querytext10" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1090,20 +1090,20 @@ ] } }, - "name": "query19" + "name": "query10" }, { "type": 1, "content": { - "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." + "json": "Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext20" + "name": "querytext11" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1152,20 +1152,20 @@ ] } }, - "name": "query20" + "name": "query11" }, { "type": 1, "content": { - "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." + "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext21" + "name": "querytext12" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1214,20 +1214,20 @@ ] } }, - "name": "query21" + "name": "query12" }, { "type": 1, "content": { - "json": "Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this." + "json": "Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext23" + "name": "querytext13" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1276,20 +1276,20 @@ ] } }, - "name": "query23" + "name": "query13" }, { "type": 1, "content": { - "json": "Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this." + "json": "Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this." }, - "name": "querytext24" + "name": "querytext14" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1338,20 +1338,20 @@ ] } }, - "name": "query24" + "name": "query14" }, { "type": 1, "content": { - "json": "Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information." + "json": "Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext25" + "name": "querytext15" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1400,42 +1400,20 @@ ] } }, - "name": "query25" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab3" - }, - "name": "tab3" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Hub and spoke" - }, - "name": "tab4title" + "name": "query15" }, { "type": 1, "content": { - "json": "If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-route-server/) can help to educate yourself on this." + "json": "If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information." }, - "name": "querytext0" + "name": "querytext16" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1484,20 +1462,42 @@ ] } }, - "name": "query0" + "name": "query16" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab3" + }, + "name": "tab3" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## PaaS" + }, + "name": "tab4title" }, { "type": 1, "content": { - "json": "If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this." + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." }, - "name": "querytext1" + "name": "querytext26" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1546,20 +1546,42 @@ ] } }, - "name": "query1" + "name": "query26" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab4" + }, + "name": "tab4" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Internet" + }, + "name": "tab5title" }, { "type": 1, "content": { - "json": "Limit the number of routes per route table to 400. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this." + "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this." }, - "name": "querytext2" + "name": "querytext9" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1608,20 +1630,42 @@ ] } }, - "name": "query2" + "name": "query9" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab5" + }, + "name": "tab5" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hub and spoke" + }, + "name": "tab6title" }, { "type": 1, "content": { - "json": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this." + "json": "If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-route-server/) can help to educate yourself on this." }, - "name": "querytext3" + "name": "querytext0" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1670,20 +1714,20 @@ ] } }, - "name": "query3" + "name": "query0" }, { "type": 1, "content": { - "json": "Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information." + "json": "If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this." }, - "name": "querytext4" + "name": "querytext1" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1732,20 +1776,20 @@ ] } }, - "name": "query4" + "name": "query1" }, { "type": 1, "content": { - "json": "Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information." + "json": "Limit the number of routes per route table to 400. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this." }, - "name": "querytext5" + "name": "querytext2" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1794,42 +1838,20 @@ ] } }, - "name": "query5" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab4" - }, - "name": "tab4" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Internet" - }, - "name": "tab5title" + "name": "query2" }, { "type": 1, "content": { - "json": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this." + "json": "Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this." }, - "name": "querytext9" + "name": "querytext3" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1878,42 +1900,20 @@ ] } }, - "name": "query9" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab5" - }, - "name": "tab5" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Segmentation" - }, - "name": "tab6title" + "name": "query3" }, { "type": 1, "content": { - "json": "Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." + "json": "Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information." }, - "name": "querytext22" + "name": "querytext4" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1962,20 +1962,20 @@ ] } }, - "name": "query22" + "name": "query4" }, { "type": 1, "content": { - "json": "Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information." + "json": "Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information." }, - "name": "querytext27" + "name": "querytext5" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2024,20 +2024,42 @@ ] } }, - "name": "query27" + "name": "query5" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab6" + }, + "name": "tab6" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Firewall" + }, + "name": "tab7title" }, { "type": 1, "content": { - "json": "Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information." + "json": "Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext28" + "name": "querytext17" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2086,20 +2108,20 @@ ] } }, - "name": "query28" + "name": "query17" }, { "type": 1, "content": { - "json": "Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." + "json": "Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." }, - "name": "querytext29" + "name": "querytext18" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2148,20 +2170,20 @@ ] } }, - "name": "query29" + "name": "query18" }, { "type": 1, "content": { - "json": "Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this." + "json": "Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information." }, - "name": "querytext30" + "name": "querytext19" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2210,20 +2232,20 @@ ] } }, - "name": "query30" + "name": "query19" }, { "type": 1, "content": { - "json": "Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this." + "json": "Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this." }, - "name": "querytext31" + "name": "querytext20" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2272,42 +2294,20 @@ ] } }, - "name": "query31" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab6" - }, - "name": "tab6" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Virtual WAN" - }, - "name": "tab7title" + "name": "query20" }, { "type": 1, "content": { - "json": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information." }, - "name": "querytext32" + "name": "querytext21" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2356,20 +2356,20 @@ ] } }, - "name": "query32" + "name": "query21" }, { "type": 1, "content": { - "json": "Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this." }, - "name": "querytext33" + "name": "querytext23" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2418,20 +2418,20 @@ ] } }, - "name": "query33" + "name": "query23" }, { "type": 1, "content": { - "json": "Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this." }, - "name": "querytext34" + "name": "querytext24" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2480,20 +2480,20 @@ ] } }, - "name": "query34" + "name": "query24" }, { "type": 1, "content": { - "json": "Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this." + "json": "Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information." }, - "name": "querytext35" + "name": "querytext25" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2542,7 +2542,7 @@ ] } }, - "name": "query35" + "name": "query25" } ] }, diff --git a/workbooks/alz_checklist.en_network_workbook_template.json b/workbooks/alz_checklist.en_network_workbook_template.json index 8a799b20..d6ec4a98 100644 --- a/workbooks/alz_checklist.en_network_workbook_template.json +++ b/workbooks/alz_checklist.en_network_workbook_template.json @@ -41,7 +41,7 @@ "dependsOn": [], "properties": { "displayName": "[parameters('workbookDisplayName')]", - "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"cb861f33-a7a7-41cf-9649-d7afabba7566\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"8cb6fd2e-540e-4ff1-b903-66521253c65f\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab1\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"1b0c84fc-c1d0-4471-9a1f-c7ccee85adf9\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab2\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"30083dca-4639-4773-ba6a-d6f817b74a60\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Firewall\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Firewall\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"f3a83fc0-a2f7-4e2f-bae8-8a3bb7d30ac6\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"8b629670-7571-4f12-be6d-a0d9202b30e7\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ea0b7755-f79a-4e0a-a8a8-66603320cfc0\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"06180d64-902f-4879-90e9-52d18661da52\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab7\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Firewall\"\n },\n \"name\": \"tab3title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"name\": \"tab4title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-route-server/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Limit the number of routes per route table to 400. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab5title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext28\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query28\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext29\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query29\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext30\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query30\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this.\"\n },\n \"name\": \"querytext31\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query31\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"name\": \"tab7title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext32\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query32\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext33\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query33\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext34\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query34\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext35\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query35\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", + "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Landing Zone Review - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"e2ba09ba-9340-4b67-8d5e-c450fbbefb85\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab0\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"96eaa1ff-69db-4816-ad3d-522d2d62ad4b\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"b1df5234-6b66-48c6-ac3b-2392e96eae51\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"1b12900e-60ba-435e-86bc-b2ae7d4c6895\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"0ea6fe14-9eca-4df0-8f43-528cb43bf21a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab4\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ac6fe09c-e2c7-44fd-a78a-e8092215e691\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"5fc57124-054d-415b-b266-603d5994bae8\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"6bed81f0-d5e6-42e0-8094-027a7b55ea30\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Firewall\",\n \"subTarget\": \"tab7\",\n \"preText\": \"Firewall\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## IP plan\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use IP addresses from the address allocation ranges for private internets (RFC 1918). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | project name, id, location, resourceGroup, subscriptionId, cidr = addressPrefix | extend compliant = (cidr matches regex @'^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)') | project id, compliant, cidr | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that IP address space isn't wasted, don't create unnecessarily large virtual networks (for example /16). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing) for further information.. [This training](https://learn.microsoft.com/learn/paths/architect-network-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | extend addressSpace = todynamic(properties.addressSpace) | extend addressPrefix = todynamic(properties.addressSpace.addressPrefixes) | mvexpand addressSpace | mvexpand addressPrefix | extend addressMask = split(addressPrefix,'/')[1] | extend compliant = addressMask > 16 | project name, id, subscriptionId, resourceGroup, addressPrefix, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard SKU and Zone-Redundant IPs when applicable, Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience. Check [this link](https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone) for further information.. [This training](https://learn.microsoft.com/en-gb/training/modules/configure-virtual-networks/6-create-public-ip-addressing) can help to educate yourself on this.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"Resources | where type =~ 'Microsoft.Network/publicIPAddresses' and sku.tier =~ 'Regional' | where isempty(zones) or array_length(zones) <= 1 | extend az = case(isempty(zones), 'Non-zonal', array_length(zones) <= 1, strcat('Zonal (', strcat_array(zones, ','), ')'), zones) | project name, id, tags, param1 = strcat('sku: ', sku.name), param2 = strcat('availabilityZone: ', az) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Virtual WAN\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/howto-firewall) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext32\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualhubs' | extend compliant = isnotnull(properties.azureFirewall.id) | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query32\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not disable branch-to-branch traffic in Virtual WAN, unless these flows should be explicitly blocked. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#is-branch-to-branch-connectivity-allowed-in-virtual-wan) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext33\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type =~ 'microsoft.network/virtualwans' | extend compliant= (properties.allowBranchToBranchTraffic == 'true') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query33\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use AS-Path as hub routing preference, since it is more flexible than ExpressRoute or VPN. Check [this link](https://learn.microsoft.com/azure/virtual-wan/about-virtual-hub-routing-preference) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext34\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs'| extend compliant= (properties.hubRoutingPreference =~ 'ASPath') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query34\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Assign at least a /23 prefix to virtual hubs to ensure enough IP space is available. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-faq#what-is-the-recommended-hub-address-space-during-hub-creation) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext35\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualhubs' | extend addressSpace = properties.addressPrefix | extend compliant= (toint(substring(addressSpace, indexof(addressSpace, '/') + 1)) < 23) | distinct name, id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query35\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Segmentation\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use a /26 prefix for your Azure Firewall subnets. Check [this link](https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext22\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureFirewallSubnet' | extend compliant = (subnetPrefixLength == 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query22\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use at least a /27 prefix for your Gateway subnets. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-howto-add-gateway-resource-manager#add-a-gateway) for further information.\"\n },\n \"name\": \"querytext27\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'GatewaySubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query27\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't rely on the NSG inbound default rules using the VirtualNetwork service tag to limit connectivity. Check [this link](https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags) for further information.\"\n },\n \"name\": \"querytext28\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/networksecuritygroups' | mvexpand properties.securityRules | project id,name,ruleAction=properties_securityRules.properties.access,rulePriority=properties_securityRules.properties.priority,ruleDst=properties_securityRules.properties.destinationAddressPrefix,ruleSrc=properties_securityRules.properties.sourceAddressPrefix,ruleProt=properties_securityRules.properties.protocol,ruleDirection=properties_securityRules.properties.direction,rulePort=properties_securityRules.properties.destinationPortRange | summarize StarDenies=countif(ruleAction=='Deny' and ruleDst=='*' and ruleSrc=='*' and ruleProt=='*' and rulePort=='*') by id,tostring(ruleDirection) | where ruleDirection == 'Inbound' | project id,compliant=(StarDenies>0) | union (resources | where type=='microsoft.network/networksecuritygroups' | where array_length(properties.securityRules)==0 | extend compliant=false | project id,compliant) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query28\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use NSGs to help protect traffic across subnets, as well as east/west traffic across the platform (traffic between landing zones). Check [this link](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-landing-zone-network-segmentation) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext29\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | where subnet.name !in~ ('GatewaySubnet', 'AzureFirewallSubnet', 'AzureFirewallManagementSubnet', 'RouteServerSubnet') | extend compliant = iff(isnotnull(subnet.properties.networkSecurityGroup.id), true, false) | project id, subnetName = subnet.name, vnetName = name, NSG = subnet.properties.networkSecurityGroup.id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query29\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable VNet Flow Logs and feed them into Traffic Analytics to gain insights into internal and external traffic flows. Check [this link](https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-network-monitoring/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext30\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/virtualnetworks' | project subscriptionId, lowerCaseVNetId = tolower(id) | join kind = leftouter ( resources | where type =~ 'microsoft.network/networkwatchers/flowlogs' and properties.enabled == true and properties.provisioningState =~ 'succeeded' | where properties.targetResourceId contains '/Microsoft.Network/virtualNetworks/' | project flowlogId = id, trafficAnalyticsEnabled = properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled, lowerCaseTargetVNetId = tolower(properties.targetResourceId) ) on $left.lowerCaseVNetId == $right.lowerCaseTargetVNetId | extend compliant = iff(isnotempty(lowerCaseTargetVNetId), true, false) | project id = lowerCaseVNetId, flowlogId, trafficAnalyticsEnabled, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query30\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Do not implement more than 900 NSG rules per NSG, due to the limit of 1000 rules. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits) for further information.. [This training](https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works) can help to educate yourself on this.\"\n },\n \"name\": \"querytext31\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/networksecuritygroups' | project id, rules = array_length(properties.securityRules) | project id, compliant = (rules < 900) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query31\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hybrid\"\n },\n \"name\": \"tab3title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Select the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways?source=recommendations#gwsku) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext10\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier !in ('Basic', 'Standard')| project name, id, subscriptionId, resourceGroup, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query10\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using unlimited-data ExpressRoute circuits only if you reach the bandwidth that justifies their cost. Check [this link](https://learn.microsoft.com/azure/expressroute/plan-manage-cost) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext11\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/expressroutecircuits' | extend compliant = (tolower(sku.family) == 'metereddata' or tolower(sku.tier) == 'local') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query11\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuit peering location supports your Azure regions for the Local SKU. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local) for further information.. [This training](https://learn.microsoft.com/training/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext12\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project id, gwid=tostring(properties.virtualNetworkGateway1.id), circuitid=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitid=tostring(id), circuitsku=sku.tier) on circuitid | project id=gwid, compliant = (circuitsku == 'Local') | summarize compliant=max(compliant) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy a zone-redundant ExpressRoute gateway in the supported Azure regions. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext13\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources| where type == 'microsoft.network/virtualnetworkgateways'| where properties.gatewayType =~ 'vpn' or properties.gatewayType == 'ExpressRoute'| extend SKUName = properties.sku.name, SKUTier = properties.sku.tier, Type = properties.gatewayType| extend compliant = SKUTier contains 'AZ'| project name, id, subscriptionId, resourceGroup, Type, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use zone-redundant VPN gateways to connect branches or remote locations to Azure (where available). Check [this link](https://learn.microsoft.com/azure/vpn-gateway/create-zone-redundant-vnet-gateway) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-vpn-gateway/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext14\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworkgateways' | where properties.gatewayType == 'Vpn' | extend compliant = (tolower(properties.sku.name) contains 'az') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query14\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use ExpressRoute circuits from different peering locations for redundancy. Check [this link](https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext15\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/connections' | where properties.connectionType == 'ExpressRoute' | project cxId=id, gwId=tostring(properties.virtualNetworkGateway1.id), circuitId=tostring(properties.peer.id) | join (resources | where type=='microsoft.network/expressroutecircuits' | project circuitId=tostring(id), circuitLocation=tostring(properties.serviceProviderProperties.peeringLocation)) on circuitId | distinct gwId, circuitLocation | summarize countErLocations=count() by id=gwId | extend compliant = (countErLocations >= 2) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query15\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you are using a route table in the GatewaySubnet, make sure that gateway routes are propagated. Check [this link](https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub) for further information.\"\n },\n \"name\": \"querytext16\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,resourceGroup,name,subnetName=tostring(subnets.name),routeTableId=tostring(subnets.properties.routeTable.id) | where subnetName == 'GatewaySubnet' | join kind=leftouter (Resources | where type == 'microsoft.network/routetables' | project routeTableName=name,routeTableId=id, disableBgpRoutePropagation=properties.disableBgpRoutePropagation) on routeTableId | project id,compliant = (disableBgpRoutePropagation == False or isnull(disableBgpRoutePropagation)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query16\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab3\"\n },\n \"name\": \"tab3\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## PaaS\"\n },\n \"name\": \"tab4title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this.\"\n },\n \"name\": \"querytext26\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets = properties.subnets | mv-expand subnets | project id = subnets.id, resourceGroup, VNet = name, serviceEndpoints = subnets.properties.serviceEndpoints, compliant = (isnull(subnets.properties.serviceEndpoints) or array_length(subnets.properties.serviceEndpoints) == 0) | order by compliant asc | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query26\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab4\"\n },\n \"name\": \"tab4\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab5title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-bastion/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'AzureBastionSubnet' | extend compliant = (subnetPrefixLength <= 26) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query9\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab5\"\n },\n \"name\": \"tab5\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Hub and spoke\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If using Route Server, use a /27 prefix for the Route Server subnet. Check [this link](https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1) for further information.. [This training](https://learn.microsoft.com/training/modules/intro-to-azure-route-server/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | project id, subnetName = subnets.name, subnetPrefix = subnets.properties.addressPrefix | extend subnetPrefixLength = split(subnetPrefix, '/')[1] | where subnetName == 'RouteServerSubnet' | extend compliant = (subnetPrefixLength <= 27) | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you have more than 400 spoke networks in a region, deploy an additional hub to bypass VNet peering limits (500) and the maximum number of prefixes that can be advertised via ExpressRoute (1000). Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | summarize peeringcount = count() by id | extend compliant = (peeringcount < 450) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Limit the number of routes per route table to 400. Check [this link](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=/azure/virtual-network/toc.json#azure-resource-manager-virtual-networking-limits) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/routetables' | mvexpand properties.routes | summarize routeCount = count() by id | extend compliant = (routeCount < 360) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use the setting 'Allow traffic to remote virtual network' when configuring VNet peerings. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-network-manage-peering) for further information.. [This training](https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | project id, peeringName=properties_virtualNetworkPeerings.name, compliant = (properties_virtualNetworkPeerings.properties.allowVirtualNetworkAccess == True) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Standard Load Balancer SKU with a zone-redundant deployment, Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id), PrivateIPZones = feIPconfigs.zones, PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PrivateSubnetId) | where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2 | project name, feConfigName, id | union (resources | where type == 'microsoft.network/loadbalancers' | where tolower(sku.name) != 'basic' | mv-expand feIPconfigs = properties.frontendIPConfigurations | extend feConfigName = (feIPconfigs.name), PIPid = toupper(feIPconfigs.properties.publicIPAddress.id), JoinID = toupper(id) | where isnotempty(PIPid) | join kind=innerunique ( resources | where type == 'microsoft.network/publicipaddresses' | where isnull(zones) or array_length(zones) < 2 | extend LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))), InnerID = toupper(id) ) on $left.PIPid == $right.InnerID) | project name, id, tags, param1='Zones: No Zone or Zonal', param2=strcat('Frontend IP Configuration:', ' ', feConfigName) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure load balancer backend pool(s) contains at least two instances, Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Check [this link](https://learn.microsoft.com/en-us/azure/reliability/reliability-load-balancer?tabs=graph#zone-redundant) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/loadBalancers' | extend bep = properties.backendAddressPools | extend BackEndPools = array_length(bep) | where BackEndPools == 0 | project name, id, Param1='backendPools', Param2=toint(0), tags | union (resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Standard' | extend bep = properties.backendAddressPools | extend BackEndPools = toint(array_length(bep)) | mv-expand bip = properties.backendAddressPools | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses) | where toint(BackendAddresses) <= 1 | project name, id, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | union ( resources | where type =~ 'Microsoft.Network/loadBalancers' | where sku.name == 'Basic' | mv-expand properties.backendAddressPools | extend backendPoolId = properties_backendAddressPools.id | project id, name, tags, tostring(backendPoolId), Param1='BackEndPools' | join kind = leftouter ( resources | where type =~ 'Microsoft.Network/networkInterfaces' | mv-expand properties.ipConfigurations | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id) | summarize poolMembers = count() by backendPoolId | project tostring(backendPoolId), poolMembers ) on backendPoolId | where toint(poolMembers) <= 1 | extend BackendAddresses = poolMembers | project id, name, tags, Param1='backendAddresses', Param2=toint(BackendAddresses)) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Firewall\"\n },\n \"name\": \"tab7title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use application rules to filter outbound traffic on destination host name for supported protocols. Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over other protocols. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext17\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.dnsSettings.enableProxy == true) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query17\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium to enable additional security features. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext18\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.sku.tier == 'Premium') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query18\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall Threat Intelligence mode to Alert and Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps-signature-rules) for further information.\"\n },\n \"name\": \"querytext19\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.threatIntelMode == 'Deny') | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query19\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure Azure Firewall IDPS mode to Deny for additional protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features#idps) for further information.. [This training](https://learn.microsoft.com/training/modules/introduction-azure-firewall/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext20\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/firewallpolicies' | extend compliant = (properties.intrusionDetection.mode == 'Deny') | project id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query20\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"For subnets in VNets not connected to Virtual WAN, attach a route table so that Internet traffic is redirected to Azure Firewall or a Network Virtual Appliance. Check [this link](https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview) for further information.\"\n },\n \"name\": \"querytext21\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetId=tostring(subnets.id), subnetName=tostring(subnets.name),subnetRT=subnets.properties.routeTable.id | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend hasRT = isnotnull(subnetRT) | distinct id, hasRT, subnetId | join kind=fullouter (resources | where type == 'microsoft.network/virtualnetworks' | mvexpand properties.virtualNetworkPeerings | extend isVWAN=(tolower(split(properties_virtualNetworkPeerings.name, '_')[0]) == 'remotevnettohubpeering') | mv-expand properties.subnets | project id, isVWAN, name, subnetId=tostring(properties_subnets.id), subnetName=tostring(properties_subnets.name) | summarize PeeredToVWAN=max(isVWAN) by id, subnetId | project id, subnetId, isVWANpeer = (PeeredToVWAN == true)) on subnetId | project id=iff(isnotempty(id), id, id1), subnetId=iff(isnotempty(subnetId), subnetId, subnetId1), hasRT, isVWANpeer | extend compliant = (hasRT==true or isVWANpeer==true) | distinct id, subnetId, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable Azure Firewall DNS proxy configuration. Check [this link](https://learn.microsoft.com/azure/firewall/dns-details) for further information.. [This training](https://learn.microsoft.com/training/courses/az-700t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext23\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/firewallPolicies' | where array_length(properties.firewalls) > 0 | extend compliant = (properties.dnsSettings.enableProxy =~ 'true') | distinct id, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query23\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Azure Firewall across multiple availability zones. Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance. Check [this link](https://learn.microsoft.com/azure/firewall/deploy-availability-zone-powershell) for further information.. [This training](https://learn.microsoft.com/training/courses/az-104t00/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext24\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/azurefirewalls' | where array_length(zones) <= 1 or isnull(zones) | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | project name, id, tags, param1='multipleZones:false' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query24\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure DDoS Protection on the Azure Firewall VNet, Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans. Check [this link](https://learn.microsoft.com/en-gb/azure/ddos-protection/ddos-protection-overview) for further information.\"\n },\n \"name\": \"querytext25\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'Microsoft.Network/azureFirewalls' | where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id) | mv-expand ipConfig = properties.ipConfigurations | project name, firewallId = id, tags, vNetName = split(ipConfig.properties.subnet.id, '/', 8)[0], vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, /subnet'))) | join kind=fullouter ( resources | where type =~ 'Microsoft.Network/ddosProtectionPlans' | mv-expand vNet = properties.virtualNetworks | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id) ) on vNetId | where isempty(ddosProtectionPlanId) | , name, id = firewallId, tags, param1 = strcat('vNet: ', vNetName), param2 = 'ddosProtection: Disabled' | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 0,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query25\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab7\"\n },\n \"name\": \"tab7\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", "version": "1.0", "sourceId": "[parameters('workbookSourceId')]", "category": "[parameters('workbookType')]" diff --git a/workbooks/appdelivery_checklist.en_network_counters_workbook.json b/workbooks/appdelivery_checklist.en_network_counters_workbook.json index 231ac474..c6571c22 100644 --- a/workbooks/appdelivery_checklist.en_network_counters_workbook.json +++ b/workbooks/appdelivery_checklist.en_network_counters_workbook.json @@ -329,7 +329,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}" + "resultVal": "{Query1Stats:$.Success}+{Query5Stats:$.Success}" } } ] @@ -348,7 +348,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}" + "resultVal": "{Query1Stats:$.Total}+{Query5Stats:$.Total}" } } ] @@ -386,7 +386,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query1Stats:$.Success}+{Query5Stats:$.Success}" + "resultVal": "{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}" } } ] @@ -405,7 +405,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query1Stats:$.Total}+{Query5Stats:$.Total}" + "resultVal": "{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}" } } ] @@ -443,7 +443,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query1Stats:$.Total}+{Query5Stats:$.Total}" + "resultVal": "{Query1Stats:$.Total}+{Query5Stats:$.Total}+{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}" } } ] @@ -462,7 +462,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query1Stats:$.Success}+{Query5Stats:$.Success}" + "resultVal": "{Query1Stats:$.Success}+{Query5Stats:$.Success}+{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}" } } ] @@ -536,21 +536,21 @@ "style": "tabs", "links": [ { - "id": "842c8ee1-0afd-4c1f-a48d-8c346850ab47", + "id": "5031dcb4-ce6e-4c07-a7f7-205dbb020f2a", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "App Gateway ({Tab0Success:value}/{Tab0Total:value})", + "linkLabel": "Load Balancer ({Tab0Success:value}/{Tab0Total:value})", "subTarget": "tab0", - "preText": "App Gateway", + "preText": "Load Balancer", "style": "primary" }, { - "id": "a8c454ab-b50b-4d1d-b369-b96f513f1aae", + "id": "fccd1b99-ca6b-4e1b-9e46-c8dd6e43e849", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Load Balancer ({Tab1Success:value}/{Tab1Total:value})", + "linkLabel": "App Gateway ({Tab1Success:value}/{Tab1Total:value})", "subTarget": "tab1", - "preText": "Load Balancer", + "preText": "App Gateway", "style": "primary" } ] @@ -566,22 +566,22 @@ { "type": 1, "content": { - "json": "## App Gateway" + "json": "## Load Balancer" }, "name": "tab0title" }, { "type": 1, "content": { - "json": "Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information." }, - "name": "querytext0" + "name": "querytext1" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -630,20 +630,20 @@ ] } }, - "name": "query0" + "name": "query1" }, { "type": 1, "content": { - "json": "Your Application Gateways v2 should be deployed in subnets with IP prefixes equal or larger than /24. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information." }, - "name": "querytext2" + "name": "querytext5" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | mv-expand subnets.properties.addressPrefixes | project id, subnetId = tostring(subnets.id), prefix1 = subnets.properties.addressPrefix, prefix2 = subnets.properties.addressPrefixes | mv-expand prefix2 | extend prefix = iff(isnotnull(prefix1), prefix1, prefix2) | extend subnetPrefixLength = split(prefix, '/')[1])on subnetId | extend compliant = (subnetPrefixLength <= 24 or subnetPrefixLength == 64) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -692,20 +692,42 @@ ] } }, - "name": "query2" + "name": "query5" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## App Gateway" + }, + "name": "tab1title" }, { "type": 1, "content": { - "json": "Configure autoscaling with a minimum amount of instances of two. Check [this link](https://learn.microsoft.com/azure/application-gateway/application-gateway-autoscaling-zone-redundant) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext3" + "name": "querytext0" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(properties.autoscaleConfiguration) and properties.autoscaleConfiguration.minCapacity >= 2) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -754,20 +776,20 @@ ] } }, - "name": "query3" + "name": "query0" }, { "type": 1, "content": { - "json": "Deploy Application Gateway across Availability Zones. Check [this link](https://learn.microsoft.com/azure/reliability/migrate-app-gateway-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." + "json": "Your Application Gateways v2 should be deployed in subnets with IP prefixes equal or larger than /24. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext4" + "name": "querytext2" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(zones) and array_length(zones) > 1) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | mv-expand subnets.properties.addressPrefixes | project id, subnetId = tostring(subnets.id), prefix1 = subnets.properties.addressPrefix, prefix2 = subnets.properties.addressPrefixes | mv-expand prefix2 | extend prefix = iff(isnotnull(prefix1), prefix1, prefix2) | extend subnetPrefixLength = split(prefix, '/')[1])on subnetId | extend compliant = (subnetPrefixLength <= 24 or subnetPrefixLength == 64) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -816,20 +838,20 @@ ] } }, - "name": "query4" + "name": "query2" }, { "type": 1, "content": { - "json": "Enable the Azure Application Gateway WAF bot protection rule set. The bot rules detect good and bad bots. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/bot-protection) for further information." + "json": "Configure autoscaling with a minimum amount of instances of two. Check [this link](https://learn.microsoft.com/azure/application-gateway/application-gateway-autoscaling-zone-redundant) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext6" + "name": "querytext3" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | mv-expand properties.managedRules.managedRuleSets | project id, rulesettype = properties_managedRules_managedRuleSets.ruleSetType | extend compliant1 = (rulesettype == 'Microsoft_BotManagerRuleSet') | project id, compliant1 | summarize compliant = max(compliant1) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(properties.autoscaleConfiguration) and properties.autoscaleConfiguration.minCapacity >= 2) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -878,20 +900,20 @@ ] } }, - "name": "query6" + "name": "query3" }, { "type": 1, "content": { - "json": "Ensure if request body inspection feature is enabled in Azure Application Gateway WAF policy. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection) for further information." + "json": "Deploy Application Gateway across Availability Zones. Check [this link](https://learn.microsoft.com/azure/reliability/migrate-app-gateway-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this." }, - "name": "querytext7" + "name": "querytext4" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | extend compliant = (properties['policySettings']['requestBodyCheck'] == 'true' and properties['policySettings']['state'] =~ 'Enabled') | distinct id, name, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(zones) and array_length(zones) > 1) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -940,20 +962,20 @@ ] } }, - "name": "query7" + "name": "query4" }, { "type": 1, "content": { - "json": "You should encrypt traffic to the backend servers. Check [this link](https://learn.microsoft.com/azure/application-gateway/ssl-overview) for further information." + "json": "Enable the Azure Application Gateway WAF bot protection rule set. The bot rules detect good and bad bots. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/bot-protection) for further information." }, - "name": "querytext8" + "name": "querytext6" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/applicationgateways'| extend compliant = (properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443') |where properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443'|distinct id,name,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | mv-expand properties.managedRules.managedRuleSets | project id, rulesettype = properties_managedRules_managedRuleSets.ruleSetType | extend compliant1 = (rulesettype == 'Microsoft_BotManagerRuleSet') | project id, compliant1 | summarize compliant = max(compliant1) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1002,42 +1024,20 @@ ] } }, - "name": "query8" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab0" - }, - "name": "tab0" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Load Balancer" - }, - "name": "tab1title" + "name": "query6" }, { "type": 1, "content": { - "json": "Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information." + "json": "Ensure if request body inspection feature is enabled in Azure Application Gateway WAF policy. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection) for further information." }, - "name": "querytext1" + "name": "querytext7" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | extend compliant = (properties['policySettings']['requestBodyCheck'] == 'true' and properties['policySettings']['state'] =~ 'Enabled') | distinct id, name, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1086,20 +1086,20 @@ ] } }, - "name": "query1" + "name": "query7" }, { "type": 1, "content": { - "json": "Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information." + "json": "You should encrypt traffic to the backend servers. Check [this link](https://learn.microsoft.com/azure/application-gateway/ssl-overview) for further information." }, - "name": "querytext5" + "name": "querytext8" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", + "query": "resources | where type == 'microsoft.network/applicationgateways'| extend compliant = (properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443') |where properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443'|distinct id,name,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1148,7 +1148,7 @@ ] } }, - "name": "query5" + "name": "query8" } ] }, diff --git a/workbooks/appdelivery_checklist.en_network_counters_workbook_template.json b/workbooks/appdelivery_checklist.en_network_counters_workbook_template.json index 74dceccb..89737f71 100644 --- a/workbooks/appdelivery_checklist.en_network_counters_workbook_template.json +++ b/workbooks/appdelivery_checklist.en_network_counters_workbook_template.json @@ -41,7 +41,7 @@ "dependsOn": [], "properties": { "displayName": "[parameters('workbookDisplayName')]", - "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"value::all\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard')| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | mv-expand subnets.properties.addressPrefixes | project id, subnetId = tostring(subnets.id), prefix1 = subnets.properties.addressPrefix, prefix2 = subnets.properties.addressPrefixes | mv-expand prefix2 | extend prefix = iff(isnotnull(prefix1), prefix1, prefix2) | extend subnetPrefixLength = split(prefix, '/')[1])on subnetId | extend compliant = (subnetPrefixLength <= 24 or subnetPrefixLength == 64) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(properties.autoscaleConfiguration) and properties.autoscaleConfiguration.minCapacity >= 2) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(zones) and array_length(zones) > 1) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | mv-expand properties.managedRules.managedRuleSets | project id, rulesettype = properties_managedRules_managedRuleSets.ruleSetType | extend compliant1 = (rulesettype == 'Microsoft_BotManagerRuleSet') | project id, compliant1 | summarize compliant = max(compliant1) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | extend compliant = (properties['policySettings']['requestBodyCheck'] == 'true' and properties['policySettings']['state'] =~ 'Enabled') | distinct id, name, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways'| extend compliant = (properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443') |where properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443'|distinct id,name,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query1Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query1Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookTotal\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query1Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookSuccess\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query1Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookPercent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{WorkbookSuccess}/{WorkbookTotal})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"InvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Application Delivery Networking - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"50\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"WorkbookPercent\\\\\\\": \\\\\\\"{WorkbookPercent}\\\\\\\", \\\\\\\"SubTitle\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 4,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"WorkbookPercent\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"SubTitle\",\n \"formatter\": 1\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"ProgressTile\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"842c8ee1-0afd-4c1f-a48d-8c346850ab47\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App Gateway ({Tab0Success:value}/{Tab0Total:value})\",\n \"subTarget\": \"tab0\",\n \"preText\": \"App Gateway\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"a8c454ab-b50b-4d1d-b369-b96f513f1aae\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Load Balancer ({Tab1Success:value}/{Tab1Total:value})\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Load Balancer\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App Gateway\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your Application Gateways v2 should be deployed in subnets with IP prefixes equal or larger than /24. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | mv-expand subnets.properties.addressPrefixes | project id, subnetId = tostring(subnets.id), prefix1 = subnets.properties.addressPrefix, prefix2 = subnets.properties.addressPrefixes | mv-expand prefix2 | extend prefix = iff(isnotnull(prefix1), prefix1, prefix2) | extend subnetPrefixLength = split(prefix, '/')[1])on subnetId | extend compliant = (subnetPrefixLength <= 24 or subnetPrefixLength == 64) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure autoscaling with a minimum amount of instances of two. Check [this link](https://learn.microsoft.com/azure/application-gateway/application-gateway-autoscaling-zone-redundant) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(properties.autoscaleConfiguration) and properties.autoscaleConfiguration.minCapacity >= 2) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Application Gateway across Availability Zones. Check [this link](https://learn.microsoft.com/azure/reliability/migrate-app-gateway-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(zones) and array_length(zones) > 1) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable the Azure Application Gateway WAF bot protection rule set. The bot rules detect good and bad bots. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/bot-protection) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | mv-expand properties.managedRules.managedRuleSets | project id, rulesettype = properties_managedRules_managedRuleSets.ruleSetType | extend compliant1 = (rulesettype == 'Microsoft_BotManagerRuleSet') | project id, compliant1 | summarize compliant = max(compliant1) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure if request body inspection feature is enabled in Azure Application Gateway WAF policy. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | extend compliant = (properties['policySettings']['requestBodyCheck'] == 'true' and properties['policySettings']['state'] =~ 'Enabled') | distinct id, name, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"You should encrypt traffic to the backend servers. Check [this link](https://learn.microsoft.com/azure/application-gateway/ssl-overview) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways'| extend compliant = (properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443') |where properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443'|distinct id,name,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Load Balancer\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", + "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"crossComponentResources\": [\n \"value::all\"\n ],\n \"parameters\": [\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query0FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query0Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard')| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query1FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query1Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | mv-expand subnets.properties.addressPrefixes | project id, subnetId = tostring(subnets.id), prefix1 = subnets.properties.addressPrefix, prefix2 = subnets.properties.addressPrefixes | mv-expand prefix2 | extend prefix = iff(isnotnull(prefix1), prefix1, prefix2) | extend subnetPrefixLength = split(prefix, '/')[1])on subnetId | extend compliant = (subnetPrefixLength <= 24 or subnetPrefixLength == 64) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query2FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query2Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(properties.autoscaleConfiguration) and properties.autoscaleConfiguration.minCapacity >= 2) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query3FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query3Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(zones) and array_length(zones) > 1) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query4FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query4Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5Stats\",\n \"type\": 1,\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query5FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query5Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | mv-expand properties.managedRules.managedRuleSets | project id, rulesettype = properties_managedRules_managedRuleSets.ruleSetType | extend compliant1 = (rulesettype == 'Microsoft_BotManagerRuleSet') | project id, compliant1 | summarize compliant = max(compliant1) by id| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query6FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query6Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7Stats\",\n \"type\": 1,\n \"query\": \"resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | extend compliant = (properties['policySettings']['requestBodyCheck'] == 'true' and properties['policySettings']['state'] =~ 'Enabled') | distinct id, name, compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query7FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query7Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8Stats\",\n \"type\": 1,\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways'| extend compliant = (properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443') |where properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443'|distinct id,name,compliant| summarize Total = count(), Success = countif(compliant==1), Failed = countif(compliant==0) | extend SuccessPercent = iff(Total==0, 100, 100*toint(Success)/toint(Total)) | extend FullyCompliant = iff(SuccessPercent == 100, 'Yes', 'No') | project Query1Stats=tostring(pack_all())\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Query8FullyCompliant\",\n \"type\": 1,\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"value\\\\\\\": \\\\\\\"{Query8Stats:$.FullyCompliant}\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"queryType\": 8\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query1Stats:$.Success}+{Query5Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query1Stats:$.Total}+{Query5Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab0Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab0Success}/{Tab0Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Success\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Total\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Tab1Percent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{Tab1Success}/{Tab1Total})\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookTotal\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query1Stats:$.Total}+{Query5Stats:$.Total}+{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookSuccess\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"{Query1Stats:$.Success}+{Query5Stats:$.Success}+{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}\"\n }\n }\n ]\n },\n {\n \"id\": \"daf05c62-1d5b-4325-b241-d7ee468f23eb\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"WorkbookPercent\",\n \"type\": 1,\n \"isHiddenWhenLocked\": true,\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"criteriaData\": [\n {\n \"criteriaContext\": {\n \"operator\": \"Default\",\n \"resultValType\": \"expression\",\n \"resultVal\": \"round(100*{WorkbookSuccess}/{WorkbookTotal})\"\n }\n }\n ]\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\"\n },\n \"name\": \"InvisibleParameters\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Application Delivery Networking - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"50\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"{\\\"version\\\":\\\"1.0.0\\\",\\\"content\\\":\\\"{\\\\\\\"WorkbookPercent\\\\\\\": \\\\\\\"{WorkbookPercent}\\\\\\\", \\\\\\\"SubTitle\\\\\\\": \\\\\\\"Percent of successful checks\\\\\\\"}\\\",\\\"transformers\\\":null}\",\n \"size\": 4,\n \"queryType\": 8,\n \"visualization\": \"tiles\",\n \"tileSettings\": {\n \"titleContent\": {\n \"columnMatch\": \"WorkbookPercent\",\n \"formatter\": 4,\n \"formatOptions\": {\n \"min\": 0,\n \"max\": 100,\n \"palette\": \"redGreen\"\n }\n },\n \"subtitleContent\": {\n \"columnMatch\": \"SubTitle\",\n \"formatter\": 1\n },\n \"showBorder\": true\n }\n },\n \"customWidth\": \"50\",\n \"name\": \"ProgressTile\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"5031dcb4-ce6e-4c07-a7f7-205dbb020f2a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Load Balancer ({Tab0Success:value}/{Tab0Total:value})\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Load Balancer\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"fccd1b99-ca6b-4e1b-9e46-c8dd6e43e849\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App Gateway ({Tab1Success:value}/{Tab1Total:value})\",\n \"subTarget\": \"tab1\",\n \"preText\": \"App Gateway\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Load Balancer\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App Gateway\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your Application Gateways v2 should be deployed in subnets with IP prefixes equal or larger than /24. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | mv-expand subnets.properties.addressPrefixes | project id, subnetId = tostring(subnets.id), prefix1 = subnets.properties.addressPrefix, prefix2 = subnets.properties.addressPrefixes | mv-expand prefix2 | extend prefix = iff(isnotnull(prefix1), prefix1, prefix2) | extend subnetPrefixLength = split(prefix, '/')[1])on subnetId | extend compliant = (subnetPrefixLength <= 24 or subnetPrefixLength == 64) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure autoscaling with a minimum amount of instances of two. Check [this link](https://learn.microsoft.com/azure/application-gateway/application-gateway-autoscaling-zone-redundant) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(properties.autoscaleConfiguration) and properties.autoscaleConfiguration.minCapacity >= 2) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Application Gateway across Availability Zones. Check [this link](https://learn.microsoft.com/azure/reliability/migrate-app-gateway-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(zones) and array_length(zones) > 1) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable the Azure Application Gateway WAF bot protection rule set. The bot rules detect good and bad bots. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/bot-protection) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | mv-expand properties.managedRules.managedRuleSets | project id, rulesettype = properties_managedRules_managedRuleSets.ruleSetType | extend compliant1 = (rulesettype == 'Microsoft_BotManagerRuleSet') | project id, compliant1 | summarize compliant = max(compliant1) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure if request body inspection feature is enabled in Azure Application Gateway WAF policy. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | extend compliant = (properties['policySettings']['requestBodyCheck'] == 'true' and properties['policySettings']['state'] =~ 'Enabled') | distinct id, name, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"You should encrypt traffic to the backend servers. Check [this link](https://learn.microsoft.com/azure/application-gateway/ssl-overview) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways'| extend compliant = (properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443') |where properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443'|distinct id,name,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", "version": "1.0", "sourceId": "[parameters('workbookSourceId')]", "category": "[parameters('workbookType')]" diff --git a/workbooks/appdelivery_checklist.en_network_workbook.json b/workbooks/appdelivery_checklist.en_network_workbook.json index 8c34d370..77f81d67 100644 --- a/workbooks/appdelivery_checklist.en_network_workbook.json +++ b/workbooks/appdelivery_checklist.en_network_workbook.json @@ -70,7 +70,7 @@ "style": "tabs", "links": [ { - "id": "849f6f19-53d3-4a15-8901-5fc567a80efc", + "id": "d2797f6a-633c-487c-bbbc-e6e0ef7bdc78", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Load Balancer", @@ -79,7 +79,7 @@ "style": "primary" }, { - "id": "c8c84999-a671-4d7f-86e2-d00192ee10be", + "id": "bf2db8b9-6cdc-42fd-9cb6-f4febd9d9140", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "App Gateway", diff --git a/workbooks/appdelivery_checklist.en_network_workbook_template.json b/workbooks/appdelivery_checklist.en_network_workbook_template.json index b07d8da7..cbc56f7c 100644 --- a/workbooks/appdelivery_checklist.en_network_workbook_template.json +++ b/workbooks/appdelivery_checklist.en_network_workbook_template.json @@ -41,7 +41,7 @@ "dependsOn": [], "properties": { "displayName": "[parameters('workbookDisplayName')]", - "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Application Delivery Networking - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"849f6f19-53d3-4a15-8901-5fc567a80efc\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Load Balancer\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Load Balancer\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"c8c84999-a671-4d7f-86e2-d00192ee10be\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App Gateway\",\n \"subTarget\": \"tab1\",\n \"preText\": \"App Gateway\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Load Balancer\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App Gateway\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your Application Gateways v2 should be deployed in subnets with IP prefixes equal or larger than /24. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | mv-expand subnets.properties.addressPrefixes | project id, subnetId = tostring(subnets.id), prefix1 = subnets.properties.addressPrefix, prefix2 = subnets.properties.addressPrefixes | mv-expand prefix2 | extend prefix = iff(isnotnull(prefix1), prefix1, prefix2) | extend subnetPrefixLength = split(prefix, '/')[1])on subnetId | extend compliant = (subnetPrefixLength <= 24 or subnetPrefixLength == 64) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure autoscaling with a minimum amount of instances of two. Check [this link](https://learn.microsoft.com/azure/application-gateway/application-gateway-autoscaling-zone-redundant) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(properties.autoscaleConfiguration) and properties.autoscaleConfiguration.minCapacity >= 2) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Application Gateway across Availability Zones. Check [this link](https://learn.microsoft.com/azure/reliability/migrate-app-gateway-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(zones) and array_length(zones) > 1) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable the Azure Application Gateway WAF bot protection rule set. The bot rules detect good and bad bots. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/bot-protection) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | mv-expand properties.managedRules.managedRuleSets | project id, rulesettype = properties_managedRules_managedRuleSets.ruleSetType | extend compliant1 = (rulesettype == 'Microsoft_BotManagerRuleSet') | project id, compliant1 | summarize compliant = max(compliant1) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure if request body inspection feature is enabled in Azure Application Gateway WAF policy. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | extend compliant = (properties['policySettings']['requestBodyCheck'] == 'true' and properties['policySettings']['state'] =~ 'Enabled') | distinct id, name, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"You should encrypt traffic to the backend servers. Check [this link](https://learn.microsoft.com/azure/application-gateway/ssl-overview) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways'| extend compliant = (properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443') |where properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443'|distinct id,name,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", + "serializedData": "{\n \"version\": \"Notebook/1.0\",\n \"items\": [\n {\n \"type\": 9,\n \"content\": {\n \"version\": \"KqlParameterItem/1.0\",\n \"parameters\": [\n {\n \"id\": \"497a107e-dde8-433e-b263-35ac8e8f7834\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"Subscription\",\n \"type\": 6,\n \"multiSelect\": true,\n \"quote\": \"'\",\n \"delimiter\": \",\",\n \"typeSettings\": {\n \"additionalResourceOptions\": [\n \"value::all\"\n ],\n \"includeAll\": true,\n \"showDefault\": false\n },\n \"timeContext\": {\n \"durationMs\": 86400000\n },\n \"value\": [\n \"value::all\"\n ]\n },\n {\n \"id\": \"844e4f4e-df51-4e3c-8eaf-0dc78b92c721\",\n \"version\": \"KqlParameterItem/1.0\",\n \"name\": \"OnlyFailed\",\n \"label\": \"Only show failed\",\n \"type\": 2,\n \"typeSettings\": {\n \"additionalResourceOptions\": [],\n \"showDefault\": false\n },\n \"jsonData\": \"[\\r\\n { \\\"value\\\":true, \\\"label\\\":\\\"True\\\" },\\r\\n { \\\"value\\\":false, \\\"label\\\":\\\"False\\\", \\\"selected\\\":true }\\r\\n]\"\n }\n ],\n \"style\": \"pills\",\n \"queryType\": 0,\n \"resourceType\": \"microsoft.operationalinsights/workspaces\"\n },\n \"name\": \"WorkbookSelectors\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"If you set \\\"Only show failed\\\" to \\\"Yes\\\", the different queries will only show items that have failed their compliance checks.\",\n \"style\": \"info\"\n },\n \"name\": \"InfoBox\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Azure Application Delivery Networking - Network\\n\\n---\\n\\nThis workbook has been automatically generated out of the checklists in the [Azure Review Checklists repo](https://github.com/Azure/review-checklists). This repo contains best practices and recommendations around generic Landing Zones as well as specific services such as Azure Virtual Desktop, Azure Kubernetes Service or Azure VMware Solution, to name a few. This repository of best practices is curated by Azure engineers, but open to anybody to contribute.\\n\\nIf you see a problem in the queries that are part of this workbook, please open a Github issue [here](https://github.com/Azure/review-checklists/issues/new).\"\n },\n \"customWidth\": \"100\",\n \"name\": \"MarkdownHeader\"\n },\n {\n \"type\": 11,\n \"content\": {\n \"version\": \"LinkItem/1.0\",\n \"style\": \"tabs\",\n \"links\": [\n {\n \"id\": \"d2797f6a-633c-487c-bbbc-e6e0ef7bdc78\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Load Balancer\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Load Balancer\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"bf2db8b9-6cdc-42fd-9cb6-f4febd9d9140\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App Gateway\",\n \"subTarget\": \"tab1\",\n \"preText\": \"App Gateway\",\n \"style\": \"primary\"\n }\n ]\n },\n \"name\": \"Tabs\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## Load Balancer\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using the Standard SKU for your Azure Load Balancers. Check [this link](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for further information.\"\n },\n \"name\": \"querytext1\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/loadbalancers' | project id, compliant=(tolower(sku.name) == 'standard') | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query1\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure NAT Gateway instead of Load Balancer outbound rules for better SNAT scalability. Check [this link](https://learn.microsoft.com/azure/nat-gateway/nat-overview#outbound-connectivity) for further information.\"\n },\n \"name\": \"querytext5\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/loadbalancers' | extend countOutRules=array_length(properties.outboundRules) | extend compliant = (countOutRules == 0) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query5\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab0\"\n },\n \"name\": \"tab0\"\n },\n {\n \"type\": 12,\n \"content\": {\n \"version\": \"NotebookGroup/1.0\",\n \"groupType\": \"editable\",\n \"items\": [\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"## App Gateway\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure you are using Application Gateway v2 SKU. Check [this link](https://learn.microsoft.com/azure/application-gateway/overview-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext0\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways' | project id, compliant = properties.sku.name in ('Standard_v2', 'WAF_v2') | project id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query0\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Your Application Gateways v2 should be deployed in subnets with IP prefixes equal or larger than /24. Check [this link](https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext2\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type=='microsoft.network/applicationgateways' | extend subnetId = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id) | project id, subnetId | join (resources | where type=='microsoft.network/virtualnetworks' | project id,subnets=properties.subnets | mv-expand subnets | mv-expand subnets.properties.addressPrefixes | project id, subnetId = tostring(subnets.id), prefix1 = subnets.properties.addressPrefix, prefix2 = subnets.properties.addressPrefixes | mv-expand prefix2 | extend prefix = iff(isnotnull(prefix1), prefix1, prefix2) | extend subnetPrefixLength = split(prefix, '/')[1])on subnetId | extend compliant = (subnetPrefixLength <= 24 or subnetPrefixLength == 64) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query2\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Configure autoscaling with a minimum amount of instances of two. Check [this link](https://learn.microsoft.com/azure/application-gateway/application-gateway-autoscaling-zone-redundant) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext3\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(properties.autoscaleConfiguration) and properties.autoscaleConfiguration.minCapacity >= 2) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query3\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy Application Gateway across Availability Zones. Check [this link](https://learn.microsoft.com/azure/reliability/migrate-app-gateway-v2) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-application-delivery/) can help to educate yourself on this.\"\n },\n \"name\": \"querytext4\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationGateways' | extend compliant = (isnotnull(zones) and array_length(zones) > 1) | distinct id,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query4\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Enable the Azure Application Gateway WAF bot protection rule set. The bot rules detect good and bad bots. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/bot-protection) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | mv-expand properties.managedRules.managedRuleSets | project id, rulesettype = properties_managedRules_managedRuleSets.ruleSetType | extend compliant1 = (rulesettype == 'Microsoft_BotManagerRuleSet') | project id, compliant1 | summarize compliant = max(compliant1) by id | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query6\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure if request body inspection feature is enabled in Azure Application Gateway WAF policy. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits#request-body-inspection) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | extend compliant = (properties['policySettings']['requestBodyCheck'] == 'true' and properties['policySettings']['state'] =~ 'Enabled') | distinct id, name, compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query7\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"You should encrypt traffic to the backend servers. Check [this link](https://learn.microsoft.com/azure/application-gateway/ssl-overview) for further information.\"\n },\n \"name\": \"querytext8\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"resources | where type == 'microsoft.network/applicationgateways'| extend compliant = (properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443') |where properties['backendHttpSettingsCollection'][0]['properties']['port'] =~ '443'|distinct id,name,compliant | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed\",\n \"size\": 4,\n \"queryType\": 1,\n \"resourceType\": \"microsoft.resourcegraph/resources\",\n \"crossComponentResources\": [\n \"{Subscription}\"\n ],\n \"gridSettings\": {\n \"formatters\": [\n {\n \"columnMatch\": \"id\",\n \"formatter\": 0,\n \"numberFormat\": {\n \"unit\": 0,\n \"options\": {\n \"style\": \"decimal\"\n }\n }\n },\n {\n \"columnMatch\": \"compliant\",\n \"formatter\": 18,\n \"formatOptions\": {\n \"thresholdsOptions\": \"icons\",\n \"thresholdsGrid\": [\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"1\",\n \"representation\": \"success\",\n \"text\": \"Success\"\n },\n {\n \"operator\": \"==\",\n \"thresholdValue\": \"0\",\n \"representation\": \"failed\",\n \"text\": \"Failed\"\n },\n {\n \"operator\": \"Default\",\n \"thresholdValue\": null,\n \"representation\": \"unknown\",\n \"text\": \"Unknown\"\n }\n ]\n }\n }\n ]\n }\n },\n \"name\": \"query8\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab1\"\n },\n \"name\": \"tab1\"\n }\n ],\n \"$schema\": \"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"\n}", "version": "1.0", "sourceId": "[parameters('workbookSourceId')]", "category": "[parameters('workbookType')]"