diff --git a/checklists/checklist.en.master.json b/checklists/checklist.en.master.json index c0e134dfc..a23643531 100644 --- a/checklists/checklist.en.master.json +++ b/checklists/checklist.en.master.json @@ -164,9 +164,9 @@ "service": "ACR", "services": [ "ACR", - "EventHubs", "PrivateLink", - "Entra" + "Entra", + "EventHubs" ], "severity": "High", "subcategory": "Identity and Access Control", @@ -183,8 +183,8 @@ "service": "ACR", "services": [ "ACR", - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "Medium", "subcategory": "Identity and Access Control", @@ -200,9 +200,9 @@ "link": "https://learn.microsoft.com/azure/container-registry/monitor-service", "service": "ACR", "services": [ - "Monitor", "ACR", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Logging and Monitoring", @@ -219,9 +219,9 @@ "service": "ACR", "services": [ "ACR", - "Firewall", "PrivateLink", - "VNet" + "VNet", + "Firewall" ], "severity": "Medium", "subcategory": "Network Security", @@ -318,8 +318,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", @@ -334,8 +334,8 @@ "id": "A02.01", "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", @@ -351,8 +351,8 @@ "link": "Best practice to deploy backup in the same region as your AVS deployment", "services": [ "ASR", - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -477,8 +477,8 @@ "id": "A03.06", "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": [ - "ExpressRoute", "ASR", + "ExpressRoute", "AVS", "NVA" ], @@ -495,8 +495,8 @@ "id": "B01.01", "link": "https://learn.microsoft.com/azure/azure-vmware/tutorial-expressroute-global-reach-private-cloud", "services": [ - "VWAN", - "AVS" + "AVS", + "VWAN" ], "severity": "Medium", "subcategory": "Direct (no vWAN, no H&S)", @@ -575,8 +575,8 @@ "id": "B03.01", "link": "https://learn.microsoft.com/azure/virtual-network/quick-create-portal", "services": [ - "VNet", - "AVS" + "AVS", + "VNet" ], "severity": "Medium", "subcategory": "Hub & Spoke", @@ -591,10 +591,10 @@ "id": "B03.02", "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings", "services": [ - "ExpressRoute", "VPN", - "VNet", - "AVS" + "ExpressRoute", + "AVS", + "VNet" ], "severity": "Medium", "subcategory": "Hub & Spoke", @@ -609,10 +609,10 @@ "id": "B03.03", "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings", "services": [ - "ExpressRoute", - "VPN", "VNet", - "AVS" + "ExpressRoute", + "AVS", + "VPN" ], "severity": "Medium", "subcategory": "Hub & Spoke", @@ -627,10 +627,10 @@ "id": "B03.04", "link": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings", "services": [ - "ExpressRoute", "VPN", - "VNet", - "AVS" + "ExpressRoute", + "AVS", + "VNet" ], "severity": "Medium", "subcategory": "Hub & Spoke", @@ -645,8 +645,8 @@ "id": "B04.01", "link": "https://learn.microsoft.com/azure/azure-vmware/enable-public-internet-access", "services": [ - "NVA", - "AVS" + "AVS", + "NVA" ], "severity": "Medium", "subcategory": "Internet", @@ -678,8 +678,8 @@ "link": "https://learn.microsoft.com/azure/bastion/tutorial-create-host-portal", "services": [ "Bastion", - "VNet", - "AVS" + "AVS", + "VNet" ], "severity": "Medium", "subcategory": "Jumpbox & Bastion", @@ -711,8 +711,8 @@ "id": "B06.01", "link": "https://learn.microsoft.com/azure/azure-vmware/configure-site-to-site-vpn-gateway", "services": [ - "VPN", - "AVS" + "AVS", + "VPN" ], "severity": "Medium", "subcategory": "VPN", @@ -727,8 +727,8 @@ "id": "B06.02", "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": [ - "VPN", - "AVS" + "AVS", + "VPN" ], "severity": "Medium", "subcategory": "VPN", @@ -743,8 +743,8 @@ "id": "B06.03", "link": "https://learn.microsoft.com/azure/architecture/solution-ideas/articles/azure-vmware-solution-foundation-networking", "services": [ - "VPN", - "AVS" + "AVS", + "VPN" ], "severity": "Medium", "subcategory": "VPN", @@ -759,8 +759,8 @@ "id": "B07.01", "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-site-to-site-portal#openvwan", "services": [ - "VWAN", - "AVS" + "AVS", + "VWAN" ], "severity": "Medium", "subcategory": "vWAN hub", @@ -775,9 +775,9 @@ "id": "B07.02", "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-point-to-site-portal", "services": [ - "VWAN", + "AVS", "VPN", - "AVS" + "VWAN" ], "severity": "Medium", "subcategory": "vWAN hub", @@ -792,9 +792,9 @@ "id": "B07.03", "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-expressroute-portal", "services": [ - "VWAN", "Firewall", - "AVS" + "AVS", + "VWAN" ], "severity": "Medium", "subcategory": "vWAN hub", @@ -889,8 +889,8 @@ "id": "C02.02", "link": "https://learn.microsoft.com/azure/azure-vmware/concepts-identity", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "Medium", @@ -906,8 +906,8 @@ "id": "C02.03", "link": "https://learn.microsoft.com/azure/azure-vmware/concepts-identity#view-the-vcenter-server-privileges", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "Medium", @@ -923,8 +923,8 @@ "id": "C02.04", "link": "Best practice", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "Medium", @@ -940,8 +940,8 @@ "id": "C03.01", "link": "https://learn.microsoft.com/azure/active-directory/privileged-identity-management/pim-configure", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "Medium", @@ -957,8 +957,8 @@ "id": "C03.02", "link": "https://learn.microsoft.com/azure/active-directory/privileged-identity-management/pim-configure", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "Medium", @@ -1008,8 +1008,8 @@ "link": "https://learn.microsoft.com/azure/azure-arc/vmware-vsphere/overview", "services": [ "VM", - "Arc", - "AVS" + "AVS", + "Arc" ], "severity": "Medium", "subcategory": "Operations", @@ -1024,9 +1024,9 @@ "id": "D01.02", "link": "https://docs.microsoft.com/azure/governance/policy/overview", "services": [ - "Monitor", + "AzurePolicy", "AVS", - "AzurePolicy" + "Monitor" ], "severity": "Medium", "subcategory": "Operations", @@ -1087,8 +1087,8 @@ "id": "E01.01", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-alerts-for-azure-vmware-solution", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Alerts", @@ -1103,8 +1103,8 @@ "id": "E01.02", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-alerts-for-azure-vmware-solution", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Alerts", @@ -1119,8 +1119,8 @@ "id": "E01.03", "link": "https://www.virtualworkloads.com/2021/04/azure-vmware-solution-azure-service-health/", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Alerts", @@ -1135,11 +1135,11 @@ "id": "E02.01", "link": "https://docs.microsoft.com/azure/azure-vmware/set-up-backup-server-for-azure-vmware-solution", "services": [ - "VM", - "Monitor", - "AVS", "Backup", - "AzurePolicy" + "Monitor", + "AzurePolicy", + "VM", + "AVS" ], "severity": "Medium", "subcategory": "Backup", @@ -1154,9 +1154,9 @@ "id": "E03.01", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-alerts-for-azure-vmware-solution", "services": [ - "Monitor", + "AzurePolicy", "AVS", - "AzurePolicy" + "Monitor" ], "severity": "Medium", "subcategory": "Capacity", @@ -1171,10 +1171,10 @@ "id": "E04.01", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/govern", "services": [ - "Monitor", "Cost", + "Subscriptions", "AVS", - "Subscriptions" + "Monitor" ], "severity": "Medium", "subcategory": "Costs", @@ -1189,9 +1189,9 @@ "id": "E05.01", "link": "https://docs.microsoft.com/azure/azure-portal/azure-portal-dashboards", "services": [ - "Monitor", "NetworkWatcher", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Dashboard", @@ -1206,9 +1206,9 @@ "id": "E06.01", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-vmware-syslogs", "services": [ - "Monitor", "Storage", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Logs & Metrics", @@ -1223,8 +1223,8 @@ "id": "E06.02", "link": "Is vROPS or vRealize Network Insight going to be used? ", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Logs & Metrics", @@ -1256,11 +1256,11 @@ "id": "E07.01", "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-create-using-portal", "services": [ - "ExpressRoute", "Monitor", "VPN", - "AVS", - "NetworkWatcher" + "ExpressRoute", + "NetworkWatcher", + "AVS" ], "severity": "Medium", "subcategory": "Network", @@ -1275,9 +1275,9 @@ "id": "E07.02", "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-create-using-portal", "services": [ - "Monitor", + "ExpressRoute", "AVS", - "ExpressRoute" + "Monitor" ], "severity": "Medium", "subcategory": "Network", @@ -1292,8 +1292,8 @@ "id": "E07.03", "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-create-using-portal", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Network", @@ -1308,8 +1308,8 @@ "id": "E08.01", "link": "Firewall logging and alerting rules are configured (Azure Firewall or 3rd party)", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Security", @@ -1324,8 +1324,8 @@ "id": "E08.02", "link": "https://docs.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-network-topology-connectivity", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Security", @@ -1340,8 +1340,8 @@ "id": "E09.01", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-vmware-syslogs", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "VMWare", @@ -1403,9 +1403,9 @@ "id": "F01.03", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-network-topology-connectivity", "services": [ + "AVS", "ARS", - "NVA", - "AVS" + "NVA" ], "severity": "Medium", "subcategory": "Hub & Spoke", @@ -1420,8 +1420,8 @@ "id": "F01.04", "link": "https://learn.microsoft.com/azure/route-server/route-server-faq", "services": [ - "ARS", - "AVS" + "AVS", + "ARS" ], "severity": "Medium", "subcategory": "Hub & Spoke", @@ -1451,10 +1451,10 @@ "id": "F02.02", "link": "Research and choose optimal solution for each application", "services": [ - "FrontDoor", - "AVS", + "NVA", "AppGW", - "NVA" + "AVS", + "FrontDoor" ], "severity": "Medium", "subcategory": "Internet", @@ -1469,8 +1469,8 @@ "id": "F03.01", "link": "https://docs.microsoft.com/azure/route-server/route-server-faq#route-server-limits", "services": [ - "ARS", - "AVS" + "AVS", + "ARS" ], "severity": "Medium", "subcategory": "Routing", @@ -1485,15 +1485,15 @@ "id": "F04.01", "link": "https://docs.microsoft.com/azure/ddos-protection/manage-ddos-protection", "services": [ - "ExpressRoute", - "VM", + "LoadBalancer", + "DDoS", "VPN", - "FrontDoor", - "AVS", "VNet", "AppGW", - "DDoS", - "LoadBalancer" + "ExpressRoute", + "FrontDoor", + "VM", + "AVS" ], "severity": "Medium", "subcategory": "Security", @@ -1539,8 +1539,8 @@ "link": "https://learn.microsoft.com/azure/architecture/networking/hub-spoke-vwan-architecture", "services": [ "VWAN", - "Firewall", - "AVS" + "AVS", + "Firewall" ], "severity": "Medium", "subcategory": "Virtual WAN", @@ -1555,8 +1555,8 @@ "id": "F06.02", "link": "https://learn.microsoft.com/azure/firewall-manager/secure-cloud-network", "services": [ - "VWAN", - "AVS" + "AVS", + "VWAN" ], "severity": "Medium", "subcategory": "Virtual WAN", @@ -1571,8 +1571,8 @@ "id": "G01.01", "link": "https://docs.microsoft.com/azure/azure-vmware/configure-nsx-network-components-azure-portal", "services": [ - "AVS", - "Subscriptions" + "Subscriptions", + "AVS" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -1588,8 +1588,8 @@ "link": "https://docs.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-platform-automation-and-devops#automated-scale", "services": [ "Storage", - "AVS", - "AzurePolicy" + "AzurePolicy", + "AVS" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -1649,8 +1649,8 @@ "id": "G01.06", "link": "https://docs.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-management-and-monitoring", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -1711,8 +1711,8 @@ "id": "H01.02", "link": "Internal policy or regulatory compliance", "services": [ - "AVS", - "AzurePolicy" + "AzurePolicy", + "AVS" ], "severity": "Medium", "subcategory": "Pre-deployment", @@ -1757,8 +1757,8 @@ "id": "H01.05", "link": "Done through the subscription/resource providers/ AVS register in the portal", "services": [ - "AVS", - "Subscriptions" + "Subscriptions", + "AVS" ], "severity": "Medium", "subcategory": "Pre-deployment", @@ -1773,8 +1773,8 @@ "id": "H01.06", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-vmware/enterprise-scale-landing-zone", "services": [ - "AVS", - "Subscriptions" + "Subscriptions", + "AVS" ], "severity": "Medium", "subcategory": "Pre-deployment", @@ -1834,8 +1834,8 @@ "id": "H01.10", "link": "https://docs.vmware.com/en/VMware-NSX-T-Data-Center/3.2/installation/GUID-4B3860B8-1883-48CA-B2F3-7C2205D91D6D.html", "services": [ - "VNet", - "AVS" + "AVS", + "VNet" ], "severity": "Medium", "subcategory": "Pre-deployment", @@ -2006,8 +2006,8 @@ "id": "I03.01", "link": "https://learn.microsoft.com/azure/sentinel/overview", "services": [ - "AVS", - "Sentinel" + "Sentinel", + "AVS" ], "severity": "Medium", "subcategory": "Investigation", @@ -2038,8 +2038,8 @@ "id": "I04.02", "link": "https://docs.microsoft.com/azure/azure-vmware/azure-security-integration", "services": [ - "AVS", - "AzurePolicy" + "AzurePolicy", + "AVS" ], "severity": "Medium", "subcategory": "Security", @@ -2220,8 +2220,8 @@ "id": "J04.02", "link": "3rd-Party tools", "services": [ - "VM", "Storage", + "VM", "AVS" ], "severity": "Medium", @@ -2237,8 +2237,8 @@ "id": "J04.03", "link": "Contact VMware", "services": [ - "VM", "Storage", + "VM", "AVS" ], "severity": "Medium", @@ -2286,10 +2286,10 @@ "id": "J04.06", "link": "https://learn.microsoft.com/azure/azure-vmware/concepts-storage#storage-policies-and-fault-tolerance", "services": [ - "VM", "Storage", - "AVS", - "AzurePolicy" + "AzurePolicy", + "VM", + "AVS" ], "severity": "Medium", "subcategory": "Storage", @@ -2304,8 +2304,8 @@ "id": "J04.07", "link": "https://learn.microsoft.com/azure/azure-vmware/configure-storage-policy", "services": [ - "VM", "Storage", + "VM", "AVS", "AzurePolicy" ], @@ -2323,8 +2323,8 @@ "link": "https://learn.microsoft.com/azure/azure-vmware/concepts-storage#storage-policies-and-fault-tolerance", "services": [ "Storage", - "AVS", - "AzurePolicy" + "AzurePolicy", + "AVS" ], "severity": "Medium", "subcategory": "Storage", @@ -2366,9 +2366,9 @@ "guid": "fbcb40ac-9480-4a6d-bcf4-8081252a6716", "link": "https://learn.microsoft.com/azure/architecture/web-apps/spring-apps/architectures/spring-apps-multi-region", "services": [ - "TrafficManager", "ASR", - "FrontDoor" + "FrontDoor", + "TrafficManager" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -2562,11 +2562,11 @@ "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", "services": [ "Subscriptions", - "WAF", "Firewall", - "Entra", + "DDoS", "VNet", - "DDoS" + "Entra", + "WAF" ], "severity": "Low", "subcategory": "DDoS", @@ -2592,8 +2592,8 @@ "id": "B03.01", "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -2607,8 +2607,8 @@ "id": "B03.02", "link": "https://learn.microsoft.com/azure/openshift/howto-secure-openshift-with-front-door", "services": [ - "FrontDoor", - "PrivateLink" + "PrivateLink", + "FrontDoor" ], "severity": "Medium", "subcategory": "Internet", @@ -2623,8 +2623,8 @@ "link": "https://learn.microsoft.com/azure/openshift/howto-restrict-egress", "services": [ "Firewall", - "NVA", - "AzurePolicy" + "AzurePolicy", + "NVA" ], "severity": "Medium", "subcategory": "Internet", @@ -3019,8 +3019,8 @@ "link": "https://learn.microsoft.com/azure/azure-arc/kubernetes/tutorial-akv-secrets-provider", "services": [ "AKS", - "Arc", - "AKV" + "AKV", + "Arc" ], "severity": "Medium", "subcategory": "Secrets", @@ -3046,8 +3046,8 @@ "id": "E05.02", "link": "https://learn.microsoft.com/azure/governance/policy/concepts/policy-for-kubernetes#install-azure-policy-extension-for-azure-arc-enabled-kubernetes", "services": [ - "Monitor", - "AzurePolicy" + "AzurePolicy", + "Monitor" ], "severity": "Medium", "subcategory": "Workload", @@ -3126,11 +3126,11 @@ "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-sas#shared-access-authorization-policies", "service": "Service Bus", "services": [ - "TrafficManager", + "ServiceBus", + "AzurePolicy", "RBAC", "Entra", - "ServiceBus", - "AzurePolicy" + "TrafficManager" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -3147,12 +3147,12 @@ "link": "https://learn.microsoft.com/azure/service-bus-messaging/service-bus-managed-service-identity", "service": "Service Bus", "services": [ - "AppSvc", + "AKV", "Storage", - "VM", + "AppSvc", + "ServiceBus", "Entra", - "AKV", - "ServiceBus" + "VM" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -3169,11 +3169,11 @@ "link": "https://learn.microsoft.com/azure/service-bus-messaging/authenticate-application#azure-built-in-roles-for-azure-service-bus", "service": "Service Bus", "services": [ + "Subscriptions", "Storage", - "RBAC", - "Entra", "ServiceBus", - "Subscriptions" + "RBAC", + "Entra" ], "severity": "High", "subcategory": "Identity and Access Management", @@ -3190,9 +3190,9 @@ "link": "https://learn.microsoft.com/azure/service-bus-messaging/monitor-service-bus-reference", "service": "Service Bus", "services": [ - "Monitor", "ServiceBus", - "VNet" + "VNet", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -3209,8 +3209,8 @@ "link": "https://learn.microsoft.com/azure/service-bus-messaging/private-link-service", "service": "Service Bus", "services": [ - "ServiceBus", "PrivateLink", + "ServiceBus", "VNet" ], "severity": "Medium", @@ -3370,8 +3370,8 @@ "link": "https://learn.microsoft.com/azure/app-service/operating-system-functionality#file-access", "service": "App Services", "services": [ - "TrafficManager", - "AppSvc" + "AppSvc", + "TrafficManager" ], "severity": "Medium", "subcategory": "Data Protection", @@ -3471,9 +3471,9 @@ "link": "https://learn.microsoft.com/azure/app-service/troubleshoot-diagnostic-logs", "service": "App Services", "services": [ - "Monitor", "AppSvc", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Logging and Monitoring", @@ -3489,9 +3489,9 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log", "service": "App Services", "services": [ - "Monitor", "AppSvc", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Logging and Monitoring", @@ -3507,10 +3507,10 @@ "link": "https://learn.microsoft.com/azure/app-service/overview-vnet-integration", "service": "App Services", "services": [ - "Monitor", "Firewall", "NVA", - "VNet" + "VNet", + "Monitor" ], "severity": "Medium", "subcategory": "Network Security", @@ -3526,11 +3526,11 @@ "link": "https://learn.microsoft.com/azure/app-service/networking/nat-gateway-integration", "service": "App Services", "services": [ - "NVA", - "Storage", - "PrivateLink", "Firewall", - "VNet" + "Storage", + "VNet", + "NVA", + "PrivateLink" ], "severity": "Low", "subcategory": "Network Security", @@ -3546,8 +3546,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", @@ -3563,11 +3563,11 @@ "link": "https://learn.microsoft.com/azure/app-service/networking/app-gateway-with-service-endpoints", "service": "App Services", "services": [ + "Monitor", "AppSvc", + "AppGW", "WAF", - "Monitor", - "FrontDoor", - "AppGW" + "FrontDoor" ], "severity": "High", "subcategory": "Network Security", @@ -3583,8 +3583,8 @@ "link": "https://learn.microsoft.com/azure/app-service/networking-features#access-restrictions", "service": "App Services", "services": [ - "WAF", - "PrivateLink" + "PrivateLink", + "WAF" ], "severity": "High", "subcategory": "Network Security", @@ -3619,8 +3619,8 @@ "link": "https://learn.microsoft.com/azure/app-service/configure-ssl-bindings#enforce-https", "service": "App Services", "services": [ - "WAF", - "AppSvc" + "AppSvc", + "WAF" ], "severity": "High", "subcategory": "Network Security", @@ -3685,11 +3685,11 @@ "service": "App Services", "services": [ "EventHubs", - "NVA", - "WAF", + "DDoS", "VNet", + "NVA", "AppGW", - "DDoS" + "WAF" ], "severity": "Medium", "subcategory": "Network Security", @@ -3706,8 +3706,8 @@ "service": "App Services", "services": [ "ACR", - "VNet", - "PrivateLink" + "PrivateLink", + "VNet" ], "severity": "Medium", "subcategory": "Network Security", @@ -3764,8 +3764,8 @@ "id": "A01.01", "link": "https://learn.microsoft.com/sql/dma/dma-sku-recommend-sql-db?view=sql-server-ver16", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "High", "subcategory": "VM Size", @@ -3780,8 +3780,8 @@ "id": "A01.02", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-vm-size?view=azuresql#memory-optimized", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "Medium", "subcategory": "VM Size", @@ -3796,8 +3796,8 @@ "id": "A02.01", "link": "https://learn.microsoft.com/azure/virtual-machines/premium-storage-performance#counters-to-measure-application-performance-requirements", "services": [ - "VM", "SQL", + "VM", "Storage" ], "severity": "Medium", @@ -3845,8 +3845,8 @@ "id": "A02.04", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql#storage", "services": [ - "SQL", "Cost", + "SQL", "Storage" ], "severity": "High", @@ -3862,8 +3862,8 @@ "id": "A02.05", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql#storage", "services": [ - "VM", "SQL", + "VM", "Storage" ], "severity": "Medium", @@ -3879,8 +3879,8 @@ "id": "A02.06", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql#storage", "services": [ - "VM", "SQL", + "VM", "Storage" ], "severity": "High", @@ -3897,8 +3897,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql#storage", "services": [ "SQL", - "Storage", - "AzurePolicy" + "AzurePolicy", + "Storage" ], "severity": "High", "subcategory": "Storage", @@ -3913,8 +3913,8 @@ "id": "A02.08", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql#storage", "services": [ - "VM", "SQL", + "VM", "Storage" ], "severity": "High", @@ -3946,8 +3946,8 @@ "id": "A03.01", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/business-continuity-high-availability-disaster-recovery-hadr-overview?view=azuresql#azure-only-disaster-recovery-solutions", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "Medium", "subcategory": "HADR", @@ -3962,8 +3962,8 @@ "id": "A03.02", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/business-continuity-high-availability-disaster-recovery-hadr-overview?view=azuresql#high-availability-nodes-in-an-availability-set", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "High", "subcategory": "HADR", @@ -3978,10 +3978,10 @@ "id": "A03.03", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/availability-group-azure-portal-configure?view=azuresql&tabs=azure-cli", "services": [ - "VM", "SQL", - "VNet", - "LoadBalancer" + "LoadBalancer", + "VM", + "VNet" ], "severity": "Medium", "subcategory": "HADR", @@ -4027,10 +4027,10 @@ "id": "A03.06", "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", - "VNet", - "LoadBalancer" + "LoadBalancer", + "VM", + "VNet" ], "severity": "High", "subcategory": "HADR", @@ -4092,8 +4092,8 @@ "id": "A04.04", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/performance-guidelines-best-practices-checklist?view=azuresql-vm#sql-server-features", "services": [ - "VM", "SQL", + "VM", "Storage" ], "severity": "Low", @@ -4109,8 +4109,8 @@ "id": "A04.05", "link": "https://learn.microsoft.com/sql/database-engine/configure-windows/server-memory-server-configuration-options#use-", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "High", "subcategory": "SQL Server", @@ -4125,8 +4125,8 @@ "id": "A04.06", "link": "https://learn.microsoft.com/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "High", "subcategory": "SQL Server", @@ -4141,8 +4141,8 @@ "id": "A04.07", "link": "https://learn.microsoft.com/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "Low", "subcategory": "SQL Server", @@ -4157,8 +4157,8 @@ "id": "A04.08", "link": "https://learn.microsoft.com/sql/relational-databases/databases/tempdb-database#optimizing-tempdb-performance-in-sql-server", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "High", "subcategory": "SQL Server", @@ -4173,8 +4173,8 @@ "id": "A04.09", "link": "https://docs.microsoft.com/azure/governance/management-groups/how-to/protect-resource-hierarchy#setting---require-authorization", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "High", "subcategory": "SQL Server", @@ -4189,8 +4189,8 @@ "id": "A04.10", "link": "https://docs.microsoft.com/azure/governance/management-groups/how-to/protect-resource-hierarchy#setting---require-authorization", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "Medium", "subcategory": "SQL Server", @@ -4205,9 +4205,9 @@ "id": "A05.01", "link": "https://learn.microsoft.com/azure/virtual-machines/constrained-vcpu", "services": [ - "VM", - "SQL", "Cost", + "SQL", + "VM", "Storage" ], "severity": "Low", @@ -4224,8 +4224,8 @@ "id": "A05.02", "link": "https://azure.microsoft.com/en-ca/pricing/hybrid-benefit/", "services": [ - "SQL", - "Cost" + "Cost", + "SQL" ], "severity": "Low", "subcategory": "Cost Optimization", @@ -4240,8 +4240,8 @@ "id": "A06.01", "link": "https://learn.microsoft.com/azure/azure-sql/virtual-machines/windows/sql-agent-extension-automatic-registration-all-vms?view=azuresql-vm&tabs=azure-cli", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "Medium", "subcategory": "Azure", @@ -4257,8 +4257,8 @@ "id": "A06.02", "link": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview?tabs=redhat", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "High", "subcategory": "Azure", @@ -4273,8 +4273,8 @@ "id": "A06.03", "link": "https://learn.microsoft.com/azure/defender-for-cloud/secure-score-security-controls", "services": [ - "VM", "SQL", + "VM", "Defender" ], "severity": "High", @@ -4550,8 +4550,8 @@ "id": "B04.03", "link": "https://learn.microsoft.com/azure/azure-sql/managed-instance/tde-certificate-migrate?view=azuresql-mi&tabs=azure-powershell", "services": [ - "VM", - "SQL" + "SQL", + "VM" ], "severity": "Medium", "subcategory": "Deployment", @@ -4628,8 +4628,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": [ "SQL", - "EventHubs", - "LoadBalancer" + "LoadBalancer", + "EventHubs" ], "severity": "High", "subcategory": "Post Migration", @@ -4662,9 +4662,9 @@ "link": "https://learn.microsoft.com/azure/architecture/example-scenario/data/sql-managed-instance-cmk", "services": [ "SQL", + "AzurePolicy", "Backup", - "AKV", - "AzurePolicy" + "AKV" ], "severity": "Low", "subcategory": "Post Migration", @@ -4697,9 +4697,9 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/long-term-retention-overview?view=azuresql-mi", "services": [ "SQL", + "Backup", "ARS", - "Storage", - "Backup" + "Storage" ], "severity": "Low", "subcategory": "Post Migration", @@ -4715,8 +4715,8 @@ "id": "B06.07", "link": "https://azure.microsoft.com/en-gb/pricing/hybrid-benefit/#overview", "services": [ - "SQL", - "Cost" + "Cost", + "SQL" ], "severity": "Low", "subcategory": "Post Migration", @@ -4744,158 +4744,304 @@ { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "aff6691b-4935-4ada-9222-3ece81b12318", - "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-reports", + "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", + "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "services": [ - "ASR" + "ASR", + "VM", + "Entra" ], "severity": "Medium", "subcategory": " ", - "text": "Do not combine ASCS and Database cluster on to single/same VM" + "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." }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export?tabs=portal", + "guid": "cca275fa-a1ab-4fe9-b55d-04c3c4919cb1", + "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response", "services": [ "ASR", "LoadBalancer" ], "severity": "Medium", "subcategory": " ", - "text": "Make sure the Floating IP is enabled on the Load balancer" + "text": "Use a Standard Load Balancer SKU in front of ASCS and DB clusters" }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "cbe05bbe-209d-4490-ba47-778424d11678", - "link": "https://learn.microsoft.com/azure/security-center/", + "guid": "b3d1325a-e124-4ba3-9df6-85eddce9bd3b", + "link": "https://www.microsoft.com/itshowcase/implementing-a-zero-trust-security-model-at-microsoft", "services": [ - "VM", - "RBAC", + "Storage", "ASR", - "Entra" + "VM" ], "severity": "Medium", "subcategory": " ", - "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" + "text": "Both VMs in the HA pair should be deployed in an availability set, or Availability Zones should be the same size and have the same storage configuration" }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", - "link": "https://learn.microsoft.com/azure/security-center/", + "guid": "b0cdb3b5-5eb2-4ec1-9eea-a3592829e2ed", + "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response", "services": [ - "SAP", - "ACR", "ASR" ], "severity": "Medium", "subcategory": " ", - "text": "Use one proximity placement group per SAP SID. Groups don't span across Availability Zones or Azure regions" + "text": "Native database replication technology should be used to synchronize the database in a HA pair." }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", + "guid": "b2173676-aff6-4691-a493-5ada42223ece", + "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response", "services": [ - "VM", "ASR", - "Entra" + "SAP" ], "severity": "Medium", "subcategory": " ", - "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." + "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" }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "cca275fa-a1ab-4fe9-b55d-04c3c4919cb1", - "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response", + "guid": "81b12318-1a54-4174-8583-3fb4ae3c2df7", "services": [ "ASR", - "LoadBalancer" + "VNet" ], "severity": "Medium", "subcategory": " ", - "text": "Use a Standard Load Balancer SKU in front of ASCS and DB clusters" + "text": "The CIDR for the primary virtual network (VNet) shouldn't conflict or overlap with the CIDR of the DR site's Vnet" }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "b3d1325a-e124-4ba3-9df6-85eddce9bd3b", - "link": "https://www.microsoft.com/itshowcase/implementing-a-zero-trust-security-model-at-microsoft", + "guid": "43165c3a-cbe0-45bb-b209-d490da477784", "services": [ - "VM", "ASR", - "Storage" + "VM", + "Entra" ], "severity": "Medium", "subcategory": " ", - "text": "Both VMs in the HA pair should be deployed in an availability set, or Availability Zones should be the same size and have the same storage configuration" + "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)." }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "b0cdb3b5-5eb2-4ec1-9eea-a3592829e2ed", - "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response", + "guid": "24d11678-5d2f-4a56-a56a-d48408fe7273", "services": [ "ASR" ], "severity": "Medium", "subcategory": " ", - "text": "Native database replication technology should be used to synchronize the database in a HA pair." + "text": "Native database replication should be used to synchronize data to the DR site, rather than Azure Site Recovery" }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "b2173676-aff6-4691-a493-5ada42223ece", - "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response", + "guid": "8300cb30-766b-4084-b126-0dd8fb1269a1", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-architecture-scenario", + "services": [ + "ASR", + "SAP" + ], + "severity": "High", + "subcategory": "High availability", + "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" + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "56402f11-ccbe-42c3-a2f6-c6f6f38ab579", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-supported-configurations", + "services": [ + "ASR", + "SAP" + ], + "severity": "High", + "subcategory": "High availability", + "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" + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "afae6bec-2671-49ae-bc69-140b8ec8d320", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", + "services": [ + "Storage", + "ASR", + "VM" + ], + "severity": "High", + "subcategory": "High availability", + "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" + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "ac614e95-6767-4bc3-b8a4-9953533da6ba", + "link": "https://learn.microsoft.com/azure/sap/workloads/dbms-guide-general", + "services": [ + "Storage", + "ASR", + "SAP" + ], + "severity": "High", + "subcategory": "High availability", + "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" + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "1f737179-8e7f-4e1a-a30c-e5a649a3092b", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-wsfc-shared-disk", + "services": [ + "ASR", + "SAP" + ], + "severity": "High", + "subcategory": "High availability", + "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" + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "a78b3d31-3170-44f2-b5d7-651a29f4ccf5", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-standard-load-balancer-outbound-connections", "services": [ + "ASR", "SAP", - "ASR" + "LoadBalancer" ], - "severity": "Medium", - "subcategory": " ", - "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" + "severity": "High", + "subcategory": "High availability", + "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" }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "81b12318-1a54-4174-8583-3fb4ae3c2df7", + "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-ha-ports-overview?source=recommendations", "services": [ "ASR", - "VNet" + "LoadBalancer" ], - "severity": "Medium", - "subcategory": " ", - "text": "The CIDR for the primary virtual network (VNet) shouldn't conflict or overlap with the CIDR of the DR site's Vnet" + "severity": "High", + "subcategory": "High availability", + "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" }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "43165c3a-cbe0-45bb-b209-d490da477784", + "guid": "c47cc4f3-f105-452c-845e-9b307b3856c1", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "services": [ + "ASR" + ], + "severity": "High", + "subcategory": "High availability", + "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" + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "844f69c3-07e5-4ec1-bff7-4be27bcf5fea", + "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", "services": [ + "ASR", "VM", + "Entra", + "SAP" + ], + "severity": "High", + "subcategory": "High availability", + "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." + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "cbe05bbe-209d-4490-ba47-778424d11678", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "services": [ + "RBAC", "ASR", + "VM", "Entra" ], - "severity": "Medium", - "subcategory": " ", - "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)." + "severity": "High", + "subcategory": "High availability", + "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" }, { "category": "Business Continuity and Disaster Recovery", "checklist": "Azure Landing Zone Review", - "guid": "24d11678-5d2f-4a56-a56a-d48408fe7273", + "guid": "f2201000-d045-40a6-a79a-d7cdc01b4d86", + "link": "https://learn.microsoft.com/azure/virtual-machines/co-location", "services": [ "ASR" ], "severity": "Medium", - "subcategory": " ", - "text": "Native database replication should be used to synchronize data to the DR site, rather than Azure Site Recovery" + "subcategory": "High availability", + "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" + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "9674e7c7-7796-4181-8920-09f4429543ba", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "services": [ + "ASR", + "VM" + ], + "severity": "High", + "subcategory": "High availability", + "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" + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "ae4ecb95-b70f-428f-8b9a-4c5b7e3478a2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "services": [ + "ASR", + "Entra", + "SAP" + ], + "severity": "High", + "subcategory": "High availability", + "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." + }, + { + "category": "Business Continuity and Disaster Recovery", + "checklist": "Azure Landing Zone Review", + "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "services": [ + "ACR", + "ASR", + "SAP" + ], + "severity": "High", + "subcategory": "High availability", + "text": "Use one proximity placement group per SAP SID. Groups don't span across Availability Zones or Azure regions" }, { "category": "Compute", @@ -4929,8 +5075,8 @@ "guid": "45911475-e39e-4530-accc-d979366bcda2", "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/scenario-azure-first-sap-identity-integration", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -4943,8 +5089,8 @@ "guid": "750ab1ab-039d-495d-94c7-c8929cb107d5", "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/scenario-azure-first-sap-identity-integration", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -4956,8 +5102,8 @@ "guid": "325ae525-ba34-4d46-a5e2-213ace7bb122", "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -4969,8 +5115,8 @@ "checklist": "Azure Landing Zone Review", "guid": "9eb54dad-7861-4e1c-973a-f3bb003fc9c1", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -4983,8 +5129,8 @@ "guid": "f29676ef-0c9c-4c4d-ab21-a55504c0c829", "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -5025,8 +5171,8 @@ "guid": "16785d6f-a96c-496a-b885-18f482734c88", "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial#configure-sap-netweaver-for-oauth", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -5038,8 +5184,8 @@ "guid": "a747c350-8d4c-449c-93af-393dbca77c48", "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/saphana-tutorial", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -5051,8 +5197,8 @@ "guid": "c7bae5bf-daf9-4761-9c56-f92891890aa4", "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration#connectivity-with-sap-rise", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -5064,8 +5210,8 @@ "guid": "e4e48226-ce54-44b6-bb6b-bfa15bd8f753", "link": "https://github.com/azuredevcollege/SAP/blob/master/sap-oauth-saml-flow/README.md", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -5077,8 +5223,8 @@ "guid": "59921095-4980-4fc1-a5b6-524a5a560c79", "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-hana-cloud-platform-identity-authentication-tutorial", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -5090,8 +5236,8 @@ "guid": "a709c664-317e-41e4-9e34-67d9016a86f4", "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-hana-cloud-platform-tutorial", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -5103,8 +5249,8 @@ "guid": "01f11b7f-38df-4251-9c76-4dec19abd3e8", "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-successfactors-inbound-provisioning-cloud-only-tutorial", "services": [ - "SAP", - "Entra" + "Entra", + "SAP" ], "severity": "Medium", "subcategory": "Identity", @@ -5116,9 +5262,9 @@ "guid": "6ba28021-4591-4147-9e39-e5309cccd979", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups", "services": [ - "SAP", + "AzurePolicy", "Subscriptions", - "AzurePolicy" + "SAP" ], "severity": "Medium", "subcategory": "Subscriptions", @@ -5131,8 +5277,8 @@ "guid": "366bcda2-750a-4b1a-a039-d95d54c7c892", "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", "services": [ - "SAP", - "Subscriptions" + "Subscriptions", + "SAP" ], "severity": "High", "subcategory": "Subscriptions", @@ -5210,8 +5356,8 @@ "guid": "4e138115-2318-41aa-9174-26943ff8ae7d", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-resource-organization", "services": [ - "TrafficManager", "Cost", + "TrafficManager", "Subscriptions" ], "severity": "Medium", @@ -5225,8 +5371,8 @@ "guid": "2f7c95f0-6e15-44e3-aa35-92829e6e2061", "link": "https://learn.microsoft.com/azure/backup/sap-hana-database-about", "services": [ - "Monitor", - "Backup" + "Backup", + "Monitor" ], "severity": "High", "subcategory": "BCDR", @@ -5239,8 +5385,8 @@ "guid": "302a2fbf-3745-4a5f-a365-c9d1a16ca22c", "link": "https://learn.microsoft.com/azure/azure-netapp-files/azacsnap-introduction", "services": [ - "VM", "Storage", + "VM", "Entra", "Monitor" ], @@ -5267,8 +5413,8 @@ "guid": "c3c7abc0-716c-4486-893c-40e181d65539", "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel-multi-sid", "services": [ - "Monitor", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -5281,8 +5427,8 @@ "guid": "a491dfc4-9353-4213-9217-eef0949f9467", "link": "https://azure.microsoft.com/pricing/offers/dev-test/", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "severity": "Low", "subcategory": "Management", @@ -5294,8 +5440,8 @@ "guid": "b7056168-6199-4732-a514-cdbb2d5c9c54", "link": "https://learn.microsoft.com/azure/lighthouse/overview", "services": [ - "SAP", "Entra", + "SAP", "Monitor" ], "severity": "Medium", @@ -5336,8 +5482,8 @@ "guid": "14591147-5e39-4e53-89cc-cd979366bcda", "link": "https://learn.microsoft.com/azure/sap/monitor/about-azure-monitor-sap-solutions", "services": [ - "SAP", "SQL", + "SAP", "Monitor" ], "severity": "Medium", @@ -5351,9 +5497,9 @@ "guid": "2750ab1a-b039-4d95-b54c-7c8929cb107d", "link": "https://learn.microsoft.com/azure/sap/workloads/vm-extension-for-sap", "services": [ - "SAP", "VM", "Entra", + "SAP", "Monitor" ], "severity": "High", @@ -5367,8 +5513,8 @@ "guid": "5325ae52-5ba3-44d4-985e-2213ace7bb12", "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "services": [ - "Monitor", - "AzurePolicy" + "AzurePolicy", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -5381,8 +5527,8 @@ "guid": "523181aa-4174-4269-93ff-8ae7d7d47431", "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-overview", "services": [ - "SAP", "NetworkWatcher", + "SAP", "Monitor" ], "severity": "Medium", @@ -5396,8 +5542,8 @@ "guid": "d89fd98d-23e4-4b40-a92e-32db9365522c", "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-monitor-and-troubleshoot", "services": [ - "SAP", "ASR", + "SAP", "Monitor" ], "severity": "High", @@ -5411,8 +5557,8 @@ "guid": "73686af4-6791-4f89-95ad-a43324e13811", "link": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/QualityCheck", "services": [ - "SAP", "VM", + "SAP", "Monitor" ], "severity": "Medium", @@ -5425,9 +5571,9 @@ "guid": "616785d6-fa96-4c96-ad88-518f482734c8", "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-zones", "services": [ + "Subscriptions", "SAP", - "Monitor", - "Subscriptions" + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -5440,9 +5586,9 @@ "guid": "410adcba-db46-424f-a6c4-05ecde75c52e", "link": "https://learn.microsoft.com/azure/advisor/advisor-how-to-improve-reliability", "services": [ - "Monitor", + "Storage", "ASR", - "Storage" + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -5455,8 +5601,8 @@ "guid": "86ba2802-1459-4114-95e3-9e5309cccd97", "link": "https://learn.microsoft.com/azure/sentinel/sap/deployment-overview", "services": [ - "SAP", "Sentinel", + "SAP", "Monitor" ], "severity": "Medium", @@ -5470,8 +5616,8 @@ "guid": "579266bc-ca27-45fa-a1ab-fe9d55d04c3c", "link": "https://learn.microsoft.com/azure/cost-management-billing/costs/enable-tag-inheritance", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -5497,8 +5643,8 @@ "guid": "07e5ed53-3d96-43d8-87ea-631b77da5aba", "link": "https://learn.microsoft.com/azure/sap/workloads/planning-guide-storage", "services": [ - "SAP", "ASR", + "SAP", "Monitor" ], "severity": "Medium", @@ -5512,8 +5658,8 @@ "guid": "abb6af9c-982c-4cf1-83fb-329fafd1ee56", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-management-and-monitoring", "services": [ - "SAP", "Storage", + "SAP", "Monitor" ], "severity": "Medium", @@ -5539,8 +5685,8 @@ "guid": "fdafb1f5-3eee-4354-a8c9-deb8127ebc2e", "link": "https://learn.microsoft.com/azure/virtual-machines/workloads/oracle/configure-oracle-asm", "services": [ - "SAP", "Storage", + "SAP", "Monitor" ], "severity": "Medium", @@ -5554,8 +5700,8 @@ "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", "services": [ - "SAP", "SQL", + "SAP", "Monitor" ], "severity": "Medium", @@ -5569,9 +5715,9 @@ "guid": "5ba34d46-85e2-4213-ace7-bb122f7c95f0", "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", "services": [ - "WAF", "AppGW", - "AzurePolicy" + "AzurePolicy", + "WAF" ], "severity": "Medium", "subcategory": "App delivery", @@ -5584,9 +5730,9 @@ "guid": "fa9d30bc-1b82-4e4b-bfdf-6b017938b9e6", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", "services": [ - "SAP", "DNS", - "VM" + "VM", + "SAP" ], "severity": "Medium", "subcategory": "DNS", @@ -5599,8 +5745,8 @@ "guid": "a2858f78-105b-4f52-b7a9-5b0f4439743b", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", "services": [ - "SAP", "DNS", + "SAP", "VNet" ], "severity": "Medium", @@ -5614,8 +5760,8 @@ "guid": "a3592829-e6e2-4061-9368-6af46791f893", "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-peering-overview", "services": [ - "SAP", "ACR", + "SAP", "VNet" ], "severity": "Medium", @@ -5643,8 +5789,8 @@ "guid": "7d4bc7d2-c34a-452e-8f1d-6ae3c8eafcc3", "link": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/?source=recommendations", "services": [ - "SAP", "ACR", + "SAP", "VWAN" ], "severity": "Medium", @@ -5658,8 +5804,8 @@ "guid": "0cedb1f6-ae6c-492b-8b17-8061f50b16d3", "link": "https://learn.microsoft.com/azure/well-architected/services/networking/network-virtual-appliances/reliability", "services": [ - "NVA", - "VNet" + "VNet", + "NVA" ], "severity": "Medium", "subcategory": "Hybrid", @@ -5688,9 +5834,9 @@ "guid": "82734c88-6ba2-4802-8459-11475e39e530", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing", "services": [ - "SAP", + "VNet", "VM", - "VNet" + "SAP" ], "severity": "High", "subcategory": "IP plan", @@ -5757,9 +5903,9 @@ "guid": "91a65e40-be90-45b3-9f73-f3edbf8dc324", "link": "https://learn.microsoft.com/azure/sap/workloads/expose-sap-process-orchestration-on-azure", "services": [ + "AppGW", "SAP", - "WAF", - "AppGW" + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -5772,10 +5918,10 @@ "guid": "5e39e530-9ccc-4d97-a366-bcda2750ab1a", "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "services": [ - "WAF", "ACR", "FrontDoor", - "AzurePolicy" + "AzurePolicy", + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -5788,10 +5934,10 @@ "guid": "b039d95d-54c7-4c89-89cb-107d5325ae52", "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", "services": [ - "WAF", - "FrontDoor", "AppGW", - "AzurePolicy" + "WAF", + "AzurePolicy", + "FrontDoor" ], "severity": "Medium", "subcategory": "Internet", @@ -5804,9 +5950,9 @@ "guid": "5ada4332-4e13-4811-9231-81aa41742694", "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "services": [ - "WAF", "AppGW", - "LoadBalancer" + "LoadBalancer", + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -5819,8 +5965,8 @@ "guid": "e73de7d5-6f36-4217-a526-e1a621ecddde", "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", "services": [ - "SAP", "ACR", + "SAP", "VWAN" ], "severity": "Medium", @@ -5834,11 +5980,11 @@ "guid": "3c536a3e-1b6b-4e87-95ca-15edb47251c0", "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", "services": [ - "Storage", - "PrivateLink", + "Backup", "ACR", + "Storage", "VNet", - "Backup" + "PrivateLink" ], "severity": "Medium", "subcategory": "Internet", @@ -5851,8 +5997,8 @@ "guid": "85e2213a-ce7b-4b12-8f7c-95f06e154e3a", "link": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview?tabs=redhat", "services": [ - "SAP", - "VM" + "VM", + "SAP" ], "severity": "High", "subcategory": "Segmentation", @@ -5933,8 +6079,8 @@ "guid": "b65c878b-4b14-4f4e-92d8-d873936493f2", "link": "https://me.sap.com/notes/2015553", "services": [ - "SAP", "Cost", + "SAP", "VNet" ], "severity": "High", @@ -5948,8 +6094,8 @@ "guid": "85e2213a-ce7b-4b12-8f7c-95f06e154e3a", "link": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview?tabs=redhat", "services": [ - "SAP", - "VM" + "VM", + "SAP" ], "severity": "High", "subcategory": "Segmentation", @@ -5985,77 +6131,85 @@ { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "209d490d-a477-4784-84d1-16785d2fa56c", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "18dffcf3-248c-4039-a67c-dec8e3a5f804", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", "services": [ - "SAP", - "RBAC", - "Subscriptions" + "VM" ], - "severity": "High", + "severity": "Medium", "subcategory": "Governance", - "text": "Customize role-based access control (RBAC) roles for SAP on Azure spoke subscriptions to avoid accidental network-related changes" + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "08951710-79a2-492a-adbc-06d7a401545b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", "services": [ - "SAP", - "NVA", - "PrivateLink" + "SAP" ], "severity": "Medium", "subcategory": "Governance", - "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" + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "1b8b394e-ae64-4a74-8933-357b523ea0a0", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", "services": [ - "SAP", "SQL", - "Storage", - "Backup" + "SAP" ], - "severity": "Medium", + "severity": "Low", "subcategory": "Governance", - "text": "For SAP database server encryption, use the SAP HANA native encryption technology. If you're using Azure SQL Database, use Transparent Data Encryption (TDE) offered by the DBMS provider to secure your data and log files, and ensure the backups are also encrypted." + "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." }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "5a76a033-ced9-4eef-9a43-5e4f96634c8e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", "services": [ - "Storage" + "SQL" ], - "severity": "Medium", + "severity": "High", "subcategory": "Governance", - "text": "Azure Storage encryption is enabled by default" + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "services": [], - "severity": "Medium", - "subcategory": "Governance", - "text": " " + "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "services": [ + "Backup", + "AKV", + "Storage", + "SQL", + "SAP" + ], + "severity": "High", + "subcategory": "Secrets", + "text": "Encrypting SAP HANA database servers on Azrue 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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "services": [], + "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", + "services": [ + "Storage", + "AKV" + ], "severity": "Medium", - "subcategory": "Governance", - "text": " " + "subcategory": "Secrets", + "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" }, { "category": "Security, Governance and Compliance", @@ -6067,151 +6221,251 @@ ], "severity": "High", "subcategory": "Secrets", - "text": "Use Azure Key Vault to store your secrets and credentials" + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", "guid": "829e2edb-2173-4676-aff6-691b4935ada4", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview-throttling", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", "services": [ + "RBAC", + "AzurePolicy", + "Subscriptions", "AKV" ], "severity": "Medium", "subcategory": "Secrets", - "text": "It is recommended to LOCK the Azure Resources post successful deployment to safeguard against unauthorized changes" + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", "guid": "2223ece8-1b12-4318-8a54-17415833fb4a", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", "services": [ - "AKV", - "AzurePolicy" + "AzurePolicy", + "AKV" ], "severity": "Medium", "subcategory": "Secrets", - "text": "Provision Azure Key Vault with the soft delete and purge policies enabled to allow retention protection for deleted objects." + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", "guid": "e3c2df74-3165-4c3a-abe0-5bbe209d490d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", "services": [ "RBAC", - "AKV", - "AzurePolicy" + "AzurePolicy", + "AKV" ], - "severity": "Medium", + "severity": "High", "subcategory": "Secrets", - "text": "Based on existing requirements, regulatory and compliance controls (internal/external) - Determine what Azure Policies and Azure RBAC role are needed" + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", "guid": "a4777842-4d11-4678-9d2f-a56c56ad4840", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", "services": [ - "SAP", - "Defender", + "Storage", "AKV", - "AzurePolicy" + "Defender", + "SAP" ], - "severity": "Medium", + "severity": "High", "subcategory": "Secrets", - "text": "When you enable Microsoft Defender for Cloud Standard for SAP, make sure to exclude the SAP database servers from any policy that installs endpoint protection." + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", "guid": "8fe72734-c486-4ba2-a0dc-0591cf65de8e", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/just-in-time-access-overview?tabs=defender-for-container-arch-aks", "services": [ - "SAP", "RBAC", - "AKV" + "AKV", + "Defender", + "SAP" ], - "severity": "Medium", + "severity": "High", "subcategory": "Secrets", - "text": "Delegate an SAP admin custom role with just-in-time access." + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", "guid": "1309cccd-5792-466b-aca2-75faa1abfe9d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", "services": [ - "SAP", - "AKV" + "AKV", + "SAP" ], - "severity": "Medium", + "severity": "Low", "subcategory": "Secrets", - "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" + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "55d04c3c-4919-4cb1-a3d1-325ae124ba34", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", + "link": "https://learn.microsoft.com/azure/storage/common/storage-encryption-key-model-get?tabs=portal", "services": [ - "SAP", - "Entra", "AKV" ], "severity": "Medium", "subcategory": "Secrets", - "text": "Azure Active Directory (Azure AD) with SAML 2.0 can also provide SSO to a range of SAP applications and platforms like SAP NetWeaver, SAP HANA, and the SAP Cloud Platform" + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "df685edd-ce9b-4d3b-a0cd-b3b55eb2ec14", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "link": "https://learn.microsoft.com/ja-jp/azure/key-vault/general/best-practices", "services": [ - "SAP", "AKV" ], - "severity": "Medium", + "severity": "High", "subcategory": "Secrets", - "text": "Make sure you harden the operating system to eradicate vulnerabilities that could lead to attacks on the SAP database." + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "abc9634d-c44d-41e9-a530-e8444e16aa3c", + "link": "https://learn.microsoft.com/azure/key-vault/certificates/certificate-scenarios", "services": [ + "SAP", "AKV" ], - "severity": "Medium", + "severity": "High", "subcategory": "Secrets", - "text": "Default to Microsoft-managed keys for principal encryption functionality and use customer-managed keys when required." + "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" }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "services": [ "AKV" ], "severity": "Medium", "subcategory": "Secrets", - "text": "Use an Azure Key Vault per application per environment per region." + "text": " " }, { "category": "Security, Governance and Compliance", "checklist": "Azure Landing Zone Review", - "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "209d490d-a477-4784-84d1-16785d2fa56c", + "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles", "services": [ - "AKV" + "RBAC", + "Subscriptions", + "SAP" + ], + "severity": "High", + "subcategory": "Security", + "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" + }, + { + "category": "Security, Governance and Compliance", + "checklist": "Azure Landing Zone Review", + "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", + "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/", + "services": [ + "PrivateLink", + "SAP", + "NVA" + ], + "severity": "High", + "subcategory": "Security", + "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" + }, + { + "category": "Security, Governance and Compliance", + "checklist": "Azure Landing Zone Review", + "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", + "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", + "services": [ + "Storage", + "VM" + ], + "severity": "Low", + "subcategory": "Security", + "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/" + }, + { + "category": "Security, Governance and Compliance", + "checklist": "Azure Landing Zone Review", + "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", + "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", + "services": [ + "Defender" + ], + "severity": "Low", + "subcategory": "Security", + "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" + }, + { + "category": "Security, Governance and Compliance", + "checklist": "Azure Landing Zone Review", + "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "services": [ + "SAP", + "VNet" + ], + "severity": "High", + "subcategory": "Security", + "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" + }, + { + "category": "Security, Governance and Compliance", + "checklist": "Azure Landing Zone Review", + "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "services": [ + "SAP", + "WAF" + ], + "severity": "Low", + "subcategory": "Security", + "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" + }, + { + "category": "Security, Governance and Compliance", + "checklist": "Azure Landing Zone Review", + "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", + "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions", + "services": [ + "SAP", + "AKV", + "Monitor" ], "severity": "Medium", - "subcategory": "Secrets", - "text": " " + "subcategory": "Security", + "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" }, { "category": "Storage", @@ -6233,10 +6487,10 @@ "id": "A01.01", "link": "https://azure.microsoft.com/support/legal/sla/virtual-desktop/v1_0/", "services": [ - "VM", - "AVD", "ASR", - "Subscriptions" + "VM", + "Subscriptions", + "AVD" ], "severity": "High", "subcategory": "Compute", @@ -6251,10 +6505,10 @@ "id": "A01.02", "link": "https://learn.microsoft.com/azure/architecture/example-scenario/wvd/azure-virtual-desktop-multi-region-bcdr", "services": [ - "VM", - "AVD", + "Storage", "ASR", - "Storage" + "VM", + "AVD" ], "severity": "Medium", "subcategory": "Compute", @@ -6269,8 +6523,8 @@ "id": "A01.03", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ - "AVD", - "ASR" + "ASR", + "AVD" ], "severity": "Low", "subcategory": "Compute", @@ -6286,8 +6540,8 @@ "link": "https://techcommunity.microsoft.com/t5/azure-virtual-desktop-blog/announcing-general-availability-of-support-for-azure/ba-p/3636262", "services": [ "ACR", - "AVD", - "ASR" + "ASR", + "AVD" ], "severity": "High", "subcategory": "Compute", @@ -6302,10 +6556,10 @@ "id": "A01.05", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ - "VM", - "AVD", "ASR", - "Backup" + "VM", + "Backup", + "AVD" ], "severity": "Medium", "subcategory": "Compute", @@ -6320,11 +6574,11 @@ "id": "A01.06", "link": "https://learn.microsoft.com/azure/site-recovery/azure-to-azure-how-to-enable-zone-to-zone-disaster-recovery", "services": [ - "Cost", - "VM", + "Backup", "AVD", "ASR", - "Backup" + "Cost", + "VM" ], "severity": "Medium", "subcategory": "Compute", @@ -6339,11 +6593,11 @@ "id": "A02.01", "link": "https://learn.microsoft.com/azure/virtual-machines/azure-compute-gallery", "services": [ - "Storage", - "VM", "AVD", "ACR", - "ASR" + "Storage", + "ASR", + "VM" ], "severity": "Low", "subcategory": "Dependencies", @@ -6358,8 +6612,8 @@ "id": "A02.02", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ - "AVD", - "ASR" + "ASR", + "AVD" ], "severity": "Medium", "subcategory": "Dependencies", @@ -6374,9 +6628,9 @@ "id": "A03.01", "link": "https://docs.microsoft.com/fslogix/manage-profile-content-cncpt", "services": [ + "Storage", "ASR", - "AVD", - "Storage" + "AVD" ], "severity": "Medium", "subcategory": "Storage", @@ -6391,10 +6645,10 @@ "id": "A03.02", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ - "Storage", + "Backup", "AVD", + "Storage", "ASR", - "Backup", "AzurePolicy" ], "severity": "Medium", @@ -6410,9 +6664,9 @@ "id": "A03.03", "link": "https://docs.microsoft.com/azure/virtual-desktop/disaster-recovery", "services": [ + "Storage", "ASR", - "AVD", - "Storage" + "AVD" ], "severity": "Medium", "subcategory": "Storage", @@ -6427,10 +6681,10 @@ "id": "A03.04", "link": "https://docs.microsoft.com/azure/backup/backup-afs", "services": [ - "AVD", + "Storage", "ASR", "Backup", - "Storage" + "AVD" ], "severity": "Medium", "subcategory": "Storage", @@ -6445,9 +6699,9 @@ "id": "A03.05", "link": "https://learn.microsoft.com/azure/storage/files/files-redundancy#zone-redundant-storage", "services": [ + "Storage", "ASR", - "AVD", - "Storage" + "AVD" ], "severity": "High", "subcategory": "Storage", @@ -6462,11 +6716,11 @@ "id": "A03.06", "link": "https://learn.microsoft.com/azure/azure-netapp-files/cross-region-replication-create-peering", "services": [ - "Storage", + "Backup", "AVD", "ACR", - "ASR", - "Backup" + "Storage", + "ASR" ], "severity": "Medium", "subcategory": "Storage", @@ -6526,9 +6780,9 @@ "id": "B01.04", "link": "https://learn.microsoft.com/azure/virtual-machines/shared-image-galleries", "services": [ + "Storage", "VM", - "AVD", - "Storage" + "AVD" ], "severity": "Low", "subcategory": "Golden Images", @@ -6588,8 +6842,8 @@ "id": "B01.08", "link": "https://github.com/The-Virtual-Desktop-Team/Virtual-Desktop-Optimization-Tool", "services": [ - "AVD", - "RBAC" + "RBAC", + "AVD" ], "severity": "Low", "subcategory": "Golden Images", @@ -6604,8 +6858,8 @@ "id": "B01.09", "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", @@ -6650,9 +6904,9 @@ "id": "B02.01", "link": "https://docs.microsoft.com/azure/virtual-desktop/app-attach-file-share", "services": [ - "AVD", + "Cost", "Storage", - "Cost" + "AVD" ], "severity": "Medium", "subcategory": "MSIX & AppAttach", @@ -6682,10 +6936,10 @@ "id": "B02.03", "link": "https://docs.microsoft.com/azure/virtual-desktop/app-attach-file-share", "services": [ - "VM", - "AVD", "Storage", - "RBAC" + "RBAC", + "VM", + "AVD" ], "severity": "Medium", "subcategory": "MSIX & AppAttach", @@ -6854,8 +7108,8 @@ "id": "C01.06", "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", @@ -6871,8 +7125,8 @@ "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-virtual-desktop-service-limits", "services": [ "ACR", - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Capacity Planning", @@ -6902,9 +7156,9 @@ "id": "C01.09", "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", @@ -6935,8 +7189,8 @@ "id": "C01.11", "link": "https://learn.microsoft.com/azure/architecture/example-scenario/wvd/windows-virtual-desktop#considerations", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -6997,10 +7251,10 @@ "id": "C02.02", "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": [ + "Storage", "ExpressRoute", "VPN", - "AVD", - "Storage" + "AVD" ], "severity": "Medium", "subcategory": "Clients & Users", @@ -7090,9 +7344,9 @@ "id": "C03.03", "link": "https://docs.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits", "services": [ + "Storage", "VM", - "AVD", - "Storage" + "AVD" ], "severity": "Low", "subcategory": "General", @@ -7107,9 +7361,9 @@ "id": "D01.01", "link": "https://docs.microsoft.com/azure/architecture/reference-architectures/identity/adds-extend-domain", "services": [ - "AVD", "VNet", "Entra", + "AVD", "Storage" ], "severity": "Medium", @@ -7125,8 +7379,8 @@ "id": "D01.02", "link": "https://docs.microsoft.com/azure/virtual-desktop/create-host-pools-azure-marketplace", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Active Directory", @@ -7141,8 +7395,8 @@ "id": "D01.03", "link": "https://docs.microsoft.com/previous-versions/windows/desktop/Policy/group-policy-hierarchy", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Active Directory", @@ -7157,8 +7411,8 @@ "id": "D01.04", "link": "https://learn.microsoft.com/fslogix/how-to-use-group-policy-templates", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Active Directory", @@ -7174,8 +7428,8 @@ "link": "https://learn.microsoft.com/azure/virtual-desktop/prerequisites?tabs=portal#session-hosts", "services": [ "VM", - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Active Directory", @@ -7190,8 +7444,8 @@ "id": "D01.06", "link": "https://docs.microsoft.com/azure/virtual-desktop/manage-app-groups", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Active Directory", @@ -7206,10 +7460,10 @@ "id": "D01.07", "link": "https://docs.microsoft.com/azure/storage/files/storage-files-identity-ad-ds-enable", "services": [ - "AVD", "Storage", + "AzurePolicy", "Entra", - "AzurePolicy" + "AVD" ], "severity": "High", "subcategory": "Active Directory", @@ -7224,8 +7478,8 @@ "id": "D01.08", "link": "https://learn.microsoft.com/azure/virtual-desktop/prerequisites?tabs=portal#identity", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "High", "subcategory": "Active Directory", @@ -7240,9 +7494,9 @@ "id": "D02.01", "link": "https://learn.microsoft.com/azure/storage/files/storage-files-identity-auth-hybrid-identities-enable", "services": [ - "AVD", "Storage", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Microsoft Entra ID", @@ -7257,10 +7511,10 @@ "id": "D03.01", "link": "https://learn.microsoft.com/azure/virtual-desktop/prerequisites?tabs=portal#identity", "services": [ - "AVD", "VNet", "Entra", - "Subscriptions" + "Subscriptions", + "AVD" ], "severity": "High", "subcategory": "Requirements", @@ -7275,8 +7529,8 @@ "id": "D03.02", "link": "https://learn.microsoft.com/azure/virtual-desktop/authentication", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "High", "subcategory": "Requirements", @@ -7291,8 +7545,8 @@ "id": "D03.03", "link": "https://learn.microsoft.com/azure/virtual-desktop/prerequisites?tabs=portal#supported-identity-scenarios", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Requirements", @@ -7307,8 +7561,8 @@ "id": "D03.04", "link": "https://learn.microsoft.com/azure/virtual-desktop/authentication#single-sign-on-sso", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Requirements", @@ -7324,8 +7578,8 @@ "link": "https://learn.microsoft.com/azure/virtual-desktop/prerequisites?tabs=portal#supported-identity-scenarios", "services": [ "VM", - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "High", "subcategory": "Requirements", @@ -7340,8 +7594,8 @@ "id": "D03.06", "link": "https://docs.microsoft.com/azure/active-directory-domain-services/compare-identity-solutions", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Low", "subcategory": "Requirements", @@ -7356,9 +7610,9 @@ "id": "E01.01", "link": "https://learn.microsoft.com/azure/virtual-desktop/administrative-template", "services": [ - "Monitor", + "Entra", "AVD", - "Entra" + "Monitor" ], "severity": "Low", "subcategory": "Management", @@ -7373,9 +7627,9 @@ "id": "E01.02", "link": "https://learn.microsoft.com/azure/virtual-desktop/management", "services": [ - "Monitor", + "VM", "AVD", - "VM" + "Monitor" ], "severity": "Low", "subcategory": "Management", @@ -7390,8 +7644,8 @@ "id": "E01.03", "link": "https://learn.microsoft.com/mem/intune/fundamentals/azure-virtual-desktop", "services": [ - "Monitor", - "AVD" + "AVD", + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -7406,10 +7660,10 @@ "id": "E01.04", "link": "https://learn.microsoft.com/azure/virtual-desktop/autoscale-scenarios", "services": [ - "Monitor", - "AVD", + "Cost", "VM", - "Cost" + "AVD", + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -7424,9 +7678,9 @@ "id": "E01.05", "link": "https://learn.microsoft.com/azure/virtual-desktop/start-virtual-machine-connect", "services": [ + "Cost", "VM", "AVD", - "Cost", "Monitor" ], "severity": "Low", @@ -7442,11 +7696,11 @@ "id": "E01.06", "link": "https://learn.microsoft.com/azure/virtual-desktop/start-virtual-machine-connect-faq#are-vms-automatically-deallocated-when-a-user-stops-using-them", "services": [ - "Cost", - "VM", "AVD", "Monitor", - "AzurePolicy" + "AzurePolicy", + "Cost", + "VM" ], "severity": "Low", "subcategory": "Management", @@ -7461,13 +7715,13 @@ "id": "E01.07", "link": "https://learn.microsoft.com/azure/virtual-desktop/tag-virtual-desktop-resources", "services": [ - "VWAN", - "ExpressRoute", - "Storage", - "Cost", "AVD", "Monitor", + "Storage", "VPN", + "VWAN", + "ExpressRoute", + "Cost", "DNS" ], "severity": "Low", @@ -7483,10 +7737,10 @@ "id": "E01.08", "link": "https://learn.microsoft.com/azure/virtual-desktop/azure-advisor-recommendations", "services": [ - "Monitor", - "AVD", "Cost", - "Entra" + "Entra", + "AVD", + "Monitor" ], "severity": "Low", "subcategory": "Management", @@ -7501,8 +7755,8 @@ "id": "E01.09", "link": "https://learn.microsoft.com/mem/intune/fundamentals/azure-virtual-desktop-multi-session", "services": [ - "Monitor", - "AVD" + "AVD", + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -7517,8 +7771,8 @@ "id": "E01.10", "link": "https://learn.microsoft.com/azure/virtual-desktop/scheduled-agent-updates", "services": [ - "Monitor", - "AVD" + "AVD", + "Monitor" ], "severity": "Low", "subcategory": "Management", @@ -7533,9 +7787,9 @@ "id": "E01.11", "link": "https://docs.microsoft.com/azure/virtual-desktop/create-validation-host-pool", "services": [ - "Monitor", + "VM", "AVD", - "VM" + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -7550,9 +7804,9 @@ "id": "E01.12", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/wvd/eslz-platform-automation-and-devops", "services": [ - "Monitor", + "VM", "AVD", - "VM" + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -7584,8 +7838,8 @@ "id": "E02.01", "link": "https://learn.microsoft.com/azure/virtual-desktop/insights", "services": [ - "Monitor", - "AVD" + "AVD", + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -7617,9 +7871,9 @@ "id": "E02.03", "link": "https://docs.microsoft.com/azure/storage/files/storage-files-monitoring?tabs=azure-portal", "services": [ - "Monitor", + "Storage", "AVD", - "Storage" + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -7634,8 +7888,8 @@ "id": "E02.04", "link": "https://docs.microsoft.com/azure/virtual-desktop/set-up-service-alerts", "services": [ - "Monitor", - "AVD" + "AVD", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -7668,9 +7922,9 @@ "id": "F01.02", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/wvd/eslz-network-topology-and-connectivity", "services": [ - "VWAN", + "VNet", "AVD", - "VNet" + "VWAN" ], "severity": "Medium", "subcategory": "Networking", @@ -7701,10 +7955,10 @@ "id": "F01.04", "link": "https://docs.microsoft.com/azure/firewall/protect-windows-virtual-desktop", "services": [ - "AVD", - "NVA", + "VNet", "Firewall", - "VNet" + "AVD", + "NVA" ], "severity": "Medium", "subcategory": "Networking", @@ -7734,8 +7988,8 @@ "id": "F01.06", "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", @@ -7750,9 +8004,9 @@ "id": "F01.07", "link": "https://docs.microsoft.com/azure/firewall/protect-windows-virtual-desktop", "services": [ - "AVD", "VNet", "Firewall", + "AVD", "NVA" ], "severity": "Low", @@ -7800,11 +8054,11 @@ "id": "F01.10", "link": "https://learn.microsoft.com/azure/storage/files/storage-files-networking-endpoints", "services": [ + "AVD", "Storage", + "VNet", "Cost", - "PrivateLink", - "AVD", - "VNet" + "PrivateLink" ], "severity": "Medium", "subcategory": "Networking", @@ -7850,8 +8104,8 @@ "id": "G02.01", "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", @@ -7866,10 +8120,10 @@ "id": "G02.02", "link": "https://learn.microsoft.com/azure/virtual-machines/disk-encryption-overview", "services": [ - "VM", - "AVD", "Storage", - "AKV" + "AKV", + "VM", + "AVD" ], "severity": "Low", "subcategory": "Host Configuration", @@ -7962,8 +8216,8 @@ "id": "G03.02", "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/web-protection-overview", "services": [ - "AVD", - "Defender" + "Defender", + "AVD" ], "severity": "Medium", "subcategory": "Management", @@ -7993,12 +8247,12 @@ "id": "G03.04", "link": "https://learn.microsoft.com/azure/virtual-desktop/security-guide#enable-microsoft-defender-for-cloud", "services": [ - "Storage", - "VM", + "Subscriptions", + "AKV", "AVD", + "Storage", "Defender", - "AKV", - "Subscriptions" + "VM" ], "severity": "Medium", "subcategory": "Management", @@ -8013,9 +8267,9 @@ "id": "G03.05", "link": "https://learn.microsoft.com/azure/virtual-desktop/security-guide#collect-audit-logs", "services": [ - "Monitor", + "Entra", "AVD", - "Entra" + "Monitor" ], "severity": "Medium", "subcategory": "Management", @@ -8030,9 +8284,9 @@ "id": "G03.06", "link": "https://docs.microsoft.com/azure/virtual-desktop/rbac", "services": [ - "AVD", + "RBAC", "Entra", - "RBAC" + "AVD" ], "severity": "Low", "subcategory": "Management", @@ -8047,8 +8301,8 @@ "id": "G03.07", "link": "https://learn.microsoft.com/azure/virtual-desktop/security-guide#windows-defender-application-control", "services": [ - "AVD", - "Defender" + "Defender", + "AVD" ], "severity": "Medium", "subcategory": "Management", @@ -8063,8 +8317,8 @@ "id": "G04.01", "link": "https://learn.microsoft.com/azure/virtual-desktop/set-up-mfa", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Medium", "subcategory": "Microsoft Entra ID", @@ -8094,8 +8348,8 @@ "id": "H01.01", "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", @@ -8111,8 +8365,8 @@ "link": "https://learn.microsoft.com/azure/storage/files/storage-files-smb-multichannel-performance", "services": [ "ACR", - "AVD", "Storage", + "AVD", "Cost" ], "severity": "Low", @@ -8128,8 +8382,8 @@ "id": "H02.01", "link": "https://azure.microsoft.com/global-infrastructure/services/", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "Azure NetApp Files", @@ -8144,8 +8398,8 @@ "id": "H02.02", "link": "https://learn.microsoft.com/azure/virtual-desktop/create-fslogix-profile-container", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "Azure NetApp Files", @@ -8160,9 +8414,9 @@ "id": "H02.03", "link": "https://docs.microsoft.com/azure/azure-netapp-files/create-active-directory-connections", "services": [ - "AVD", "Storage", - "VNet" + "VNet", + "AVD" ], "severity": "High", "subcategory": "Azure NetApp Files", @@ -8177,8 +8431,8 @@ "id": "H03.01", "link": "https://docs.microsoft.com/azure/virtual-machines/disks-types", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "Capacity Planning", @@ -8193,9 +8447,9 @@ "id": "H03.02", "link": "https://docs.microsoft.com/azure/virtual-desktop/store-fslogix-profile", "services": [ + "Storage", "VM", - "AVD", - "Storage" + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -8210,8 +8464,8 @@ "id": "H03.03", "link": "https://learn.microsoft.com/azure/virtual-desktop/store-fslogix-profile", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -8226,8 +8480,8 @@ "id": "H03.04", "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", @@ -8242,9 +8496,9 @@ "id": "H03.05", "link": "https://docs.microsoft.com/azure/virtual-desktop/fslogix-containers-azure-files", "services": [ - "AVD", + "Cost", "Storage", - "Cost" + "AVD" ], "severity": "High", "subcategory": "Capacity Planning", @@ -8259,9 +8513,9 @@ "id": "H04.01", "link": "https://learn.microsoft.com/fslogix/concepts-container-types#when-to-use-profile-and-odfc-containers", "services": [ + "Storage", "ASR", - "AVD", - "Storage" + "AVD" ], "severity": "High", "subcategory": "FSLogix", @@ -8276,8 +8530,8 @@ "id": "H04.02", "link": "https://learn.microsoft.com/fslogix/overview-prerequisites#configure-antivirus-file-and-folder-exclusions", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "FSLogix", @@ -8292,8 +8546,8 @@ "id": "H04.03", "link": "https://docs.microsoft.com/fslogix/profile-container-configuration-reference", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "FSLogix", @@ -8309,9 +8563,9 @@ "link": "https://learn.microsoft.com/fslogix/concepts-configuration-examples", "services": [ "ACR", - "AVD", "Storage", - "AKV" + "AKV", + "AVD" ], "severity": "High", "subcategory": "FSLogix", @@ -8326,8 +8580,8 @@ "id": "H04.05", "link": "https://learn.microsoft.com/fslogix/concepts-multi-concurrent-connections", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "High", "subcategory": "FSLogix", @@ -8342,9 +8596,9 @@ "id": "H04.06", "link": "https://docs.microsoft.com/fslogix/cloud-cache-configuration-reference", "services": [ + "Storage", "VM", - "AVD", - "Storage" + "AVD" ], "severity": "Low", "subcategory": "FSLogix", @@ -8359,8 +8613,8 @@ "id": "H04.07", "link": "https://docs.microsoft.com/fslogix/manage-profile-content-cncpt#redirectionsxml", "services": [ - "AVD", - "Storage" + "Storage", + "AVD" ], "severity": "Medium", "subcategory": "FSLogix", @@ -8569,8 +8823,8 @@ "link": "https://learn.microsoft.com/azure/cost-management-billing/manage/mca-section-invoice", "services": [ "Cost", - "Entra", - "Storage" + "Storage", + "Entra" ], "severity": "Low", "subcategory": "Microsoft Customer Agreement", @@ -8663,8 +8917,8 @@ "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/concept-activity-logs-azure-monitor", "service": "Entra", "services": [ - "Monitor", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Identity", @@ -8699,8 +8953,8 @@ "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/overview", "service": "Entra", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "Low", "subcategory": "Identity", @@ -8815,8 +9069,8 @@ "id": "B03.11", "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/identity/adds-extend-domain#vm-recommendations", "services": [ - "VM", "ACR", + "VM", "Entra" ], "severity": "Medium", @@ -8896,8 +9150,8 @@ "id": "B04.01", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access-landing-zones#managed-identities", "services": [ - "VNet", - "Entra" + "Entra", + "VNet" ], "severity": "Medium", "subcategory": "Landing zones", @@ -8912,11 +9166,11 @@ "id": "B04.02", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access-landing-zones#rbac-recommendations", "services": [ + "AKV", + "ACR", "Storage", "RBAC", - "ACR", - "Entra", - "AKV" + "Entra" ], "severity": "Medium", "subcategory": "Landing zones", @@ -8990,8 +9244,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups#management-group-recommendations", "services": [ "RBAC", - "Subscriptions", - "AzurePolicy" + "AzurePolicy", + "Subscriptions" ], "severity": "Medium", "subcategory": "Subscriptions", @@ -9006,10 +9260,10 @@ "id": "C02.04", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups#management-group-recommendations", "services": [ - "ExpressRoute", "DNS", - "VWAN", - "Subscriptions" + "ExpressRoute", + "Subscriptions", + "VWAN" ], "severity": "Medium", "subcategory": "Subscriptions", @@ -9069,10 +9323,10 @@ "id": "C02.08", "link": "https://learn.microsoft.com/azure/governance/management-groups/overview", "services": [ - "Subscriptions", - "RBAC", "Cost", - "AzurePolicy" + "RBAC", + "AzurePolicy", + "Subscriptions" ], "severity": "High", "subcategory": "Subscriptions", @@ -9101,9 +9355,9 @@ "id": "C02.10", "link": "https://learn.microsoft.com/azure/cost-management-billing/reservations/save-compute-costs-reservations", "services": [ + "Cost", "VM", "Subscriptions", - "Cost", "AzurePolicy" ], "severity": "High", @@ -9120,8 +9374,8 @@ "id": "C02.11", "link": "https://learn.microsoft.com/azure/architecture/framework/scalability/design-capacity", "services": [ - "Monitor", - "Subscriptions" + "Subscriptions", + "Monitor" ], "severity": "High", "subcategory": "Subscriptions", @@ -9243,8 +9497,8 @@ "id": "D01.01", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-app-delivery", "services": [ - "FrontDoor", - "AppGW" + "AppGW", + "FrontDoor" ], "severity": "Medium", "subcategory": "App delivery", @@ -9337,13 +9591,13 @@ "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/hybrid-networking/expressroute", "service": "VNet", "services": [ - "ExpressRoute", - "NVA", "Firewall", + "VNet", + "NVA", "VPN", - "DNS", "Entra", - "VNet" + "ExpressRoute", + "DNS" ], "severity": "High", "subcategory": "Hub and spoke", @@ -9391,8 +9645,8 @@ "link": "https://learn.microsoft.com/azure/route-server/quickstart-configure-route-server-portal#create-a-route-server-1", "service": "ARS", "services": [ - "ARS", - "VNet" + "VNet", + "ARS" ], "severity": "Low", "subcategory": "Hub and spoke", @@ -9544,8 +9798,8 @@ "link": "https://learn.microsoft.com/azure/expressroute/plan-manage-cost", "service": "ExpressRoute", "services": [ - "ExpressRoute", - "Cost" + "Cost", + "ExpressRoute" ], "severity": "High", "subcategory": "Hybrid", @@ -9562,8 +9816,8 @@ "link": "https://learn.microsoft.com/azure/expressroute/expressroute-faqs#expressroute-local", "service": "ExpressRoute", "services": [ - "ExpressRoute", - "Cost" + "Cost", + "ExpressRoute" ], "severity": "High", "subcategory": "Hybrid", @@ -9661,8 +9915,8 @@ "link": "https://learn.microsoft.com/azure/expressroute/expressroute-erdirect-about", "service": "ExpressRoute", "services": [ - "ExpressRoute", - "Cost" + "Cost", + "ExpressRoute" ], "severity": "High", "subcategory": "Hybrid", @@ -9711,9 +9965,9 @@ "link": "https://learn.microsoft.com/azure/expressroute/how-to-configure-connection-monitor", "service": "ExpressRoute", "services": [ - "Monitor", "ACR", - "NetworkWatcher" + "NetworkWatcher", + "Monitor" ], "severity": "Medium", "subcategory": "Hybrid", @@ -9780,8 +10034,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", @@ -9918,8 +10172,8 @@ "link": "https://learn.microsoft.com/azure/dns/private-dns-autoregistration", "service": "DNS", "services": [ - "VM", "DNS", + "VM", "VNet" ], "severity": "High", @@ -9952,8 +10206,8 @@ "link": "https://learn.microsoft.com/azure/bastion/bastion-faq#subnet", "service": "Bastion", "services": [ - "VNet", - "Bastion" + "Bastion", + "VNet" ], "severity": "Medium", "subcategory": "Internet", @@ -9986,9 +10240,9 @@ "service": "Firewall", "services": [ "ACR", - "Firewall", + "RBAC", "AzurePolicy", - "RBAC" + "Firewall" ], "severity": "Medium", "subcategory": "Internet", @@ -10020,10 +10274,10 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", "service": "WAF", "services": [ - "WAF", "ACR", "FrontDoor", - "AzurePolicy" + "AzurePolicy", + "WAF" ], "severity": "Medium", "subcategory": "Internet", @@ -10039,10 +10293,10 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "WAF", "services": [ - "WAF", - "FrontDoor", "AppGW", - "AzurePolicy" + "WAF", + "AzurePolicy", + "FrontDoor" ], "severity": "Low", "subcategory": "Internet", @@ -10059,8 +10313,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "WAF", "services": [ - "WAF", - "VNet" + "VNet", + "WAF" ], "severity": "High", "subcategory": "Internet", @@ -10077,8 +10331,8 @@ "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-reference-architectures", "service": "VNet", "services": [ - "VNet", - "DDoS" + "DDoS", + "VNet" ], "severity": "High", "subcategory": "Internet", @@ -10165,11 +10419,11 @@ "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview", "service": "Firewall", "services": [ - "VWAN", - "NVA", - "Storage", "Firewall", - "VNet" + "Storage", + "VNet", + "VWAN", + "NVA" ], "severity": "High", "subcategory": "Internet", @@ -10230,8 +10484,8 @@ "link": "https://learn.microsoft.com/azure/app-service/networking-features", "service": "ExpressRoute", "services": [ - "ExpressRoute", - "PrivateLink" + "PrivateLink", + "ExpressRoute" ], "severity": "Medium", "subcategory": "PaaS", @@ -10264,10 +10518,10 @@ "link": "https://learn.microsoft.com/azure/app-service/networking-features", "service": "Firewall", "services": [ + "PrivateLink", "DNS", - "NVA", "Firewall", - "PrivateLink" + "NVA" ], "severity": "Medium", "subcategory": "PaaS", @@ -10285,8 +10539,8 @@ "link": "https://learn.microsoft.com/azure/firewall/firewall-faq#why-does-azure-firewall-need-a--26-subnet-size", "service": "Firewall", "services": [ - "Firewall", - "VNet" + "VNet", + "Firewall" ], "severity": "High", "subcategory": "Segmentation", @@ -10385,9 +10639,9 @@ "link": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", "service": "NSG", "services": [ - "NVA", "Entra", - "VNet" + "VNet", + "NVA" ], "severity": "Medium", "subcategory": "Segmentation", @@ -10403,8 +10657,8 @@ "link": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", "service": "NSG", "services": [ - "VNet", - "NetworkWatcher" + "NetworkWatcher", + "VNet" ], "severity": "Medium", "subcategory": "Segmentation", @@ -10436,8 +10690,8 @@ "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about", "service": "VWAN", "services": [ - "VWAN", - "ACR" + "ACR", + "VWAN" ], "severity": "Medium", "subcategory": "Virtual WAN", @@ -10452,8 +10706,8 @@ "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about", "service": "VWAN", "services": [ - "VWAN", - "ACR" + "ACR", + "VWAN" ], "severity": "Low", "subcategory": "Virtual WAN", @@ -10627,8 +10881,8 @@ "link": "https://learn.microsoft.com/azure/governance/policy/overview", "service": "Policy", "services": [ - "Subscriptions", - "AzurePolicy" + "AzurePolicy", + "Subscriptions" ], "severity": "Medium", "subcategory": "Governance", @@ -10658,8 +10912,8 @@ "link": "https://learn.microsoft.com/security/benchmark/azure/mcsb-asset-management#am-2-use-only-approved-services", "service": "Policy", "services": [ - "Subscriptions", - "AzurePolicy" + "AzurePolicy", + "Subscriptions" ], "severity": "Low", "subcategory": "Governance", @@ -10690,10 +10944,10 @@ "link": "https://learn.microsoft.com/azure/governance/policy/overview#azure-rbac-permissions-in-azure-policy", "service": "Policy", "services": [ - "Subscriptions", "RBAC", + "AzurePolicy", "Entra", - "AzurePolicy" + "Subscriptions" ], "severity": "Medium", "subcategory": "Governance", @@ -10708,8 +10962,8 @@ "link": "https://learn.microsoft.com/azure/governance/policy/overview", "service": "Policy", "services": [ - "Subscriptions", - "AzurePolicy" + "AzurePolicy", + "Subscriptions" ], "severity": "Medium", "subcategory": "Governance", @@ -10784,8 +11038,8 @@ "link": "https://learn.microsoft.com/azure/automation/automation-solution-vm-management-config", "service": "VM", "services": [ - "VM", "Cost", + "VM", "TrafficManager" ], "severity": "Low", @@ -10815,9 +11069,9 @@ "id": "E02.02", "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": [ - "Monitor", "Cost", - "TrafficManager" + "TrafficManager", + "Monitor" ], "severity": "Medium", "subcategory": "Optimize your cloud investment", @@ -10833,9 +11087,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": "WAF", "services": [ + "AppGW", "WAF", - "FrontDoor", - "AppGW" + "FrontDoor" ], "severity": "High", "subcategory": "App delivery", @@ -10850,10 +11104,10 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", "service": "WAF", "services": [ - "WAF", - "FrontDoor", "Sentinel", - "AppGW" + "AppGW", + "WAF", + "FrontDoor" ], "severity": "Medium", "subcategory": "App delivery", @@ -10895,10 +11149,10 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "service": "Monitor", "services": [ - "Monitor", "RBAC", + "AzurePolicy", "Entra", - "AzurePolicy" + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -10927,8 +11181,8 @@ "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": [ - "Monitor", - "ARS" + "ARS", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -10944,8 +11198,8 @@ "link": "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/govern/policy-compliance/regulatory-compliance", "service": "Policy", "services": [ - "Monitor", - "AzurePolicy" + "AzurePolicy", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -10962,8 +11216,8 @@ "service": "VM", "services": [ "VM", - "Monitor", - "AzurePolicy" + "AzurePolicy", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -11011,8 +11265,8 @@ "link": "https://learn.microsoft.com/azure/network-watcher/network-watcher-monitoring-overview", "service": "Network Watcher", "services": [ - "Monitor", - "NetworkWatcher" + "NetworkWatcher", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -11042,9 +11296,9 @@ "id": "F03.10", "link": "https://learn.microsoft.com/azure/governance/policy/overview", "services": [ - "Monitor", "RBAC", - "AzurePolicy" + "AzurePolicy", + "Monitor" ], "severity": "Low", "subcategory": "Monitoring", @@ -11101,9 +11355,9 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "service": "Monitor", "services": [ - "Monitor", "RBAC", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -11132,8 +11386,8 @@ "id": "F03.16", "link": "https://learn.microsoft.com/azure/azure-monitor/agents/diagnostics-extension-overview", "services": [ - "Monitor", - "Storage" + "Storage", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -11210,8 +11464,8 @@ "service": "VM", "services": [ "VM", - "Monitor", - "AzurePolicy" + "AzurePolicy", + "Monitor" ], "severity": "Medium", "subcategory": "Operational compliance", @@ -11226,9 +11480,9 @@ "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", "service": "VM", "services": [ - "VM", "ACR", - "ASR" + "ASR", + "VM" ], "severity": "Medium", "subcategory": "Protect and Recover", @@ -11377,8 +11631,8 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "service": "Key Vault", "services": [ - "AKV", - "AzurePolicy" + "AzurePolicy", + "AKV" ], "severity": "Medium", "subcategory": "Encryption and keys", @@ -11441,8 +11695,8 @@ "service": "Key Vault", "services": [ "PrivateLink", - "VNet", - "AKV" + "AKV", + "VNet" ], "severity": "Medium", "subcategory": "Encryption and keys", @@ -11457,9 +11711,9 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/monitor-key-vault", "service": "Key Vault", "services": [ - "Monitor", "Entra", - "AKV" + "AKV", + "Monitor" ], "severity": "Medium", "subcategory": "Encryption and keys", @@ -11474,8 +11728,8 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "service": "Key Vault", "services": [ - "AKV", - "AzurePolicy" + "AzurePolicy", + "AKV" ], "severity": "Medium", "subcategory": "Encryption and keys", @@ -11565,9 +11819,9 @@ "id": "G03.02", "link": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export?tabs=portal", "services": [ - "Monitor", + "Storage", "ARS", - "Storage" + "Monitor" ], "severity": "Medium", "subcategory": "Operations", @@ -11647,8 +11901,8 @@ "link": "https://learn.microsoft.com/azure/security-center/", "service": "VM", "services": [ - "Monitor", - "Defender" + "Defender", + "Monitor" ], "severity": "Medium", "subcategory": "Operations", @@ -11663,8 +11917,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "service": "Monitor", "services": [ - "Monitor", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Operations", @@ -12189,8 +12443,8 @@ "id": "D01.03", "link": "https://learn.microsoft.com/azure/architecture/guide/multitenant/approaches/cost-management-allocation", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "severity": "Medium", "subcategory": "Cost Optimization", @@ -12374,10 +12628,10 @@ "link": "https://learn.microsoft.com/azure/event-hubs/authorize-access-shared-access-signature#shared-access-authorization-policies", "services": [ "EventHubs", - "TrafficManager", + "AzurePolicy", "RBAC", "Entra", - "AzurePolicy" + "TrafficManager" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -12393,11 +12647,11 @@ "id": "A02.02", "link": "https://learn.microsoft.com/azure/event-hubs/authenticate-managed-identity?tabs=latest", "services": [ + "AKV", "EventHubs", "Storage", - "VM", "Entra", - "AKV" + "VM" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -12413,9 +12667,9 @@ "id": "A02.03", "link": "https://learn.microsoft.com/azure/event-hubs/authorize-access-azure-active-directory#azure-built-in-roles-for-azure-event-hubs", "services": [ - "EventHubs", + "RBAC", "Entra", - "RBAC" + "EventHubs" ], "severity": "High", "subcategory": "Identity and Access Management", @@ -12432,8 +12686,8 @@ "link": "https://learn.microsoft.com/azure/event-hubs/monitor-event-hubs-reference", "services": [ "Monitor", - "EventHubs", - "VNet" + "VNet", + "EventHubs" ], "severity": "Medium", "subcategory": "Monitoring", @@ -12449,9 +12703,9 @@ "id": "A04.01", "link": "https://learn.microsoft.com/azure/event-hubs/private-link-service", "services": [ - "EventHubs", "PrivateLink", - "VNet" + "VNet", + "EventHubs" ], "severity": "Medium", "subcategory": "Networking", @@ -12482,8 +12736,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-error-handling-policies", "service": "APIM", "services": [ - "APIM", - "AzurePolicy" + "AzurePolicy", + "APIM" ], "severity": "Medium", "subcategory": "Development best practices", @@ -12497,8 +12751,8 @@ "link": "https://learn.microsoft.com/azure/api-management/set-edit-policies?tabs=form#use-base-element-to-set-policy-evaluation-order", "service": "APIM", "services": [ - "APIM", - "AzurePolicy" + "AzurePolicy", + "APIM" ], "severity": "Medium", "subcategory": "Development best practices", @@ -12513,8 +12767,8 @@ "service": "APIM", "services": [ "ACR", - "APIM", - "AzurePolicy" + "AzurePolicy", + "APIM" ], "severity": "Medium", "subcategory": "Development best practices", @@ -12542,8 +12796,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-use-azure-monitor#resource-logs", "service": "APIM", "services": [ - "Monitor", - "APIM" + "APIM", + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -12557,8 +12811,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-app-insights", "service": "APIM", "services": [ - "Monitor", - "APIM" + "APIM", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -12572,8 +12826,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-use-azure-monitor", "service": "APIM", "services": [ - "Monitor", - "APIM" + "APIM", + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -12587,9 +12841,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#certificate-management-in-azure-key-vault", "service": "APIM", "services": [ - "APIM", + "AKV", "Entra", - "AKV" + "APIM" ], "severity": "High", "subcategory": "Data protection", @@ -12603,8 +12857,8 @@ "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": [ - "APIM", - "Entra" + "Entra", + "APIM" ], "severity": "High", "subcategory": "Identity", @@ -12618,8 +12872,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-aad", "service": "APIM", "services": [ - "APIM", - "Entra" + "Entra", + "APIM" ], "severity": "Medium", "subcategory": "Identity", @@ -12633,8 +12887,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-create-groups", "service": "APIM", "services": [ - "APIM", - "Entra" + "Entra", + "APIM" ], "severity": "Medium", "subcategory": "Privileged access", @@ -12662,8 +12916,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-properties?tabs=azure-portal", "service": "APIM", "services": [ - "APIM", - "AzurePolicy" + "AzurePolicy", + "APIM" ], "severity": "Medium", "subcategory": "Best practices", @@ -12677,8 +12931,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region", "service": "APIM", "services": [ - "APIM", - "ASR" + "ASR", + "APIM" ], "severity": "Medium", "subcategory": "Business continuity and disaster recovery", @@ -12692,8 +12946,8 @@ "link": "https://learn.microsoft.com/azure/api-management/high-availability", "service": "APIM", "services": [ - "APIM", - "ASR" + "ASR", + "APIM" ], "severity": "Medium", "subcategory": "Business continuity and disaster recovery", @@ -12707,9 +12961,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#service-native-backup-capability", "service": "APIM", "services": [ - "APIM", "ASR", - "Backup" + "Backup", + "APIM" ], "severity": "High", "subcategory": "Business continuity and disaster recovery", @@ -12722,8 +12976,8 @@ "guid": "f96ddac5-77ec-4fa9-8833-4327f052059e", "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-cache-external", "services": [ - "APIM", - "AzurePolicy" + "AzurePolicy", + "APIM" ], "severity": "Medium", "subcategory": "Performance and scalability", @@ -12737,9 +12991,9 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-howto-log-event-hubs", "service": "APIM", "services": [ - "EventHubs", + "AzurePolicy", "APIM", - "AzurePolicy" + "EventHubs" ], "severity": "Low", "subcategory": "Performance and scalability", @@ -12753,8 +13007,8 @@ "link": "https://learn.microsoft.com/azure/api-management/api-management-sample-flexible-throttling", "service": "APIM", "services": [ - "APIM", - "AzurePolicy" + "AzurePolicy", + "APIM" ], "severity": "Medium", "subcategory": "Performance and scalability", @@ -12797,9 +13051,9 @@ "link": "https://learn.microsoft.com/azure/api-management/front-door-api-management", "service": "APIM", "services": [ - "APIM", "FrontDoor", - "Entra" + "Entra", + "APIM" ], "severity": "Medium", "subcategory": "Connectivity", @@ -12813,8 +13067,8 @@ "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": [ - "APIM", - "VNet" + "VNet", + "APIM" ], "severity": "Medium", "subcategory": "Security", @@ -12828,10 +13082,10 @@ "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": [ - "Monitor", - "APIM", "VNet", - "Entra" + "Entra", + "APIM", + "Monitor" ], "severity": "Medium", "subcategory": "Security", @@ -12845,10 +13099,10 @@ "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": [ - "APIM", + "PrivateLink", "VNet", "Entra", - "PrivateLink" + "APIM" ], "severity": "Medium", "subcategory": "Security", @@ -12890,8 +13144,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/app-platform/api-management/platform-automation-and-devops#design-recommendations", "service": "APIM", "services": [ - "APIM", - "Entra" + "Entra", + "APIM" ], "severity": "Medium", "subcategory": "Best practices", @@ -12905,8 +13159,8 @@ "link": "https://learn.microsoft.com/azure/api-management/visual-studio-code-tutorial", "service": "APIM", "services": [ - "APIM", - "Entra" + "Entra", + "APIM" ], "severity": "Medium", "subcategory": "Best practices", @@ -13004,8 +13258,8 @@ "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": [ - "APIM", - "AKV" + "AKV", + "APIM" ], "severity": "High", "subcategory": "Data protection", @@ -13019,8 +13273,8 @@ "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": [ - "APIM", - "Entra" + "Entra", + "APIM" ], "severity": "Medium", "subcategory": "Identities", @@ -13034,10 +13288,10 @@ "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", - "APIM", + "AppGW", "Entra", - "AppGW" + "APIM", + "WAF" ], "severity": "High", "subcategory": "Network", @@ -13108,9 +13362,9 @@ "guid": "e0d5973c-d4ce-432c-8881-37f6f7c4c0d4", "link": "https://learn.microsoft.com/azure/virtual-machines/managed-disks-overview#temporary-disk", "services": [ + "Storage", "VM", - "SQL", - "Storage" + "SQL" ], "severity": "Medium", "subcategory": "Virtual Machines", @@ -13124,9 +13378,9 @@ "guid": "e514548d-2447-4ec6-9138-b8200f1ce16e", "link": "https://learn.microsoft.com/azure/reliability/availability-zones-overview", "services": [ - "VM", "ACR", - "Storage" + "Storage", + "VM" ], "severity": "Medium", "subcategory": "Virtual Machines", @@ -13154,8 +13408,8 @@ "guid": "6ba2c021-4991-414a-9d3c-e574dccbd979", "link": "https://learn.microsoft.com/azure/virtual-machines/availability", "services": [ - "VM", - "ASR" + "ASR", + "VM" ], "severity": "High", "subcategory": "Virtual Machines", @@ -13169,8 +13423,8 @@ "guid": "2a6bcca2-b5fe-4a1e-af3d-d95d48c7c891", "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", "services": [ - "VM", "ASR", + "VM", "AVS" ], "severity": "High", @@ -13199,8 +13453,8 @@ "guid": "e6e2065b-3a76-4af4-a691-e8939ada4666", "link": "https://learn.microsoft.com/azure/quotas/per-vm-quota-requests", "services": [ - "VM", - "ASR" + "ASR", + "VM" ], "severity": "Medium", "subcategory": "Virtual Machines", @@ -13425,8 +13679,8 @@ "guid": "8df03a82-2cd4-463c-abbc-8ac299ebc92a", "link": "https://learn.microsoft.com/azure/networking/disaster-recovery-dns-traffic-manager", "services": [ - "TrafficManager", "DNS", + "TrafficManager", "ASR", "Monitor" ], @@ -13501,10 +13755,10 @@ "guid": "ead53cc7-de2e-48aa-ab35-71549ab9153d", "link": "https://learn.microsoft.com/azure/expressroute/use-s2s-vpn-as-backup-for-expressroute-privatepeering", "services": [ - "ExpressRoute", - "VPN", "Cost", - "Backup" + "ExpressRoute", + "Backup", + "VPN" ], "severity": "Low", "subcategory": "ExpressRoute", @@ -13547,8 +13801,8 @@ "guid": "dccbd979-2a6b-4cca-8b5f-ea1ebf3dd95d", "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-custom-probe-overview#design-guidance", "services": [ - "Monitor", - "LoadBalancer" + "LoadBalancer", + "Monitor" ], "severity": "Low", "subcategory": "Load Balancers", @@ -13576,8 +13830,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", @@ -13605,9 +13859,9 @@ "id": "A01.01", "service": "AVS", "services": [ + "Subscriptions", "Entra", - "AVS", - "Subscriptions" + "AVS" ], "severity": "High", "subcategory": "Identity", @@ -13696,8 +13950,8 @@ "id": "A01.07", "service": "AVS", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "Medium", @@ -13712,8 +13966,8 @@ "id": "A01.08", "service": "AVS", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "Medium", @@ -13728,8 +13982,8 @@ "id": "A01.09", "service": "AVS", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "High", @@ -13744,8 +13998,8 @@ "id": "A01.10", "service": "AVS", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "High", @@ -13775,11 +14029,11 @@ "id": "B02.01", "service": "AVS", "services": [ - "ExpressRoute", "Monitor", "VPN", - "AVS", - "NetworkWatcher" + "ExpressRoute", + "NetworkWatcher", + "AVS" ], "severity": "High", "subcategory": "Monitoring", @@ -13793,11 +14047,11 @@ "id": "B02.02", "service": "AVS", "services": [ + "Monitor", "ExpressRoute", + "NetworkWatcher", "VM", - "Monitor", - "AVS", - "NetworkWatcher" + "AVS" ], "severity": "Medium", "subcategory": "Monitoring", @@ -13828,8 +14082,8 @@ "id": "B03.01", "service": "AVS", "services": [ - "ARS", - "AVS" + "AVS", + "ARS" ], "severity": "High", "subcategory": "Routing", @@ -13843,8 +14097,8 @@ "id": "C01.01", "service": "AVS", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "High", @@ -13859,8 +14113,8 @@ "id": "C01.02", "service": "AVS", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "High", @@ -13905,8 +14159,8 @@ "id": "C01.05", "service": "AVS", "services": [ - "Entra", "RBAC", + "Entra", "AVS" ], "severity": "Medium", @@ -13937,8 +14191,8 @@ "service": "AVS", "services": [ "VM", - "AVS", - "Entra" + "Entra", + "AVS" ], "severity": "High", "subcategory": "Security (identity)", @@ -13966,9 +14220,9 @@ "id": "C02.02", "service": "AVS", "services": [ - "Firewall", + "AppGW", "AVS", - "AppGW" + "Firewall" ], "severity": "High", "subcategory": "Security (network)", @@ -13996,8 +14250,8 @@ "id": "C02.04", "service": "AVS", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Security (network)", @@ -14011,11 +14265,11 @@ "id": "C02.05", "service": "AVS", "services": [ - "ExpressRoute", + "DDoS", "VPN", - "AVS", "VNet", - "DDoS" + "ExpressRoute", + "AVS" ], "severity": "Medium", "subcategory": "Security (network)", @@ -14058,8 +14312,8 @@ "id": "C03.02", "service": "AVS", "services": [ - "Arc", - "AVS" + "AVS", + "Arc" ], "severity": "Medium", "subcategory": "Security (guest/VM)", @@ -14132,8 +14386,8 @@ "service": "AVS", "services": [ "Storage", - "AVS", - "AzurePolicy" + "AzurePolicy", + "AVS" ], "severity": "High", "subcategory": "Governance (platform)", @@ -14176,8 +14430,8 @@ "id": "C04.05", "service": "AVS", "services": [ - "AVS", - "AzurePolicy" + "AzurePolicy", + "AVS" ], "severity": "Medium", "subcategory": "Governance (platform)", @@ -14249,8 +14503,8 @@ "id": "C05.01", "service": "AVS", "services": [ - "VM", "Defender", + "VM", "AVS" ], "severity": "Medium", @@ -14266,8 +14520,8 @@ "service": "AVS", "services": [ "VM", - "Arc", - "AVS" + "AVS", + "Arc" ], "severity": "Medium", "subcategory": "Governance (guest/VM)", @@ -14312,8 +14566,8 @@ "service": "AVS", "services": [ "VM", - "AVS", "Backup", + "AVS", "AzurePolicy" ], "severity": "Medium", @@ -14328,9 +14582,9 @@ "id": "C06.01", "service": "AVS", "services": [ - "Monitor", "Defender", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Compliance", @@ -14401,8 +14655,8 @@ "id": "D01.01", "service": "AVS", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -14416,8 +14670,8 @@ "id": "D01.02", "service": "AVS", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -14431,8 +14685,8 @@ "id": "D01.03", "service": "AVS", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -14446,8 +14700,8 @@ "id": "D01.04", "service": "AVS", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -14461,9 +14715,9 @@ "id": "D01.05", "service": "AVS", "services": [ - "Monitor", "Storage", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -14477,8 +14731,8 @@ "id": "D01.06", "service": "AVS", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Low", "subcategory": "Monitoring", @@ -14492,8 +14746,8 @@ "id": "D02.01", "service": "AVS", "services": [ - "VM", "Storage", + "VM", "AVS", "AzurePolicy" ], @@ -14524,8 +14778,8 @@ "service": "AVS", "services": [ "Storage", - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Operations", @@ -14539,8 +14793,8 @@ "id": "D02.04", "service": "AVS", "services": [ - "Arc", - "AVS" + "AVS", + "Arc" ], "severity": "Medium", "subcategory": "Operations", @@ -14554,8 +14808,8 @@ "id": "D02.05", "service": "AVS", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Operations", @@ -14583,9 +14837,9 @@ "id": "D02.07", "service": "AVS", "services": [ - "Monitor", + "AzurePolicy", "AVS", - "AzurePolicy" + "Monitor" ], "severity": "Medium", "subcategory": "Operations", @@ -14614,8 +14868,8 @@ "id": "E01.01", "service": "AVS", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Backup", @@ -14704,10 +14958,10 @@ "id": "E02.06", "service": "AVS", "services": [ - "ExpressRoute", "ASR", - "NVA", - "AVS" + "ExpressRoute", + "AVS", + "NVA" ], "severity": "Medium", "subcategory": "Disaster Recovery", @@ -14721,8 +14975,8 @@ "id": "E03.01", "service": "AVS", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -14736,8 +14990,8 @@ "id": "E03.02", "service": "AVS", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -14751,8 +15005,8 @@ "id": "E03.03", "service": "AVS", "services": [ - "AVS", - "Backup" + "Backup", + "AVS" ], "severity": "Medium", "subcategory": "Business Continuity", @@ -14836,8 +15090,8 @@ "id": "F02.03", "service": "AVS", "services": [ - "AVS", - "AzurePolicy" + "AzurePolicy", + "AVS" ], "severity": "Low", "subcategory": "Automated Deployment", @@ -14910,8 +15164,8 @@ "id": "F04.01", "service": "AVS", "services": [ - "AVS", - "Subscriptions" + "Subscriptions", + "AVS" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -14926,8 +15180,8 @@ "service": "AVS", "services": [ "Storage", - "AVS", - "AzurePolicy" + "AzurePolicy", + "AVS" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -14983,8 +15237,8 @@ "id": "F04.06", "service": "AVS", "services": [ - "Monitor", - "AVS" + "AVS", + "Monitor" ], "severity": "Medium", "subcategory": "Automated Scale", @@ -15031,8 +15285,8 @@ "id": "G02.01", "service": "AVS", "services": [ - "VPN", - "AVS" + "AVS", + "VPN" ], "severity": "Medium", "subcategory": "Networking", @@ -15075,8 +15329,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", @@ -15092,8 +15346,8 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#avoid-combining-traffic-manager-and-front-door", "service": "AVS", "services": [ - "ExpressRoute", "Storage", + "ExpressRoute", "AVS" ], "severity": "Medium", @@ -15109,8 +15363,8 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-the-same-domain-name-on-front-door-and-your-origin", "service": "AVS", "services": [ - "ExpressRoute", "Storage", + "ExpressRoute", "AVS" ], "severity": "Medium", @@ -16003,8 +16257,8 @@ "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/sql-database-security-baseline#br-1-ensure-regular-automated-backups", "services": [ "SQL", - "Storage", - "Backup" + "Backup", + "Storage" ], "severity": "Medium", "subcategory": "Backup", @@ -16020,8 +16274,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/automated-backups-overview?tabs=single-database&view=azuresql#backup-storage-redundancy", "services": [ "SQL", - "Storage", - "Backup" + "Backup", + "Storage" ], "severity": "Low", "subcategory": "Backup", @@ -16082,8 +16336,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/threat-detection-configure", "services": [ "SQL", - "EventHubs", - "Defender" + "Defender", + "EventHubs" ], "severity": "High", "subcategory": "Advanced Threat Protection", @@ -16098,9 +16352,9 @@ "id": "E02.01", "link": "https://learn.microsoft.com/azure/azure-sql/database/azure-defender-for-sql?view=azuresql#enable-microsoft-defender-for-sql ", "services": [ + "Subscriptions", "SQL", - "Defender", - "Subscriptions" + "Defender" ], "severity": "High", "subcategory": "Defender for Azure SQL", @@ -16115,9 +16369,9 @@ "id": "E02.02", "link": "https://learn.microsoft.com/azure/azure-sql/database/threat-detection-configure", "services": [ - "Monitor", "SQL", - "Defender" + "Defender", + "Monitor" ], "severity": "High", "subcategory": "Defender for Azure SQL", @@ -16132,9 +16386,9 @@ "id": "E03.01", "link": "https://learn.microsoft.com/azure/defender-for-cloud/sql-azure-vulnerability-assessment-overview", "services": [ - "Monitor", "SQL", - "Defender" + "Defender", + "Monitor" ], "severity": "High", "subcategory": "Vulnerability Assessment", @@ -16181,8 +16435,8 @@ "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": [ "SQL", - "Storage", - "AKV" + "AKV", + "Storage" ], "severity": "Low", "subcategory": "Column Encryption", @@ -16198,8 +16452,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/transparent-data-encryption-byok-create-server", "services": [ "SQL", - "Storage", - "Backup" + "Backup", + "Storage" ], "severity": "High", "subcategory": "Transparent Data Encryption", @@ -16261,9 +16515,9 @@ "id": "G01.02", "link": "https://learn.microsoft.com/azure/azure-sql/database/security-best-practice?view=azuresql#central-management-for-identities", "services": [ - "Monitor", "SQL", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Azure Active Directory", @@ -16294,11 +16548,11 @@ "id": "G02.01", "link": "https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview", "services": [ + "AKV", + "ACR", "SQL", "RBAC", - "ACR", - "Entra", - "AKV" + "Entra" ], "severity": "Low", "subcategory": "Managed Identities", @@ -16346,8 +16600,8 @@ "link": "https://learn.microsoft.com/sql/relational-databases/security/ledger/ledger-digest-management", "services": [ "SQL", - "Storage", - "AzurePolicy" + "AzurePolicy", + "Storage" ], "severity": "Medium", "subcategory": "Database Digest", @@ -16409,8 +16663,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/auditing-overview", "services": [ "SQL", - "Storage", - "AzurePolicy" + "AzurePolicy", + "Storage" ], "severity": "Medium", "subcategory": "Auditing", @@ -16425,12 +16679,12 @@ "id": "I01.02", "link": "https://learn.microsoft.com/azure/azure-sql/database/auditing-overview", "services": [ + "Backup", "EventHubs", + "Monitor", "Storage", "SQL", - "Monitor", - "Entra", - "Backup" + "Entra" ], "severity": "Low", "subcategory": "Auditing", @@ -16445,11 +16699,11 @@ "id": "I01.03", "link": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log", "services": [ + "Subscriptions", "EventHubs", - "Storage", - "SQL", "Monitor", - "Subscriptions" + "Storage", + "SQL" ], "severity": "Medium", "subcategory": "Auditing", @@ -16464,8 +16718,8 @@ "id": "I02.01", "link": "https://learn.microsoft.com/azure/azure-sql/database/auditing-overview", "services": [ - "Monitor", - "SQL" + "SQL", + "Monitor" ], "severity": "Medium", "subcategory": "SIEM/SOAR", @@ -16480,8 +16734,8 @@ "id": "I02.02", "link": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log", "services": [ - "Monitor", - "SQL" + "SQL", + "Monitor" ], "severity": "Medium", "subcategory": "SIEM/SOAR", @@ -16512,8 +16766,8 @@ "id": "J01.01", "link": "https://learn.microsoft.com/azure/azure-sql/database/network-access-controls-overview", "services": [ - "SQL", - "PrivateLink" + "PrivateLink", + "SQL" ], "severity": "High", "subcategory": "Connectivity", @@ -16528,8 +16782,8 @@ "id": "J01.02", "link": "https://learn.microsoft.com/azure/azure-sql/database/connectivity-architecture", "services": [ - "SQL", "PrivateLink", + "SQL", "AzurePolicy" ], "severity": "Low", @@ -16562,8 +16816,8 @@ "link": "https://learn.microsoft.com/sql/relational-databases/system-stored-procedures/sp-invoke-external-rest-endpoint-transact-sql", "services": [ "SQL", - "EventHubs", - "APIM" + "APIM", + "EventHubs" ], "severity": "Medium", "subcategory": "Outbound Control", @@ -16594,11 +16848,11 @@ "id": "J03.01", "link": "https://learn.microsoft.com/azure/azure-sql/database/private-endpoint-overview?view=azuresql#disable-public-access-to-your-logical-server", "services": [ - "PrivateLink", - "SQL", - "Firewall", "Monitor", - "VNet" + "Firewall", + "VNet", + "SQL", + "PrivateLink" ], "severity": "Medium", "subcategory": "Private Access", @@ -16613,8 +16867,8 @@ "id": "J03.02", "link": "https://learn.microsoft.com/azure/azure-sql/database/private-endpoint-overview?view=azuresql#disable-public-access-to-your-logical-server", "services": [ - "SQL", "PrivateLink", + "SQL", "VNet" ], "severity": "High", @@ -16630,9 +16884,9 @@ "id": "J03.03", "link": "https://learn.microsoft.com/azure/private-link/private-endpoint-overview#network-security-of-private-endpoints", "services": [ + "PrivateLink", "SQL", - "VNet", - "PrivateLink" + "VNet" ], "severity": "Medium", "subcategory": "Private Access", @@ -16647,8 +16901,8 @@ "id": "J03.04", "link": "https://learn.microsoft.com/azure/azure-sql/managed-instance/connectivity-architecture-overview", "services": [ - "ExpressRoute", "SQL", + "ExpressRoute", "VNet" ], "severity": "Medium", @@ -16665,8 +16919,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/database/network-access-controls-overview?view=azuresql#ip-vs-virtual-network-firewall-rules", "services": [ "SQL", - "VNet", - "AzurePolicy" + "AzurePolicy", + "VNet" ], "severity": "High", "subcategory": "Public Access", @@ -16714,8 +16968,8 @@ "link": "https://learn.microsoft.com/azure/azure-sql/managed-instance/public-endpoint-overview", "services": [ "SQL", - "VNet", - "AzurePolicy" + "AzurePolicy", + "VNet" ], "severity": "High", "subcategory": "Public Access", @@ -16791,8 +17045,8 @@ "id": "A01.01", "link": "https://learn.microsoft.com/azure/architecture/guide/multitenant/considerations/tenancy-models", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "subcategory": "Azure Monitor - enforce data collection rules", "text": "Data collection rules in Azure Monitor -https://learn.microsoft.com/azure/azure-monitor/essentials/data-collection-rule-overview", @@ -16847,8 +17101,8 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", "services": [ "Cost", - "Backup", - "Storage" + "Storage", + "Backup" ], "subcategory": "delete/archive", "text": "delete or archive unused resources (old backups, logs, storage accounts, etc...)", @@ -16861,10 +17115,10 @@ "id": "A03.04", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement#design-recommendations", "services": [ - "ASR", "Cost", - "Backup", - "Storage" + "Storage", + "ASR", + "Backup" ], "subcategory": "delete/archive", "text": "consider a good balance between site recovery storage and backup for non mission critical applications", @@ -16877,8 +17131,8 @@ "id": "A04.01", "link": "https://learn.microsoft.com/azure/cost-management-billing/manage/direct-ea-administration#manage-notification-contacts", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "subcategory": "Log Analytics retention for workspaces", "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 ", @@ -16936,10 +17190,10 @@ "id": "A08.01", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement#design-considerations", "services": [ - "VM", "Cost", - "Backup", - "Storage" + "Storage", + "VM", + "Backup" ], "subcategory": "stopped/deallocated VMs: check disks", "text": "check that the disks are really needed, if not: delete. If they are needed, find lower storage tiers or use backup -", @@ -17008,9 +17262,9 @@ "id": "B03.01", "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" + "Storage", + "VM" ], "subcategory": "db optimization", "text": "optimizing the DB queries will increase performance and allow better right-sizing of storage and VMs", @@ -17050,8 +17304,8 @@ "id": "C01.02", "link": "https://learn.microsoft.com/azure/governance/policy/overview", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "subcategory": "Advisor", "text": "make sure advisor is configured for VM right sizing ", @@ -17077,8 +17331,8 @@ "id": "C02.02", "link": "https://learn.microsoft.com/azure/governance/policy/overview", "services": [ - "Monitor", - "Cost" + "Cost", + "Monitor" ], "subcategory": "Automation", "text": "set up cost alerts for applications that have variable costs (ideally for all of them)", @@ -17210,8 +17464,8 @@ "id": "C06.01", "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/concept-activity-logs-azure-monitor", "services": [ - "ACR", - "Cost" + "Cost", + "ACR" ], "subcategory": "free services", "text": "Take advantage of Azure free services: Azure offers a number of free services, such as DevOps, Azure Container Registry, and Azure Logic Apps, that can help you save costs on development and operations. ", @@ -17264,9 +17518,9 @@ "id": "D02.01", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/manage/centralize-operations", "services": [ - "VM", - "SQL", "Cost", + "SQL", + "VM", "AzurePolicy" ], "subcategory": "check AHUB is applied to all Windows VMs, RHEL and SQL", @@ -17294,8 +17548,8 @@ "id": "D04.01", "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" ], "subcategory": "Functions", "text": "saving plans will provide 17% on select app service plans", @@ -17308,8 +17562,8 @@ "id": "D05.01", "link": "https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-groups-create-azure-portal", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "subcategory": "planning", "text": "consolidate reserved VM families with flexibility option (no more than 4-5 families)", @@ -17323,9 +17577,9 @@ "id": "D06.01", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access#prerequisites-for-a-landing-zone---design-recommendations", "services": [ + "Cost", "VM", - "ARS", - "Cost" + "ARS" ], "subcategory": "reservations/savings plans", "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.", @@ -17378,8 +17632,8 @@ "id": "D08.01", "link": "https://learn.microsoft.com/azure/architecture/reference-architectures/identity/adds-extend-domain", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "subcategory": "reserve VMs with normalized and rationalized sizes", "text": "after the right-sizing optimization", @@ -17392,8 +17646,8 @@ "id": "D09.01", "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy", "services": [ - "SQL", "Cost", + "SQL", "AzurePolicy" ], "subcategory": "SQL Database AHUB", @@ -17407,9 +17661,9 @@ "id": "D10.01", "link": "https://learn.microsoft.com/azure/active-directory/roles/best-practices", "services": [ - "VM", + "Cost", "SQL", - "Cost" + "VM" ], "subcategory": "SQL Database Reservations", "text": "the VM + licence part discount (ahub+3YRI) is around 70% discount", @@ -17477,8 +17731,8 @@ "id": "E02.01", "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#send-logs-to-microsoft-sentinel", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "subcategory": "Autoscale", "text": "consider using a VMSS to match demand rather than flat sizing", @@ -17491,8 +17745,8 @@ "id": "E02.02", "link": "https://learn.microsoft.com/azure/reliability/cross-region-replication-azure", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "subcategory": "Autoscale", "text": "use AKS autoscaler to match your clusters usage (make sure the pods requirements match the scaler)", @@ -17559,8 +17813,8 @@ "id": "E04.01", "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "services": [ - "VM", "Cost", + "VM", "LoadBalancer" ], "subcategory": "databricks", @@ -17684,9 +17938,9 @@ "id": "E06.02", "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment", "services": [ + "Cost", "FrontDoor", - "EventHubs", - "Cost" + "EventHubs" ], "subcategory": "Networking", "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.", @@ -17699,9 +17953,9 @@ "id": "E06.03", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-setup-guide/monitoring-reporting?tabs=AzureMonitor", "services": [ - "FrontDoor", + "Cost", "AppSvc", - "Cost" + "FrontDoor" ], "subcategory": "Networking", "text": "Frontdoor -Route to something that returns nothingEither 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.", @@ -17796,9 +18050,9 @@ "id": "E09.05", "link": "https://learn.microsoft.com/azure/site-recovery/site-recovery-overview", "services": [ - "ASR", "Cost", - "Storage" + "Storage", + "ASR" ], "subcategory": "Storage", "text": "for ASR, consider using Standard SSD disks if the RPO/RTO and replication throughput allow it", @@ -17839,9 +18093,9 @@ "id": "E11.01", "link": "https://learn.microsoft.com/azure/reliability/availability-zones-overview", "services": [ - "Monitor", + "Cost", "EventHubs", - "Cost" + "Monitor" ], "subcategory": "Synapse", "text": "Create budgets to manage costs and create alerts that automatically notify stakeholders of spending anomalies and overspending risks.", @@ -17868,8 +18122,8 @@ "id": "E11.03", "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", "services": [ - "SQL", - "Cost" + "Cost", + "SQL" ], "subcategory": "Synapse", "text": "Control costs for a dedicated SQL pool by pausing the resource when it is not in use.", @@ -17922,8 +18176,8 @@ "id": "E12.01", "link": "https://learn.microsoft.com/azure/application-gateway/overview-v2", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "subcategory": "VM", "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.", @@ -17937,8 +18191,8 @@ "id": "E12.02", "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-overview", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "subcategory": "VM", "text": "right-sizing all VMs", @@ -17951,8 +18205,8 @@ "id": "E12.03", "link": "https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "subcategory": "VM", "text": "swap VM sized with normalized and most recent sizes", @@ -17966,8 +18220,8 @@ "id": "E12.04", "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "services": [ - "VM", "Cost", + "VM", "Monitor" ], "subcategory": "VM", @@ -17982,8 +18236,8 @@ "id": "E12.05", "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "services": [ - "VM", - "Cost" + "Cost", + "VM" ], "subcategory": "VM", "text": "containerizing an application can improve VM density and save money on scaling it", @@ -18076,8 +18330,8 @@ "link": "https://learn.microsoft.com/azure/application-gateway/configuration-infrastructure#size-of-the-subnet", "service": "App Gateway", "services": [ - "VNet", - "AppGW" + "AppGW", + "VNet" ], "severity": "Medium", "subcategory": "App Gateway", @@ -18094,12 +18348,12 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "App Gateway", "services": [ - "NVA", - "WAF", - "Entra", + "Subscriptions", "VNet", + "NVA", "AppGW", - "Subscriptions" + "Entra", + "WAF" ], "severity": "Medium", "subcategory": "App Gateway", @@ -18164,9 +18418,9 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "service": "Front Door", "services": [ - "WAF", "FrontDoor", - "AzurePolicy" + "AzurePolicy", + "WAF" ], "severity": "Medium", "subcategory": "Front Door", @@ -18182,10 +18436,10 @@ "link": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview", "service": "Front Door", "services": [ - "WAF", - "FrontDoor", "AppGW", - "AzurePolicy" + "WAF", + "AzurePolicy", + "FrontDoor" ], "severity": "Medium", "subcategory": "App delivery", @@ -18218,8 +18472,8 @@ "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy#how-application-proxy-works", "service": "Entra", "services": [ - "AVD", - "Entra" + "Entra", + "AVD" ], "severity": "Low", "subcategory": "App delivery", @@ -18253,9 +18507,9 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings", "service": "Front Door", "services": [ - "WAF", + "Storage", "FrontDoor", - "Storage" + "WAF" ], "severity": "High", "subcategory": "Front Door", @@ -18271,8 +18525,8 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#avoid-combining-traffic-manager-and-front-door", "service": "Front Door", "services": [ - "TrafficManager", - "FrontDoor" + "FrontDoor", + "TrafficManager" ], "severity": "High", "subcategory": "Front Door", @@ -18369,8 +18623,8 @@ "link": "https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates", "service": "Front Door", "services": [ - "FrontDoor", "Cost", + "FrontDoor", "AKV" ], "severity": "High", @@ -18386,8 +18640,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", @@ -18434,8 +18688,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", @@ -18451,8 +18705,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", @@ -18468,8 +18722,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#use-prevention-mode", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "High", "subcategory": "Front Door", @@ -18485,8 +18739,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", @@ -18502,8 +18756,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", @@ -18518,8 +18772,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", @@ -18534,8 +18788,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", @@ -18550,8 +18804,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", @@ -18566,8 +18820,8 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-best-practices#geo-filter-traffic", "service": "Front Door", "services": [ - "WAF", - "FrontDoor" + "FrontDoor", + "WAF" ], "severity": "Low", "subcategory": "Front Door", @@ -18582,8 +18836,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", @@ -18615,8 +18869,8 @@ "link": "https://learn.microsoft.com/azure/storage/common/storage-private-endpoints", "service": "Azure Storage", "services": [ - "Storage", - "PrivateLink" + "PrivateLink", + "Storage" ], "severity": "High", "subcategory": "Networking", @@ -18632,8 +18886,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", @@ -18748,8 +19002,8 @@ "service": "Azure Storage", "services": [ "Storage", - "Subscriptions", - "AzurePolicy" + "AzurePolicy", + "Subscriptions" ], "severity": "High", "subcategory": "Data Availability, Compliance", @@ -18829,8 +19083,8 @@ "id": "A11.02", "service": "Azure Storage", "services": [ - "RBAC", "Storage", + "RBAC", "Entra" ], "severity": "Medium", @@ -18864,10 +19118,10 @@ "link": "https://learn.microsoft.com/rest/api/storageservices/authorize-with-shared-key", "service": "Azure Storage", "services": [ - "Monitor", "Storage", "Entra", - "AKV" + "AKV", + "Monitor" ], "severity": "High", "subcategory": "Identity and Access Management", @@ -18883,10 +19137,10 @@ "link": "https://learn.microsoft.com/azure/storage/blobs/blob-storage-monitoring-scenarios#audit-account-activity", "service": "Azure Storage", "services": [ - "Monitor", "Storage", + "AzurePolicy", "AKV", - "AzurePolicy" + "Monitor" ], "severity": "High", "subcategory": "Monitoring", @@ -18903,9 +19157,9 @@ "service": "Azure Storage", "services": [ "Storage", + "AzurePolicy", "Entra", - "AKV", - "AzurePolicy" + "AKV" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -18922,8 +19176,8 @@ "service": "Azure Storage", "services": [ "Storage", - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -18940,9 +19194,9 @@ "service": "Azure Storage", "services": [ "Storage", + "AzurePolicy", "Entra", - "AKV", - "AzurePolicy" + "AKV" ], "severity": "Medium", "subcategory": "Identity and Access Management", @@ -18992,8 +19246,8 @@ "service": "Azure Storage", "services": [ "Storage", - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "High", "subcategory": "Identity and Access Management", @@ -19059,8 +19313,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", @@ -19268,10 +19522,10 @@ "id": "02.02.01", "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-multi-region", "services": [ - "TrafficManager", "AKS", "FrontDoor", - "LoadBalancer" + "LoadBalancer", + "TrafficManager" ], "severity": "Medium", "subcategory": "High Availability", @@ -19321,8 +19575,8 @@ "link": "https://learn.microsoft.com/azure/aks/operator-best-practices-scheduler", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "simple": -1, @@ -19340,8 +19594,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", @@ -19372,8 +19626,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", @@ -19389,8 +19643,8 @@ "link": "https://learn.microsoft.com/azure/aks/scale-down-mode", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "subcategory": "Cost", @@ -19406,8 +19660,8 @@ "link": "https://learn.microsoft.com/azure/aks/gpu-multi-instance", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Medium", "subcategory": "Cost", @@ -19423,8 +19677,8 @@ "link": "https://learn.microsoft.com/azure/aks/start-stop-nodepools", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "subcategory": "Cost", @@ -19495,8 +19749,8 @@ "security": 1, "service": "AKS", "services": [ - "AKS", - "ACR" + "ACR", + "AKS" ], "severity": "Medium", "simple": -1, @@ -19889,8 +20143,8 @@ "security": 1, "service": "AKS", "services": [ - "AKS", "ACR", + "AKS", "AppGW" ], "severity": "Medium", @@ -19980,10 +20234,10 @@ "security": 1, "service": "AKS", "services": [ + "PrivateLink", "AKS", - "Cost", "VNet", - "PrivateLink" + "Cost" ], "severity": "Medium", "simple": -1, @@ -20299,8 +20553,8 @@ "security": 2, "service": "AKS", "services": [ - "WAF", - "AKS" + "AKS", + "WAF" ], "severity": "High", "simple": -1, @@ -20320,8 +20574,8 @@ "service": "AKS", "services": [ "AKS", - "VNet", - "DDoS" + "DDoS", + "VNet" ], "severity": "Medium", "subcategory": "Security", @@ -20372,8 +20626,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-metric-alerts", "service": "AKS", "services": [ - "Monitor", - "AKS" + "AKS", + "Monitor" ], "severity": "High", "simple": -1, @@ -20604,8 +20858,8 @@ "link": "https://learn.microsoft.com/azure/aks/monitor-aks", "service": "AKS", "services": [ - "Monitor", - "AKS" + "AKS", + "Monitor" ], "severity": "Low", "subcategory": "Compliance", @@ -20637,8 +20891,8 @@ "link": "https://learn.microsoft.com/azure/aks/spot-node-pool", "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "simple": -1, @@ -20656,8 +20910,8 @@ "scale": 1, "service": "AKS", "services": [ - "AKS", - "Cost" + "Cost", + "AKS" ], "severity": "Low", "simple": -1, @@ -20674,8 +20928,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-overview", "service": "AKS", "services": [ - "Monitor", - "AKS" + "AKS", + "Monitor" ], "severity": "High", "simple": -1, @@ -20693,8 +20947,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/insights/container-insights-overview", "service": "AKS", "services": [ - "Monitor", - "AKS" + "AKS", + "Monitor" ], "severity": "High", "simple": -1, @@ -20711,8 +20965,8 @@ "link": "https://learn.microsoft.com/azure/azure-monitor/containers/container-insights-analyze", "service": "AKS", "services": [ - "Monitor", - "AKS" + "AKS", + "Monitor" ], "severity": "Medium", "simple": -1, @@ -20729,8 +20983,8 @@ "link": "https://learn.microsoft.com/azure/aks/configure-azure-cni", "service": "AKS", "services": [ - "Monitor", - "AKS" + "AKS", + "Monitor" ], "severity": "Medium", "simple": -1, @@ -20748,10 +21002,10 @@ "link": "https://learn.microsoft.com/azure/virtual-machines/premium-storage-performance", "service": "AKS", "services": [ - "EventHubs", - "Storage", "AKS", "Monitor", + "EventHubs", + "Storage", "ServiceBus" ], "severity": "Medium", @@ -20769,10 +21023,10 @@ "link": "https://learn.microsoft.com/azure/aks/load-balancer-standard", "service": "AKS", "services": [ - "Monitor", "AKS", "NVA", - "LoadBalancer" + "LoadBalancer", + "Monitor" ], "severity": "Medium", "simple": -1, @@ -20789,8 +21043,8 @@ "link": "https://learn.microsoft.com/azure/aks/aks-resource-health", "service": "AKS", "services": [ - "Monitor", - "AKS" + "AKS", + "Monitor" ], "severity": "Medium", "subcategory": "Monitoring", @@ -21523,8 +21777,8 @@ "id": "05.01.01", "link": "https://learn.microsoft.com/azure/backup/back-up-azure-stack-hyperconverged-infrastructure-virtual-machines", "services": [ - "VM", "ASR", + "VM", "Backup" ], "severity": "High", @@ -21809,8 +22063,8 @@ "id": "A01.02", "link": "https://learn.microsoft.com/azure/security-center/enable-azure-defender", "services": [ - "Monitor", - "Defender" + "Defender", + "Monitor" ], "severity": "High", "subcategory": "Pricing & Settings", @@ -21852,8 +22106,8 @@ "id": "A01.05", "link": "https://learn.microsoft.com/azure/security-center/security-center-enable-data-collection", "services": [ - "Defender", - "AzurePolicy" + "AzurePolicy", + "Defender" ], "severity": "Medium", "subcategory": "Pricing & Settings", @@ -21867,8 +22121,8 @@ "id": "A01.06", "link": "https://learn.microsoft.com/azure/security-center/security-center-provide-security-contact-details", "services": [ - "Defender", - "AzurePolicy" + "AzurePolicy", + "Defender" ], "severity": "Low", "subcategory": "Pricing & Settings", @@ -21910,8 +22164,8 @@ "id": "A01.09", "link": "https://learn.microsoft.com/azure/security-center/continuous-export?tabs=azure-portal", "services": [ - "EventHubs", - "Defender" + "Defender", + "EventHubs" ], "severity": "High", "subcategory": "Pricing & Settings", @@ -21925,9 +22179,9 @@ "id": "A01.10", "link": "https://learn.microsoft.com/azure/security-center/continuous-export?tabs=azure-portal", "services": [ - "Monitor", + "Sentinel", "Defender", - "Sentinel" + "Monitor" ], "severity": "Medium", "subcategory": "Pricing & Settings", @@ -21969,9 +22223,9 @@ "id": "A01.13", "link": "https://learn.microsoft.com/azure/active-directory/app-proxy/application-proxy-integrate-with-microsoft-cloud-application-security", "services": [ - "Monitor", + "Entra", "Defender", - "Entra" + "Monitor" ], "severity": "Low", "subcategory": "Pricing & Settings", @@ -22014,8 +22268,8 @@ "id": "A03.01", "link": "https://learn.microsoft.com/azure/defender-for-cloud/tutorial-security-incident", "services": [ - "Monitor", - "Defender" + "Defender", + "Monitor" ], "severity": "Medium", "subcategory": "Security Alerts", @@ -22103,8 +22357,8 @@ "id": "A09.01", "link": "https://techcommunity.microsoft.com/t5/azure-network-security/azure-firewall-manager-is-now-integrated-with-azure-security/ba-p/2228679", "services": [ - "Firewall", - "Defender" + "Defender", + "Firewall" ], "severity": "Medium", "subcategory": "Firewall Manager", @@ -22119,9 +22373,9 @@ "id": "A09.02", "link": "https://learn.microsoft.com/azure/security/fundamentals/network-best-practices", "services": [ - "Firewall", + "Defender", "VNet", - "Defender" + "Firewall" ], "severity": "Medium", "subcategory": "Firewall Manager", @@ -22135,9 +22389,9 @@ "id": "A09.03", "link": "https://azure.microsoft.com/blog/how-azure-security-center-detects-ddos-attack-using-cyber-threat-intelligence/", "services": [ - "Firewall", + "DDoS", "Defender", - "DDoS" + "Firewall" ], "severity": "Medium", "subcategory": "Firewall Manager", @@ -22182,9 +22436,9 @@ "id": "B01.02", "link": "https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses", "services": [ + "Firewall", "VM", - "EventHubs", - "Firewall" + "EventHubs" ], "severity": "High", "subcategory": "Public IPs", @@ -22273,8 +22527,8 @@ "id": "B02.05", "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-nsg-manage-log", "services": [ - "VNet", - "Sentinel" + "Sentinel", + "VNet" ], "severity": "Medium", "subcategory": "NSG", @@ -22303,8 +22557,8 @@ "id": "B03.02", "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview", "services": [ - "Firewall", - "VNet" + "VNet", + "Firewall" ], "severity": "High", "subcategory": "UDR", @@ -22405,8 +22659,8 @@ "id": "B04.06", "link": "https://learn.microsoft.com/azure/private-link/private-endpoint-overview", "services": [ - "VNet", - "PrivateLink" + "PrivateLink", + "VNet" ], "severity": "High", "subcategory": "Virtual Networks", @@ -22420,8 +22674,8 @@ "id": "B04.07", "link": "https://learn.microsoft.com/azure/virtual-network/monitor-virtual-network", "services": [ - "Monitor", - "VNet" + "VNet", + "Monitor" ], "severity": "High", "subcategory": "Virtual Networks", @@ -22436,8 +22690,8 @@ "link": "https://learn.microsoft.com/azure/virtual-network/kubernetes-network-policies", "services": [ "AKS", - "VNet", - "AzurePolicy" + "AzurePolicy", + "VNet" ], "severity": "High", "subcategory": "Virtual Networks", @@ -22451,8 +22705,8 @@ "id": "B04.09", "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-scenario-udr-gw-nva", "services": [ - "NVA", - "VNet" + "VNet", + "NVA" ], "severity": "High", "subcategory": "Virtual Networks", @@ -22466,9 +22720,9 @@ "id": "B04.10", "link": "https://learn.microsoft.com/azure/virtual-network/monitor-virtual-network", "services": [ - "Monitor", + "Sentinel", "VNet", - "Sentinel" + "Monitor" ], "severity": "High", "subcategory": "Virtual Networks", @@ -22497,8 +22751,8 @@ "id": "B06.01", "link": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about", "services": [ - "VWAN", - "RBAC" + "RBAC", + "VWAN" ], "severity": "High", "subcategory": "Virtual WAN", @@ -22542,9 +22796,9 @@ "id": "B07.02", "link": "https://learn.microsoft.com/azure/application-gateway/configuration-front-end-ip", "services": [ - "WAF", + "AppGW", "EventHubs", - "AppGW" + "WAF" ], "severity": "High", "subcategory": "Application Gateway", @@ -22558,9 +22812,9 @@ "id": "B07.03", "link": "https://learn.microsoft.com/azure/application-gateway/configuration-front-end-ip", "services": [ - "WAF", + "AppGW", "EventHubs", - "AppGW" + "WAF" ], "severity": "High", "subcategory": "Application Gateway", @@ -22603,9 +22857,9 @@ "id": "B08.02", "link": "https://learn.microsoft.com/security/benchmark/azure/baselines/front-door-security-baseline?toc=/azure/frontdoor/TOC.json", "services": [ - "WAF", "FrontDoor", - "AzurePolicy" + "AzurePolicy", + "WAF" ], "severity": "High", "subcategory": "FrontDoor", @@ -22648,8 +22902,8 @@ "id": "B08.05", "link": "https://learn.microsoft.com/azure/frontdoor/front-door-diagnostics", "services": [ - "FrontDoor", - "Sentinel" + "Sentinel", + "FrontDoor" ], "severity": "High", "subcategory": "FrontDoor", @@ -22790,8 +23044,8 @@ "id": "C02.04", "link": "https://learn.microsoft.com/azure/architecture/framework/security/design-admins#managed-accounts-for-admins", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "High", "subcategory": "Privileged administration", @@ -22819,8 +23073,8 @@ "id": "C02.06", "link": "https://learn.microsoft.com/azure/architecture/framework/security/design-admins#admin-workstation-security", "services": [ - "Monitor", - "Entra" + "Entra", + "Monitor" ], "severity": "Medium", "subcategory": "Privileged administration", @@ -22961,8 +23215,8 @@ "id": "C06.01", "link": "https://learn.microsoft.com/azure/active-directory/authentication/tutorial-enable-sspr", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "High", "subcategory": "Password Reset", @@ -23046,9 +23300,9 @@ "id": "C08.01", "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-monitoring", "services": [ - "Monitor", + "Sentinel", "Entra", - "Sentinel" + "Monitor" ], "severity": "High", "subcategory": "Diagnostic Settings", @@ -23090,8 +23344,8 @@ "id": "C10.01", "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/concept-conditional-access-policy-common", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "High", "subcategory": "Conditional Access Policies", @@ -23105,8 +23359,8 @@ "id": "C10.02", "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/location-condition", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "Medium", "subcategory": "Conditional Access Policies", @@ -23120,8 +23374,8 @@ "id": "C10.03", "link": "https://learn.microsoft.com/azure/active-directory/authentication/tutorial-enable-azure-mfa", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "High", "subcategory": "Conditional Access Policies", @@ -23135,8 +23389,8 @@ "id": "C10.04", "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/howto-conditional-access-policy-admin-mfa", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "Medium", "subcategory": "Conditional Access Policies", @@ -23150,8 +23404,8 @@ "id": "C10.05", "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/howto-conditional-access-policy-azure-management", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "High", "subcategory": "Conditional Access Policies", @@ -23165,8 +23419,8 @@ "id": "C10.06", "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/howto-conditional-access-policy-block-legacy", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "High", "subcategory": "Conditional Access Policies", @@ -23180,8 +23434,8 @@ "id": "C10.07", "link": "https://learn.microsoft.com/azure/active-directory/conditional-access/require-managed-devices", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "High", "subcategory": "Conditional Access Policies", @@ -23196,8 +23450,8 @@ "id": "C11.01", "link": "https://devblogs.microsoft.com/premier-developer/azure-active-directory-automating-guest-user-management/", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "Medium", "subcategory": "Guest users", @@ -23225,8 +23479,8 @@ "id": "C13.01", "link": "https://learn.microsoft.com/azure/active-directory/roles/security-emergency-access", "services": [ - "Entra", - "AzurePolicy" + "AzurePolicy", + "Entra" ], "severity": "Medium", "subcategory": "Break Glass Accounts", @@ -23297,8 +23551,8 @@ "id": "D02.02", "link": "https://learn.microsoft.com/azure/backup/backup-azure-vms-first-look-arm", "services": [ - "VM", - "ASR" + "ASR", + "VM" ], "severity": "Medium", "subcategory": "High Availability ", @@ -23557,8 +23811,8 @@ "id": "E01.01", "link": "https://learn.microsoft.com/azure/sentinel/quickstart-onboard", "services": [ - "Monitor", - "Sentinel" + "Sentinel", + "Monitor" ], "severity": "High", "subcategory": "Architecture ", @@ -23586,9 +23840,9 @@ "id": "E01.03", "link": "https://learn.microsoft.com/azure/sentinel/multiple-workspace-view", "services": [ - "Monitor", "ACR", - "Sentinel" + "Sentinel", + "Monitor" ], "severity": "Medium", "subcategory": "Architecture ", @@ -23644,8 +23898,8 @@ "id": "E05.01", "link": "https://learn.microsoft.com/azure/sentinel/connect-azure-active-directory", "services": [ - "Entra", - "Sentinel" + "Sentinel", + "Entra" ], "severity": "High", "subcategory": "Data Connectors", @@ -23659,8 +23913,8 @@ "id": "E05.02", "link": "https://learn.microsoft.com/azure/sentinel/data-connectors-reference#azure-active-directory-identity-protection", "services": [ - "Entra", - "Sentinel" + "Sentinel", + "Entra" ], "severity": "High", "subcategory": "Data Connectors", @@ -23688,8 +23942,8 @@ "id": "E05.04", "link": "https://learn.microsoft.com/azure/sentinel/connect-defender-for-cloud", "services": [ - "Defender", - "Sentinel" + "Sentinel", + "Defender" ], "severity": "High", "subcategory": "Data Connectors", @@ -23703,8 +23957,8 @@ "id": "E05.05", "link": "https://learn.microsoft.com/azure/sentinel/data-connectors-reference#azure-firewall", "services": [ - "Firewall", - "Sentinel" + "Sentinel", + "Firewall" ], "severity": "High", "subcategory": "Data Connectors", @@ -23873,8 +24127,8 @@ "id": "F03.01", "link": "https://learn.microsoft.com/azure/firewall/firewall-diagnostics", "services": [ - "Monitor", - "Firewall" + "Firewall", + "Monitor" ], "severity": "Medium", "subcategory": "Diagnostic Settings", @@ -23888,8 +24142,8 @@ "id": "F04.01", "link": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview", "services": [ - "Firewall", - "VNet" + "VNet", + "Firewall" ], "severity": "High", "subcategory": "Firewall Manager", @@ -23904,8 +24158,8 @@ "link": "https://techcommunity.microsoft.com/t5/azure-network-security/role-based-access-control-for-azure-firewall/ba-p/2245598", "services": [ "RBAC", - "Firewall", - "AzurePolicy" + "AzurePolicy", + "Firewall" ], "severity": "High", "subcategory": "Firewall Manager", @@ -23919,8 +24173,8 @@ "id": "F04.03", "link": "https://learn.microsoft.com/azure/firewall-manager/policy-overview", "services": [ - "Firewall", - "AzurePolicy" + "AzurePolicy", + "Firewall" ], "severity": "High", "subcategory": "Firewall Manager", @@ -23934,8 +24188,8 @@ "id": "F04.04", "link": "https://learn.microsoft.com/azure/firewall/rule-processing", "services": [ - "Firewall", - "AzurePolicy" + "AzurePolicy", + "Firewall" ], "severity": "High", "subcategory": "Firewall Manager", @@ -23949,8 +24203,8 @@ "id": "F04.05", "link": "https://learn.microsoft.com/azure/firewall/rule-processing", "services": [ - "Firewall", - "AzurePolicy" + "AzurePolicy", + "Firewall" ], "severity": "High", "subcategory": "Firewall Manager", @@ -23964,8 +24218,8 @@ "id": "F04.06", "link": "https://learn.microsoft.com/azure/firewall/rule-processing", "services": [ - "Firewall", - "AzurePolicy" + "AzurePolicy", + "Firewall" ], "severity": "High", "subcategory": "Firewall Manager", @@ -23979,8 +24233,8 @@ "id": "F04.07", "link": "https://learn.microsoft.com/azure/firewall/features", "services": [ - "Firewall", - "AzurePolicy" + "AzurePolicy", + "Firewall" ], "severity": "High", "subcategory": "Firewall Manager", @@ -24079,8 +24333,8 @@ "id": "F05.01", "link": "https://learn.microsoft.com/azure/security/fundamentals/ddos-best-practices", "services": [ - "Firewall", - "DDoS" + "DDoS", + "Firewall" ], "severity": "Medium", "subcategory": "DDOS Protection", @@ -24106,8 +24360,8 @@ "guid": "aa359271-8e6e-4205-8725-769e46691e88", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#azure-subscription-and-service-limits", "services": [ - "Arc", - "Entra" + "Entra", + "Arc" ], "severity": "Medium", "subcategory": "Capacity Planning", @@ -24121,8 +24375,8 @@ "guid": "deace4bb-1deb-44c6-9fc3-fc14eeaa3692", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#azure-resource-providers", "services": [ - "Arc", - "Subscriptions" + "Subscriptions", + "Arc" ], "severity": "High", "subcategory": "General", @@ -24191,8 +24445,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": [ - "Arc", - "Subscriptions" + "Subscriptions", + "Arc" ], "severity": "Low", "subcategory": "Organization", @@ -24206,9 +24460,9 @@ "guid": "9bf39d95-d44c-47c8-a19c-a1f6d5215ae5", "link": "https://learn.microsoft.com/azure/azure-arc/servers/security-overview#identity-and-access-control", "services": [ - "Arc", "RBAC", - "Entra" + "Entra", + "Arc" ], "severity": "Medium", "subcategory": "Access", @@ -24221,9 +24475,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", "Entra", - "AKV" + "AKV", + "Arc" ], "severity": "Low", "subcategory": "Access", @@ -24237,9 +24491,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" + "Subscriptions", + "Arc" ], "severity": "High", "subcategory": "Requirements", @@ -24253,9 +24507,9 @@ "guid": "33ee7ad6-c6d3-4733-865c-7acbe44bbe60", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#required-permissions", "services": [ - "Arc", "RBAC", - "Entra" + "Entra", + "Arc" ], "severity": "Medium", "subcategory": "Requirements", @@ -24269,9 +24523,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": [ - "Arc", "RBAC", - "Entra" + "Entra", + "Arc" ], "severity": "Medium", "subcategory": "Security", @@ -24285,9 +24539,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": [ - "Arc", "RBAC", - "Entra" + "Entra", + "Arc" ], "severity": "Medium", "subcategory": "Security", @@ -24301,9 +24555,9 @@ "guid": "65d38e53-f9cc-4bd8-9826-6abca264f9a1", "link": "https://learn.microsoft.com/azure/azure-arc/servers/prerequisites#required-permissions", "services": [ - "Arc", "RBAC", - "Entra" + "Entra", + "Arc" ], "severity": "Medium", "subcategory": "Security", @@ -24348,8 +24602,8 @@ "link": "https://learn.microsoft.com/azure/azure-arc/servers/manage-vm-extensions", "services": [ "Monitor", - "Arc", - "AzurePolicy" + "AzurePolicy", + "Arc" ], "severity": "Medium", "subcategory": "Management", @@ -24506,10 +24760,10 @@ "guid": "94174158-33ee-47ad-9c6d-3733165c7acb", "link": "https://learn.microsoft.com/azure/azure-arc/servers/private-link-security", "services": [ - "ExpressRoute", - "Arc", "PrivateLink", - "VPN" + "ExpressRoute", + "VPN", + "Arc" ], "severity": "Medium", "subcategory": "Networking", @@ -24565,9 +24819,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": [ + "PrivateLink", "Monitor", - "Arc", - "PrivateLink" + "Arc" ], "severity": "Low", "subcategory": "Networking", @@ -24580,8 +24834,8 @@ "guid": "ac6aae01-e6a8-44de-9df4-7d2d92881b1c", "link": "https://learn.microsoft.com/azure/governance/policy/", "services": [ - "Arc", - "AzurePolicy" + "AzurePolicy", + "Arc" ], "severity": "Medium", "subcategory": "Management", @@ -24607,8 +24861,8 @@ "guid": "667357c4-4967-44c5-bd85-b859c7733be2", "link": "https://learn.microsoft.com/azure/governance/machine-configuration/machine-configuration-create", "services": [ - "Arc", - "AzurePolicy" + "AzurePolicy", + "Arc" ], "severity": "Medium", "subcategory": "Management", @@ -24648,8 +24902,8 @@ "guid": "195abb91-a4ed-490d-ae2c-c84c37b6b780", "link": "https://learn.microsoft.com/azure/key-vault/general/basic-concepts", "services": [ - "Arc", - "AKV" + "AKV", + "Arc" ], "severity": "Medium", "subcategory": "Secrets", @@ -24663,10 +24917,10 @@ "guid": "6d02bfe4-564b-40d8-94a3-48726ee79d6b", "link": "https://learn.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal#option-2-create-a-new-application-secret", "services": [ - "Arc", "Storage", "Entra", - "AKV" + "AKV", + "Arc" ], "severity": "High", "subcategory": "Secrets", @@ -24680,8 +24934,8 @@ "guid": "a1a27b77-5a91-4be1-b388-ff394c2bd463", "link": "https://learn.microsoft.com/azure/azure-arc/servers/security-overview#using-disk-encryption", "services": [ - "Arc", - "AKV" + "AKV", + "Arc" ], "severity": "Medium", "subcategory": "Secrets", @@ -24722,8 +24976,8 @@ "guid": "4b69bad3-8aad-453c-a78e-1d76667357c4", "link": "https://learn.microsoft.com/azure/azure-arc/servers/managed-identity-authentication", "services": [ - "Arc", - "Entra" + "Entra", + "Arc" ], "severity": "Medium", "subcategory": "Security", @@ -24737,8 +24991,8 @@ "guid": "5a91be1f-388f-4f39-9c2b-d463cbbbc868", "link": "https://learn.microsoft.com/azure/security-center/security-center-get-started", "services": [ - "Arc", - "Defender" + "Defender", + "Arc" ], "severity": "Medium", "subcategory": "Security", @@ -24773,7 +25027,7 @@ ], "metadata": { "name": "Master checklist", - "timestamp": "January 10, 2024" + "timestamp": "January 11, 2024" }, "severities": [ { diff --git a/checklists/sap_checklist.en.json b/checklists/sap_checklist.en.json index 66439c3fd..95013363c 100644 --- a/checklists/sap_checklist.en.json +++ b/checklists/sap_checklist.en.json @@ -1,5 +1,66 @@ { "items": [ + { + "category": "Business Continuity and Disaster Recovery", + "subcategory": " ", + "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.", + "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", + "severity": "Medium", + "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment" + }, + { + "category": "Business Continuity and Disaster Recovery", + "subcategory": " ", + "text": "Use a Standard Load Balancer SKU in front of ASCS and DB clusters", + "guid": "cca275fa-a1ab-4fe9-b55d-04c3c4919cb1", + "severity": "Medium", + "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response" + }, + { + "category": "Business Continuity and Disaster Recovery", + "subcategory": " ", + "text": "Both VMs in the HA pair should be deployed in an availability set, or Availability Zones should be the same size and have the same storage configuration", + "guid": "b3d1325a-e124-4ba3-9df6-85eddce9bd3b", + "severity": "Medium", + "link": "https://www.microsoft.com/itshowcase/implementing-a-zero-trust-security-model-at-microsoft" + }, + { + "category": "Business Continuity and Disaster Recovery", + "subcategory": " ", + "text": "Native database replication technology should be used to synchronize the database in a HA pair.", + "guid": "b0cdb3b5-5eb2-4ec1-9eea-a3592829e2ed", + "severity": "Medium", + "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response" + }, + { + "category": "Business Continuity and Disaster Recovery", + "subcategory": " ", + "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", + "guid": "b2173676-aff6-4691-a493-5ada42223ece", + "severity": "Medium", + "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response" + }, + { + "category": "Business Continuity and Disaster Recovery", + "subcategory": " ", + "text": "The CIDR for the primary virtual network (VNet) shouldn't conflict or overlap with the CIDR of the DR site's Vnet", + "guid": "81b12318-1a54-4174-8583-3fb4ae3c2df7", + "severity": "Medium" + }, + { + "category": "Business Continuity and Disaster Recovery", + "subcategory": " ", + "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).", + "guid": "43165c3a-cbe0-45bb-b209-d490da477784", + "severity": "Medium" + }, + { + "category": "Business Continuity and Disaster Recovery", + "subcategory": " ", + "text": "Native database replication should be used to synchronize data to the DR site, rather than Azure Site Recovery", + "guid": "24d11678-5d2f-4a56-a56a-d48408fe7273", + "severity": "Medium" + }, { "category": "Business Continuity and Disaster Recovery", "subcategory": "High availability", @@ -72,7 +133,7 @@ "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations", "link": "https://learn.microsoft.com/azure/virtual-machines/availability" }, - { + { "category": "Business Continuity and Disaster Recovery", "subcategory": "High availability", "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.", @@ -123,74 +184,6 @@ "severity": "High", "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios" }, - - - - - - - - { - "category": "Business Continuity and Disaster Recovery", - "subcategory": " ", - "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.", - "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", - "severity": "Medium", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/design-logs-deployment" - }, - { - "category": "Business Continuity and Disaster Recovery", - "subcategory": " ", - "text": "Use a Standard Load Balancer SKU in front of ASCS and DB clusters", - "guid": "cca275fa-a1ab-4fe9-b55d-04c3c4919cb1", - "severity": "Medium", - "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response" - }, - { - "category": "Business Continuity and Disaster Recovery", - "subcategory": " ", - "text": "Both VMs in the HA pair should be deployed in an availability set, or Availability Zones should be the same size and have the same storage configuration", - "guid": "b3d1325a-e124-4ba3-9df6-85eddce9bd3b", - "severity": "Medium", - "link": "https://www.microsoft.com/itshowcase/implementing-a-zero-trust-security-model-at-microsoft" - }, - { - "category": "Business Continuity and Disaster Recovery", - "subcategory": " ", - "text": "Native database replication technology should be used to synchronize the database in a HA pair.", - "guid": "b0cdb3b5-5eb2-4ec1-9eea-a3592829e2ed", - "severity": "Medium", - "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response" - }, - { - "category": "Business Continuity and Disaster Recovery", - "subcategory": " ", - "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", - "guid": "b2173676-aff6-4691-a493-5ada42223ece", - "severity": "Medium", - "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response" - }, - { - "category": "Business Continuity and Disaster Recovery", - "subcategory": " ", - "text": "The CIDR for the primary virtual network (VNet) shouldn't conflict or overlap with the CIDR of the DR site's Vnet", - "guid": "81b12318-1a54-4174-8583-3fb4ae3c2df7", - "severity": "Medium" - }, - { - "category": "Business Continuity and Disaster Recovery", - "subcategory": " ", - "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).", - "guid": "43165c3a-cbe0-45bb-b209-d490da477784", - "severity": "Medium" - }, - { - "category": "Business Continuity and Disaster Recovery", - "subcategory": " ", - "text": "Native database replication should be used to synchronize data to the DR site, rather than Azure Site Recovery", - "guid": "24d11678-5d2f-4a56-a56a-d48408fe7273", - "severity": "Medium" - }, { "category": "Compute", "subcategory": " ", @@ -860,60 +853,6 @@ "severity": "Medium", "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration" }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Security", - "text": "Customize role-based access control (RBAC) roles for SAP on Azure spoke subscriptions to avoid accidental network-related changes", - "guid": "209d490d-a477-4784-84d1-16785d2fa56c", - "severity": "High", - "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations", - "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles" - }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Security", - "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", - "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", - "severity": "High", - "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal", - "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/" - }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Secrets", - "text": "Encrypting SAP HANA database servers on Azrue 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.", - "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", - "severity": "High", - "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance" - }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Secrets", - "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.", - "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", - "severity": "Medium", - "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations", - "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption" - }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Security", - "text": "Consider using Microsoft anti-malware software on Azure to protect your virtual machines from malicious files, adware, and other threats.", - "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", - "severity": "Low", - "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/", - "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations" - }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Security", - "text": "For even more powerful protection, consider using Microsoft Defender for Endpoint.", - "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", - "severity": "Low", - "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations", - "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide" - }, { "category": "Security, Governance and Compliance", "subcategory": "Governance", @@ -932,33 +871,6 @@ "training": "https://support.sap.com/en/my-support/knowledge-base/security-notes-news.html", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations" }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Security", - "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.", - "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", - "severity": "High", - "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations", - "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape" - }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Security", - "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.", - "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", - "severity": "Low", - "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations", - "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance" - }, - { - "category": "Security, Governance and Compliance", - "subcategory": "Security", - "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.", - "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", - "severity": "Medium", - "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations", - "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions" - }, { "category": "Security, Governance and Compliance", "subcategory": "Governance", @@ -975,7 +887,25 @@ "severity": "High", "training": "https://me.sap.com/notes/3019299/E", "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security" - }, + }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Secrets", + "text": "Encrypting SAP HANA database servers on Azrue 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.", + "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", + "severity": "High", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance" + }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Secrets", + "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.", + "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", + "severity": "Medium", + "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption" + }, { "category": "Security, Governance and Compliance", "subcategory": "Secrets", @@ -1074,6 +1004,69 @@ "severity": "Medium", "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices" }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Security", + "text": "Customize role-based access control (RBAC) roles for SAP on Azure spoke subscriptions to avoid accidental network-related changes", + "guid": "209d490d-a477-4784-84d1-16785d2fa56c", + "severity": "High", + "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations", + "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles" + }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Security", + "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", + "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", + "severity": "High", + "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal", + "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/" + }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Security", + "text": "Consider using Microsoft anti-malware software on Azure to protect your virtual machines from malicious files, adware, and other threats.", + "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", + "severity": "Low", + "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/", + "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations" + }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Security", + "text": "For even more powerful protection, consider using Microsoft Defender for Endpoint.", + "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", + "severity": "Low", + "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations", + "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide" + }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Security", + "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.", + "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", + "severity": "High", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape" + }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Security", + "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.", + "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", + "severity": "Low", + "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance" + }, + { + "category": "Security, Governance and Compliance", + "subcategory": "Security", + "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.", + "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", + "severity": "Medium", + "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations", + "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions" + }, { "category": "Storage", "subcategory": " ", @@ -1127,6 +1120,6 @@ "metadata": { "name": "Azure Landing Zone Review", "state": "Preview", - "timestamp": "November 24, 2023" + "timestamp": "January 11, 2024" } } \ No newline at end of file diff --git a/checklists/sap_checklist.es.json b/checklists/sap_checklist.es.json index 32fa20ed8..276671f9b 100644 --- a/checklists/sap_checklist.es.json +++ b/checklists/sap_checklist.es.json @@ -17,38 +17,6 @@ } ], "items": [ - { - "category": "Continuidad del negocio y recuperación ante desastres", - "guid": "aff6691b-4935-4ada-9222-3ece81b12318", - "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-reports", - "severity": "Medio", - "subcategory": " ", - "text": "No combine ASCS y el clúster de base de datos en una sola máquina virtual o en la misma máquina virtual" - }, - { - "category": "Continuidad del negocio y recuperación ante desastres", - "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export?tabs=portal", - "severity": "Medio", - "subcategory": " ", - "text": "Asegúrese de que la IP flotante esté habilitada en el equilibrador de carga" - }, - { - "category": "Continuidad del negocio y recuperación ante desastres", - "guid": "cbe05bbe-209d-4490-ba47-778424d11678", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "Medio", - "subcategory": " ", - "text": "No mezcle servidores de diferentes roles en el mismo conjunto de disponibilidad. Mantenga las máquinas virtuales de servicios centrales, las máquinas virtuales de base de datos y las máquinas virtuales de aplicaciones en sus propios conjuntos de disponibilidad" - }, - { - "category": "Continuidad del negocio y recuperación ante desastres", - "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "Medio", - "subcategory": " ", - "text": "Use un grupo de selección de ubicación de proximidad por SID de SAP. Los grupos no abarcan zonas de disponibilidad ni regiones de Azure" - }, { "category": "Continuidad del negocio y recuperación ante desastres", "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", @@ -101,7 +69,7 @@ "guid": "43165c3a-cbe0-45bb-b209-d490da477784", "severity": "Medio", "subcategory": " ", - "text": "Use Site Recovery para replicar un servidor de aplicaciones en un sitio de recuperación ante desastres. Site Recovery también puede ayudar a replicar máquinas virtuales de clúster de servicios centrales en el sitio de recuperación ante desastres. Al invocar la recuperación ante desastres, deberá volver a configurar el clúster de Linux Pacemaker en el sitio de recuperación ante desastres (por ejemplo, reemplazar la VIP o SBD, ejecutar corosync.conf, etc.)." + "text": "Use Site Recovery para replicar un servidor de aplicaciones en un sitio de recuperación ante desastres. Site Recovery también puede ayudar a replicar máquinas virtuales de clúster de servicios centrales en el sitio de recuperación ante desastres. Al invocar la recuperación ante desastres, deberá volver a configurar el clúster de Linux Pacemaker en el sitio de recuperación ante desastres (por ejemplo, reemplazar el VIP o SBD, ejecutar corosync.conf, etc.)." }, { "category": "Continuidad del negocio y recuperación ante desastres", @@ -110,12 +78,135 @@ "subcategory": " ", "text": "La replicación nativa de la base de datos debe usarse para sincronizar los datos con el sitio de recuperación ante desastres, en lugar de Azure Site Recovery" }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "8300cb30-766b-4084-b126-0dd8fb1269a1", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-architecture-scenario", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Considere la disponibilidad del software de SAP frente a puntos únicos de fallo. Esto incluye puntos únicos de falla dentro de aplicaciones como DBMS utilizados en las arquitecturas SAP NetWeaver y SAP S/4HANA, SAP ABAP y ASCS + SCS. También, otras herramientas como 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" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "56402f11-ccbe-42c3-a2f6-c6f6f38ab579", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-supported-configurations", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "En el caso de SAP y bases de datos de SAP, considere la posibilidad de implementar clústeres de conmutación por error automática. En Windows, los clústeres de conmutación por error de Windows Server admiten la conmutación por error. En Linux, Linux Pacemaker o herramientas de terceros como SIOS Protection Suite y Veritas InfoScale admiten la conmutación por error.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "afae6bec-2671-49ae-bc69-140b8ec8d320", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Azure no admite arquitecturas en las que las máquinas virtuales principal y secundaria compartan el almacenamiento de los datos de DBMS. Para la capa DBMS, el patrón de arquitectura común es replicar bases de datos al mismo tiempo y con pilas de almacenamiento diferentes a las que usan las máquinas virtuales principal y secundaria.", + "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" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "ac614e95-6767-4bc3-b8a4-9953533da6ba", + "link": "https://learn.microsoft.com/azure/sap/workloads/dbms-guide-general", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Los datos de DBMS y los archivos de registro de transacciones y puesta al día se almacenan en el almacenamiento en bloque compatible con Azure o en Azure NetApp Files. Azure Files o Azure Premium Files no se admiten como almacenamiento para datos de DBMS o archivos de registro de puesta al día con la carga de trabajo de SAP.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-databases/2-explore-database-support-azure-for-sap-workloads" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "1f737179-8e7f-4e1a-a30c-e5a649a3092b", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-wsfc-shared-disk", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Puede usar discos compartidos de Azure en Windows para componentes ASCS + SCS y escenarios específicos de alta disponibilidad. Configure los clústeres de conmutación por error por separado para los componentes de la capa de aplicación de SAP y la capa de DBMS. Actualmente, Azure no admite arquitecturas de alta disponibilidad que combinen componentes de la capa de aplicación de SAP y la capa de DBMS en un clúster de conmutación por error.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "a78b3d31-3170-44f2-b5d7-651a29f4ccf5", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-standard-load-balancer-outbound-connections", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "La mayoría de los clústeres de conmutación por error para los componentes de la capa de aplicación (ASCS) de SAP y la capa de DBMS requieren una dirección IP virtual para un clúster de conmutación por error. Azure Load Balancer debe controlar la dirección IP virtual para todos los demás casos. Un principio de diseño es usar un equilibrador de carga por configuración de clúster. Te recomendamos que utilices la versión estándar del equilibrador de carga (SKU de equilibrador de carga estándar).", + "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-ha-ports-overview?source=recommendations", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Asegúrese de que la IP flotante esté habilitada en el equilibrador de carga", + "training": "https://learn.microsoft.com/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "c47cc4f3-f105-452c-845e-9b307b3856c1", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Antes de implementar la infraestructura de alta disponibilidad, y en función de la región que elija, determine si desea realizar la implementación con un conjunto de disponibilidad de Azure o una zona de disponibilidad.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "844f69c3-07e5-4ec1-bff7-4be27bcf5fea", + "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Si desea cumplir los acuerdos de nivel de servicio de infraestructura para las aplicaciones de los componentes de SAP (servicios centrales, servidores de aplicaciones y bases de datos), debe elegir las mismas opciones de alta disponibilidad (máquinas virtuales, conjuntos de disponibilidad, zonas de disponibilidad) para todos los componentes." + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "cbe05bbe-209d-4490-ba47-778424d11678", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "No mezcle servidores de diferentes roles en el mismo conjunto de disponibilidad. Mantenga las máquinas virtuales de servicios centrales, las máquinas virtuales de base de datos y las máquinas virtuales de aplicaciones en sus propios conjuntos de disponibilidad", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "f2201000-d045-40a6-a79a-d7cdc01b4d86", + "link": "https://learn.microsoft.com/azure/virtual-machines/co-location", + "severity": "Medio", + "subcategory": "Alta disponibilidad", + "text": "No se pueden implementar conjuntos de disponibilidad de Azure dentro de una zona de disponibilidad de Azure a menos que se usen grupos de selección de ubicación de proximidad.", + "training": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "9674e7c7-7796-4181-8920-09f4429543ba", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Al crear conjuntos de disponibilidad, use el número máximo de dominios de error y dominios de actualización disponibles. Por ejemplo, si implementa más de dos máquinas virtuales en un conjunto de disponibilidad, use el número máximo de dominios de error (tres) y suficientes dominios de actualización para limitar el efecto de posibles errores de hardware físico, interrupciones de red o interrupciones de energía, además del mantenimiento planeado de Azure. El número predeterminado de dominios de error es dos y no puede cambiarlo en línea más adelante.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "ae4ecb95-b70f-428f-8b9a-4c5b7e3478a2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Cuando se usan grupos de selección con selección de ubicación de proximidad de Azure en una implementación de conjunto de disponibilidad, los tres componentes de SAP (servicios centrales, servidor de aplicaciones y base de datos) deben estar en el mismo grupo con selección de ubicación de proximidad." + }, + { + "category": "Continuidad del negocio y recuperación ante desastres", + "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "Alto", + "subcategory": "Alta disponibilidad", + "text": "Use un grupo de selección de ubicación de proximidad por SID de SAP. Los grupos no abarcan zonas de disponibilidad ni regiones de Azure" + }, { "category": "Calcular", "guid": "2829e2ed-b217-4367-9aff-6691b4935ada", "severity": "Medio", "subcategory": " ", - "text": "Realizar solicitudes de cuota para la SKU y las zonas de VM correctas" + "text": "Realizar solicitudes de cuota para la SKU y las zonas de máquina virtual correctas" }, { "category": "Identidad y acceso", @@ -265,7 +356,7 @@ "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", "severity": "Alto", "subcategory": "Suscripciones", - "text": "Aprovechar la suscripción como unidad de escalado y escalar nuestros recursos, considere la posibilidad de implementar la suscripción por entorno, por ejemplo. Sandbox, no-prod, prod ", + "text": "Aprovechar la suscripción como unidad de escalado y escalar nuestros recursos, considere implementar la suscripción por entorno, por ejemplo. Sandbox, no-prod, prod ", "training": "https://learn.microsoft.com/training/modules/configure-subscriptions/?source=recommendations" }, { @@ -291,7 +382,7 @@ "link": "https://learn.microsoft.com/azure/quotas/quickstart-increase-quota-portal", "severity": "Alto", "subcategory": "Suscripciones", - "text": "Si realiza la implementación en una zona de disponibilidad, asegúrese de que la implementación de la zona de la máquina virtual esté disponible una vez que se haya aprobado la cuota. Envíe una solicitud de soporte técnico con la suscripción, la serie de máquinas virtuales, el número de CPU y la zona de disponibilidad necesaria." + "text": "Si realiza la implementación en una zona de disponibilidad, asegúrese de que la implementación de la zona de la máquina virtual esté disponible una vez que se haya aprobado la cuota. Envíe una solicitud de soporte técnico con la suscripción, la serie de máquinas virtuales, el número de CPU y la zona de disponibilidad necesarias." }, { "category": "Grupo de administración y suscripciones", @@ -308,7 +399,7 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-resource-organization", "severity": "Medio", "subcategory": "Suscripciones", - "text": "Aproveche la etiqueta de recurso de Azure para la categorización de costos y la agrupación de recursos (: BillTo, Departamento (o unidad de negocio), Entorno (producción, Fase, Desarrollo), Nivel (nivel web, nivel de aplicación), Propietario de la aplicación, ProjectName)", + "text": "Aproveche la etiqueta de recurso de Azure para la categorización de costos y la agrupación de recursos (facturación, departamento (o unidad de negocio), entorno (producción, fase, desarrollo), nivel (nivel web, nivel de aplicación), propietario de la aplicación, ProjectName)", "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/" }, { @@ -534,7 +625,7 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", "severity": "Medio", "subcategory": "DNS", - "text": "Si el DNS o el nombre virtual de la máquina virtual no se cambia durante la migración a Azure, el DNS en segundo plano y los nombres virtuales conectan muchas interfaces del sistema en el entorno de SAP, y los clientes solo conocen a veces las interfaces que los desarrolladores definen a lo largo del tiempo. Los problemas de conexión surgen entre varios sistemas cuando los nombres virtuales o DNS cambian después de las migraciones, y se recomienda conservar los alias DNS para evitar este tipo de dificultades.", + "text": "Si el DNS o el nombre virtual de la máquina virtual no se cambia durante la migración a Azure, el DNS en segundo plano y los nombres virtuales conectan muchas interfaces del sistema en el entorno de SAP, y los clientes solo conocen a veces las interfaces que los desarrolladores definen a lo largo del tiempo. Los desafíos de conexión surgen entre varios sistemas cuando los nombres virtuales o DNS cambian después de las migraciones, y se recomienda conservar los alias DNS para evitar este tipo de dificultades.", "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/4-explore-name-resolution" }, { @@ -579,7 +670,7 @@ "link": "https://learn.microsoft.com/azure/well-architected/services/networking/network-virtual-appliances/reliability", "severity": "Medio", "subcategory": "Híbrido", - "text": "Considere la posibilidad de implementar aplicaciones virtuales de red (NVA) entre regiones solo si se usan aplicaciones virtuales de red de asociado. Las aplicaciones virtuales de red entre regiones o redes virtuales no son necesarias si hay aplicaciones virtuales de red nativas. Al implementar tecnologías de redes de asociados y aplicaciones virtuales de red, siga las instrucciones del proveedor para comprobar las configuraciones conflictivas con las redes de Azure.", + "text": "Considere la posibilidad de implementar aplicaciones virtuales de red (NVA) entre regiones solo si se usan aplicaciones virtuales de red de asociados. Las aplicaciones virtuales de red entre regiones o redes virtuales no son necesarias si hay aplicaciones virtuales de red nativas. Al implementar tecnologías de redes de asociados y aplicaciones virtuales de red, siga las instrucciones del proveedor para comprobar las configuraciones conflictivas con las redes de Azure.", "training": "https://learn.microsoft.com/training/modules/control-network-traffic-flow-with-routes/?source=recommendations" }, { @@ -687,7 +778,7 @@ "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", "severity": "Medio", "subcategory": "Internet", - "text": "Para evitar la pérdida de datos, use Azure Private Link para acceder de forma segura a los recursos de la plataforma como servicio, como Azure Blob Storage, Azure Files, Azure Data Lake Storage Gen2, Azure Data Factory, etc. El punto de conexión privado de Azure también puede ayudar a proteger el tráfico entre redes virtuales y servicios como Azure Storage, Azure Backup, etc. El tráfico entre la red virtual y el servicio habilitado para punto de conexión privado viaja a través de la red global de Microsoft, lo que impide su exposición a la red pública de Internet.", + "text": "Para evitar la pérdida de datos, use Azure Private Link para acceder de forma segura a los recursos de plataforma como servicio, como Azure Blob Storage, Azure Files, Azure Data Lake Storage Gen2, Azure Data Factory, etc. El punto de conexión privado de Azure también puede ayudar a proteger el tráfico entre redes virtuales y servicios como Azure Storage, Azure Backup, etc. El tráfico entre la red virtual y el servicio habilitado para punto de conexión privado viaja a través de la red global de Microsoft, lo que impide su exposición a la red pública de Internet.", "training": "https://learn.microsoft.com/training/modules/design-implement-private-access-to-azure-services/?source=recommendations" }, { @@ -714,7 +805,7 @@ "link": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", "severity": "Medio", "subcategory": "Segmentación", - "text": "Puede usar reglas de grupo de seguridad de aplicaciones (ASG) y NSG para definir listas de control de acceso de seguridad de red entre las capas de aplicación SAP y DBMS. Los ASG agrupan las máquinas virtuales para ayudar a administrar su seguridad.", + "text": "Puede usar reglas de grupo de seguridad de aplicaciones (ASG) y NSG para definir listas de control de acceso de seguridad de red entre la aplicación SAP y las capas DBMS. Los ASG agrupan las máquinas virtuales para ayudar a administrar su seguridad.", "training": "https://learn.microsoft.com/training/modules/configure-network-security-groups/?source=recommendations" }, { @@ -750,7 +841,7 @@ "link": "https://me.sap.com/notes/2015553", "severity": "Alto", "subcategory": "Segmentación", - "text": "No se recomienda hospedar el sistema de administración de bases de datos (DBMS) y las capas de aplicación de los sistemas SAP en diferentes redes virtuales y conectarlas con el emparejamiento de redes virtuales debido a los costos sustanciales que puede generar un tráfico de red excesivo entre las capas. Se recomienda el uso de subredes dentro de la red virtual de Azure para separar la capa de aplicación de SAP y la capa de DBMS.", + "text": "No se recomienda hospedar el sistema de administración de bases de datos (DBMS) y las capas de aplicación de los sistemas SAP en diferentes redes virtuales y conectarlas con el emparejamiento de redes virtuales debido a los costos sustanciales que puede producir un tráfico de red excesivo entre las capas. Se recomienda el uso de subredes dentro de la red virtual de Azure para separar la capa de aplicación de SAP y la capa de DBMS.", "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity" }, { @@ -777,55 +868,60 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration", "severity": "Medio", "subcategory": "Segmentación", - "text": "En el caso de las implementaciones de SAP RISE/ECS, el emparejamiento virtual es la forma preferida de establecer la conectividad con el entorno de Azure existente del cliente. Tanto la red virtual de SAP como las redes virtuales del cliente están protegidas con grupos de seguridad de red (NSG), lo que permite la comunicación en los puertos de SAP y de base de datos a través del emparejamiento de red virtual" + "text": "En el caso de las implementaciones de SAP RISE/ECS, el emparejamiento virtual es la forma preferida de establecer la conectividad con el entorno de Azure existente del cliente. Tanto la red virtual de SAP como las redes virtuales del cliente están protegidas con grupos de seguridad de red (NSG), lo que permite la comunicación en los puertos de SAP y de base de datos a través del emparejamiento de redes virtuales" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "209d490d-a477-4784-84d1-16785d2fa56c", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "Alto", + "guid": "18dffcf3-248c-4039-a67c-dec8e3a5f804", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", + "severity": "Medio", "subcategory": "Gobernanza", - "text": "Personalización de los roles de control de acceso basado en rol (RBAC) para SAP en suscripciones de Azure spoke para evitar cambios accidentales relacionados con la red" + "text": "Si ejecuta máquinas virtuales Windows y Linux en Azure, en el entorno local o en otros entornos en la nube, puede usar el Centro de administración de actualizaciones de Automatización de Azure para administrar las actualizaciones del sistema operativo, incluidas las revisiones de seguridad.", + "training": "https://learn.microsoft.com/azure/automation/update-management/overview" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "08951710-79a2-492a-adbc-06d7a401545b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", "severity": "Medio", "subcategory": "Gobernanza", - "text": "Aísle las redes perimetrales y las aplicaciones virtuales de red del resto del patrimonio de SAP, configure Azure Private Link y administre y controle de forma segura los recursos de SAP en Azure" + "text": "Revise de forma rutinaria las notas de seguridad de SAP OSS, ya que SAP publica parches de seguridad muy críticos, o revisiones, que requieren una acción inmediata para proteger sus sistemas SAP.", + "training": "https://support.sap.com/en/my-support/knowledge-base/security-notes-news.html" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "Medio", + "guid": "1b8b394e-ae64-4a74-8933-357b523ea0a0", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "Bajo", "subcategory": "Gobernanza", - "text": "Para el cifrado del servidor de base de datos de SAP, use la tecnología de cifrado nativa de SAP HANA. Si usa Azure SQL Database, use el cifrado de datos transparente (TDE) que ofrece el proveedor de DBMS para proteger los datos y los archivos de registro, y asegúrese de que las copias de seguridad también están cifradas." + "text": "En el caso de SAP en SQL Server, puede deshabilitar la cuenta de administrador del sistema de SQL Server porque los sistemas SAP en SQL Server no usan la cuenta. Asegúrese de que otro usuario con derechos de administrador del sistema pueda acceder al servidor antes de deshabilitar la cuenta de administrador del sistema original." }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "Medio", + "guid": "5a76a033-ced9-4eef-9a43-5e4f96634c8e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "Alto", "subcategory": "Gobernanza", - "text": "El cifrado de Azure Storage está habilitado de forma predeterminada" + "text": "Deshabilite xp_cmdshell. La característica de SQL Server xp_cmdshell habilita un shell de comandos del sistema operativo interno de SQL Server. Es un riesgo potencial en las auditorías de seguridad.", + "training": "https://me.sap.com/notes/3019299/E" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "Medio", - "subcategory": "Gobernanza", - "text": " " + "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "Alto", + "subcategory": "Secretos", + "text": "El cifrado de servidores de bases de datos SAP HANA en Azrue utiliza la tecnología de cifrado nativa de SAP HANA. Además, si usa SQL Server en Azure, use el cifrado de datos transparente (TDE) para proteger los datos y los archivos de registro y asegurarse de que las copias de seguridad también están cifradas.", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", "severity": "Medio", - "subcategory": "Gobernanza", - "text": " " + "subcategory": "Secretos", + "text": "El cifrado de Azure Storage está habilitado para todas las cuentas de Azure Resource Manager y de almacenamiento clásico, y no se puede deshabilitar. Dado que los datos están cifrados de forma predeterminada, no es necesario modificar el código o las aplicaciones para usar el cifrado de Azure Storage.", + "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", @@ -833,95 +929,160 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/overview", "severity": "Alto", "subcategory": "Secretos", - "text": "Uso de Azure Key Vault para almacenar los secretos y las credenciales" + "text": "Uso de Azure Key Vault para almacenar los secretos y las credenciales", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", "guid": "829e2edb-2173-4676-aff6-691b4935ada4", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview-throttling", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", "severity": "Medio", "subcategory": "Secretos", - "text": "Se recomienda BLOQUEAR los recursos de Azure después de la implementación correcta para protegerse contra cambios no autorizados" + "text": "Se recomienda bloquear los recursos de Azure después de la implementación correcta para protegerse contra cambios no autorizados. También puede aplicar restricciones y reglas de LOCK por suscripción mediante directivas de Azure personalizadas (rol personalizado).", + "training": "https://learn.microsoft.com/training/modules/use-azure-resource-manager/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", "guid": "2223ece8-1b12-4318-8a54-17415833fb4a", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", "severity": "Medio", "subcategory": "Secretos", - "text": "Aprovisione Azure Key Vault con las directivas de eliminación temporal y purga habilitadas para permitir la protección de retención de los objetos eliminados." + "text": "Aprovisione Azure Key Vault con las directivas de eliminación temporal y purga habilitadas para permitir la protección de retención de los objetos eliminados.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", "guid": "e3c2df74-3165-4c3a-abe0-5bbe209d490d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Medio", + "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", + "severity": "Alto", "subcategory": "Secretos", - "text": "En función de los requisitos existentes, controles normativos y de cumplimiento (internos y externos): determine qué directivas de Azure y el rol de RBAC de Azure son necesarios" + "text": "En función de los requisitos existentes, controles normativos y de cumplimiento (internos y externos): determine qué directivas de Azure y el rol de RBAC de Azure son necesarios", + "training": "https://learn.microsoft.com/training/paths/describe-azure-management-governance/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", "guid": "a4777842-4d11-4678-9d2f-a56c56ad4840", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Medio", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "Alto", "subcategory": "Secretos", - "text": "Al habilitar Microsoft Defender for Cloud Standard para SAP, asegúrese de excluir los servidores de base de datos de SAP de cualquier directiva que instale Endpoint Protection." + "text": "Al habilitar Microsoft Defender para punto de conexión en el entorno de SAP, se recomienda excluir los archivos de datos y registro en los servidores DBMS en lugar de dirigirse a todos los servidores. Siga las recomendaciones de su proveedor de DBMS al excluir archivos de destino.", + "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/microsoft-defender-endpoint-mde-for-sap-applications-on-windows/ba-p/3912268" }, { "category": "Seguridad, gobernanza y cumplimiento", "guid": "8fe72734-c486-4ba2-a0dc-0591cf65de8e", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Medio", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/just-in-time-access-overview?tabs=defender-for-container-arch-aks", + "severity": "Alto", "subcategory": "Secretos", - "text": "Delegue un rol personalizado de administrador de SAP con acceso Just-In-Time." + "text": "Delegue un rol personalizado de administrador de SAP con acceso Just-In-Time de Microsoft Defender for Cloud.", + "training": "https://learn.microsoft.com/training/modules/secure-vms-with-azure-security-center/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", "guid": "1309cccd-5792-466b-aca2-75faa1abfe9d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Medio", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "Bajo", "subcategory": "Secretos", - "text": "cifre los datos en tránsito integrando el producto de seguridad de terceros con comunicaciones de red seguras (SNC) para DIAG (SAP GUI), RFC y SPNEGO para HTTPS" + "text": "cifre los datos en tránsito integrando el producto de seguridad de terceros con comunicaciones de red seguras (SNC) para DIAG (SAP GUI), RFC y SPNEGO para HTTPS", + "training": "https://learn.microsoft.com/azure/security/fundamentals/encryption-overview#encryption-of-data-in-transit" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "55d04c3c-4919-4cb1-a3d1-325ae124ba34", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", + "link": "https://learn.microsoft.com/azure/storage/common/storage-encryption-key-model-get?tabs=portal", "severity": "Medio", "subcategory": "Secretos", - "text": "Azure Active Directory (Azure AD) con SAML 2.0 también puede proporcionar SSO a una amplia gama de aplicaciones y plataformas de SAP, como SAP NetWeaver, SAP HANA y SAP Cloud Platform" + "text": "De forma predeterminada, utilice claves administradas por Microsoft para la funcionalidad de cifrado de entidad de seguridad y use claves administradas por el cliente cuando sea necesario.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "df685edd-ce9b-4d3b-a0cd-b3b55eb2ec14", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Medio", + "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "link": "https://learn.microsoft.com/ja-jp/azure/key-vault/general/best-practices", + "severity": "Alto", "subcategory": "Secretos", - "text": "Asegúrese de reforzar el sistema operativo para erradicar las vulnerabilidades que podrían provocar ataques a la base de datos de SAP." + "text": "Use una instancia de Azure Key Vault por aplicación, por entorno, por región.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Medio", + "guid": "abc9634d-c44d-41e9-a530-e8444e16aa3c", + "link": "https://learn.microsoft.com/azure/key-vault/certificates/certificate-scenarios", + "severity": "Alto", "subcategory": "Secretos", - "text": "De forma predeterminada, utilice claves administradas por Microsoft para la funcionalidad de cifrado de entidad de seguridad y use claves administradas por el cliente cuando sea necesario." + "text": "Para controlar y administrar claves y secretos de cifrado de disco para sistemas operativos Windows y Windows que no son de HANA, use Azure Key Vault. SAP HANA no es compatible con Azure Key Vault, por lo que debe usar métodos alternativos como SAP ABAP o claves SSH.", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/?source=recommendations" }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "severity": "Medio", "subcategory": "Secretos", - "text": "Use una instancia de Azure Key Vault por aplicación, por entorno, por región." + "text": " " }, { "category": "Seguridad, gobernanza y cumplimiento", - "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "209d490d-a477-4784-84d1-16785d2fa56c", + "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles", + "severity": "Alto", + "subcategory": "Seguridad", + "text": "Personalización de los roles de control de acceso basado en rol (RBAC) para SAP en suscripciones de Azure spoke para evitar cambios accidentales relacionados con la red", + "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations" + }, + { + "category": "Seguridad, gobernanza y cumplimiento", + "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", + "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/", + "severity": "Alto", + "subcategory": "Seguridad", + "text": "Aísle las redes perimetrales y las aplicaciones virtuales de red del resto del patrimonio de SAP, configure Azure Private Link y administre y controle de forma segura los recursos de SAP en Azure", + "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal" + }, + { + "category": "Seguridad, gobernanza y cumplimiento", + "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", + "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", + "severity": "Bajo", + "subcategory": "Seguridad", + "text": "Considere la posibilidad de usar el software antimalware de Microsoft en Azure para proteger las máquinas virtuales de archivos malintencionados, adware y otras amenazas.", + "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/" + }, + { + "category": "Seguridad, gobernanza y cumplimiento", + "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", + "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", + "severity": "Bajo", + "subcategory": "Seguridad", + "text": "Para una protección aún más eficaz, considere la posibilidad de usar Microsoft Defender para punto de conexión.", + "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations" + }, + { + "category": "Seguridad, gobernanza y cumplimiento", + "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "severity": "Alto", + "subcategory": "Seguridad", + "text": "Aísle los servidores de aplicaciones y bases de datos de SAP de Internet o de la red local pasando todo el tráfico a través de la red virtual del centro de conectividad, que está conectada a la red radial mediante el emparejamiento de red virtual. Las redes virtuales emparejadas garantizan que la solución de SAP en Azure esté aislada de la red pública de Internet.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations" + }, + { + "category": "Seguridad, gobernanza y cumplimiento", + "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "Bajo", + "subcategory": "Seguridad", + "text": "En el caso de las aplicaciones orientadas a Internet, como SAP Fiori, asegúrese de distribuir la carga según los requisitos de la aplicación mientras se mantienen los niveles de seguridad. Para la seguridad de nivel 7, puede usar un firewall de aplicaciones web (WAF) de terceros disponible en Azure Marketplace.", + "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations" + }, + { + "category": "Seguridad, gobernanza y cumplimiento", + "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", + "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions", "severity": "Medio", - "subcategory": "Secretos", - "text": " " + "subcategory": "Seguridad", + "text": "Para habilitar la comunicación segura en las soluciones de Azure Monitor para SAP, puede optar por usar un certificado raíz o un certificado de servidor. Le recomendamos encarecidamente que utilice certificados raíz.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations" }, { "category": "Almacenamiento", @@ -934,7 +1095,7 @@ "metadata": { "name": "Azure Landing Zone Review", "state": "Preview", - "timestamp": "November 24, 2023" + "timestamp": "January 11, 2024" }, "severities": [ { diff --git a/checklists/sap_checklist.ja.json b/checklists/sap_checklist.ja.json index 6b59b7d66..fa5319820 100644 --- a/checklists/sap_checklist.ja.json +++ b/checklists/sap_checklist.ja.json @@ -17,38 +17,6 @@ } ], "items": [ - { - "category": "ビジネス継続性と災害復旧", - "guid": "aff6691b-4935-4ada-9222-3ece81b12318", - "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-reports", - "severity": "中程度", - "subcategory": " ", - "text": "ASCS とデータベース クラスターを 1 つまたは同じ VM に結合しないでください" - }, - { - "category": "ビジネス継続性と災害復旧", - "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export?tabs=portal", - "severity": "中程度", - "subcategory": " ", - "text": "ロードバランサーでフローティング IP が有効になっていることを確認します" - }, - { - "category": "ビジネス継続性と災害復旧", - "guid": "cbe05bbe-209d-4490-ba47-778424d11678", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "中程度", - "subcategory": " ", - "text": "同じ可用性セット内に異なるロールのサーバーを混在させないでください。セントラル サービス VM、データベース VM、アプリケーション VM を独自の可用性セットに保持する" - }, - { - "category": "ビジネス継続性と災害復旧", - "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "中程度", - "subcategory": " ", - "text": "SAP SID ごとに 1 つの近接配置グループを使用します。グループは、Availability Zones や Azure リージョンにまたがっていません" - }, { "category": "ビジネス継続性と災害復旧", "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", @@ -110,6 +78,129 @@ "subcategory": " ", "text": "ネイティブ データベース レプリケーションは、Azure Site Recovery ではなく、DR サイトにデータを同期するために使用する必要があります" }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "8300cb30-766b-4084-b126-0dd8fb1269a1", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-architecture-scenario", + "severity": "高い", + "subcategory": "高可用性", + "text": "単一障害点に対する SAP ソフトウェアの可用性を検討します。これには、SAP NetWeaver や SAP S/4HANA アーキテクチャ、SAP ABAP、ASCS + SCS で使用される DBMS などのアプリケーション内の単一障害点が含まれます。また、SAP Web ディスパッチャなどの他のツールも必要です。", + "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" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "56402f11-ccbe-42c3-a2f6-c6f6f38ab579", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-supported-configurations", + "severity": "高い", + "subcategory": "高可用性", + "text": "SAP および SAP データベースの場合は、自動フェールオーバー クラスターの実装を検討してください。Windows では、Windows Server フェールオーバー クラスタリングがフェールオーバーをサポートします。Linux では、Linux Pacemaker や、SIOS Protection Suite や Veritas InfoScale などのサードパーティツールがフェイルオーバーをサポートしています。", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "afae6bec-2671-49ae-bc69-140b8ec8d320", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", + "severity": "高い", + "subcategory": "高可用性", + "text": "Azure では、プライマリ VM とセカンダリ VM が DBMS データのストレージを共有するアーキテクチャはサポートされていません。DBMSレイヤーの場合、一般的なアーキテクチャパターンは、プライマリおよびセカンダリVMが使用するストレージスタックとは異なるストレージスタックを使用して、データベースを同時にレプリケートすることです。", + "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" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "ac614e95-6767-4bc3-b8a4-9953533da6ba", + "link": "https://learn.microsoft.com/azure/sap/workloads/dbms-guide-general", + "severity": "高い", + "subcategory": "高可用性", + "text": "DBMS データとトランザクション/REDO ログ ファイルは、Azure でサポートされているブロック ストレージまたは Azure NetApp Files に格納されます。Azure Files または Azure Premium Files は、SAP ワークロードでの DBMS データや再実行ログ ファイルのストレージとしてはサポートされていません。", + "training": "https://learn.microsoft.com/training/modules/explore-azure-databases/2-explore-database-support-azure-for-sap-workloads" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "1f737179-8e7f-4e1a-a30c-e5a649a3092b", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-wsfc-shared-disk", + "severity": "高い", + "subcategory": "高可用性", + "text": "Windows の Azure 共有ディスクは、ASCS + SCS コンポーネントと特定の高可用性シナリオに使用できます。フェールオーバー クラスターは、SAP アプリケーション層コンポーネントと DBMS 層に対して個別に設定します。現在、Azure では、SAP アプリケーション レイヤー コンポーネントと DBMS レイヤーを 1 つのフェールオーバー クラスターに結合する高可用性アーキテクチャはサポートされていません。", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "a78b3d31-3170-44f2-b5d7-651a29f4ccf5", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-standard-load-balancer-outbound-connections", + "severity": "高い", + "subcategory": "高可用性", + "text": "SAP アプリケーション レイヤー コンポーネント (ASCS) と DBMS レイヤーのほとんどのフェールオーバー クラスターでは、フェールオーバー クラスターの仮想 IP アドレスが必要です。 Azure Load Balancer は、他のすべてのケースで仮想 IP アドレスを処理する必要があります。設計原則の 1 つは、クラスター構成ごとに 1 つのロード バランサーを使用することです。ロード バランサーの Standard バージョン (Standard Load Balancer SKU) を使用することをお勧めします。", + "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-ha-ports-overview?source=recommendations", + "severity": "高い", + "subcategory": "高可用性", + "text": "ロードバランサーでフローティング IP が有効になっていることを確認します", + "training": "https://learn.microsoft.com/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "c47cc4f3-f105-452c-845e-9b307b3856c1", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "severity": "高い", + "subcategory": "高可用性", + "text": "高可用性インフラストラクチャをデプロイする前に、選択したリージョンに応じて、Azure 可用性セットと可用性ゾーンのどちらを使用してデプロイするかを決定します。", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "844f69c3-07e5-4ec1-bff7-4be27bcf5fea", + "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", + "severity": "高い", + "subcategory": "高可用性", + "text": "SAP コンポーネント (セントラル サービス、アプリケーション サーバー、データベース) のアプリケーションのインフラストラクチャ SLA を満たす場合は、すべてのコンポーネントに対して同じ高可用性オプション (VM、可用性セット、可用性ゾーン) を選択する必要があります。" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "cbe05bbe-209d-4490-ba47-778424d11678", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "高い", + "subcategory": "高可用性", + "text": "同じ可用性セット内に異なるロールのサーバーを混在させないでください。セントラル サービス VM、データベース VM、アプリケーション VM を独自の可用性セットに保持する", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "f2201000-d045-40a6-a79a-d7cdc01b4d86", + "link": "https://learn.microsoft.com/azure/virtual-machines/co-location", + "severity": "中程度", + "subcategory": "高可用性", + "text": "近接通信配置グループを使用しない限り、Azure 可用性ゾーン内に Azure 可用性セットをデプロイすることはできません。", + "training": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "9674e7c7-7796-4181-8920-09f4429543ba", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "高い", + "subcategory": "高可用性", + "text": "可用性セットを作成するときは、使用可能な障害ドメインと更新ドメインの最大数を使用します。たとえば、1 つの可用性セットに 2 つ以上の VM をデプロイする場合は、Azure の計画メンテナンスに加えて、潜在的な物理ハードウェア障害、ネットワークの停止、または停電の影響を制限するために、最大数の障害ドメイン (3 つ) と十分な更新ドメインを使用します。障害ドメインの既定の数は 2 であり、後でオンラインで変更することはできません。", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "ae4ecb95-b70f-428f-8b9a-4c5b7e3478a2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "高い", + "subcategory": "高可用性", + "text": "可用性セットのデプロイで Azure 近接通信配置グループを使用する場合は、3 つの SAP コンポーネント (セントラル サービス、アプリケーション サーバー、データベース) をすべて同じ近接通信配置グループに含める必要があります。" + }, + { + "category": "ビジネス継続性と災害復旧", + "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "高い", + "subcategory": "高可用性", + "text": "SAP SID ごとに 1 つの近接配置グループを使用します。グループは、Availability Zones や Azure リージョンにまたがっていません" + }, { "category": "計算する", "guid": "2829e2ed-b217-4367-9aff-6691b4935ada", @@ -274,7 +365,7 @@ "link": "https://learn.microsoft.com/azure/quotas/quotas-overview", "severity": "高い", "subcategory": "サブスクリプション", - "text": "サブスクリプションのプロビジョニングの一環としてクォータの増加を確認する (例: サブスクリプション内で使用可能な VM コアの合計)", + "text": "サブスクリプションのプロビジョニングの一環としてクォータを確実に増やす (例: サブスクリプション内で使用可能な VM コアの合計数)", "training": "https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits" }, { @@ -299,7 +390,7 @@ "link": "https://azure.microsoft.com/explore/global-infrastructure/products-by-region/", "severity": "高い", "subcategory": "サブスクリプション", - "text": "必要なサービスと機能が、選択したデプロイ リージョン内で利用可能であることを確認します。ANF、ゾーンなど", + "text": "必要なサービスと機能が、選択した展開リージョン内で利用可能であることを確認します。ANF、ゾーンなど", "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/migrate/azure-best-practices/multiple-regions?source=recommendations" }, { @@ -308,7 +399,7 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-resource-organization", "severity": "中程度", "subcategory": "サブスクリプション", - "text": "コストの分類とリソースのグループ化 (BillTo、部門 (または部署)、環境 (運用、ステージング、開発)、層 (Web 層、アプリケーション層)、アプリケーション所有者、プロジェクト名) に Azure リソース タグを活用します", + "text": "コストの分類とリソースのグループ化 (BillTo、部門 (または部署)、環境 (運用、ステージ、開発)、層 (Web 層、アプリケーション層)、アプリケーション所有者、プロジェクト名) に Azure リソース タグを活用します", "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/" }, { @@ -326,7 +417,7 @@ "link": "https://learn.microsoft.com/azure/azure-netapp-files/azacsnap-introduction", "severity": "中程度", "subcategory": "BCDR (英語)", - "text": "HANA、Oracle、または DB2 データベース用に Azure NetApp Files をデプロイする場合は、Azure アプリケーション整合性スナップショット ツール (AzAcSnap) を使用して、アプリケーション整合性スナップショットを作成します。AzAcSnap は Oracle データベースもサポートしています。個々の VM ではなく、中央の VM で AzAcSnap を使用することを検討してください。" + "text": "HANA、Oracle、または DB2 データベースに Azure NetApp Files をデプロイする場合は、Azure アプリケーション整合性スナップショット ツール (AzAcSnap) を使用して、アプリケーション整合性スナップショットを作成します。AzAcSnap は Oracle データベースもサポートしています。個々の VM ではなく、中央の VM で AzAcSnap を使用することを検討してください。" }, { "category": "管理と監視", @@ -552,7 +643,7 @@ "link": "https://learn.microsoft.com/azure/virtual-network/virtual-network-peering-overview", "severity": "中程度", "subcategory": "ハイブリッド", - "text": "ローカルおよびグローバル VNet ピアリングは接続を提供し、複数の Azure リージョンにまたがる SAP デプロイのランディング ゾーン間の接続を確保するための推奨されるアプローチです", + "text": "ローカルとグローバルの VNet ピアリングは接続を提供し、複数の Azure リージョンにまたがる SAP デプロイのランディング ゾーン間の接続を確保するための推奨されるアプローチです", "training": "https://learn.microsoft.com/training/modules/configure-vnet-peering/?source=recommendations" }, { @@ -561,7 +652,7 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/planning-guide", "severity": "高い", "subcategory": "ハイブリッド", - "text": "SAP アプリケーションと SAP データベース サーバーの間に NVA をデプロイすることはサポートされていません", + "text": "SAP アプリケーションと SAP データベース サーバー間の NVA のデプロイはサポートされていません", "training": "https://me.sap.com/notes/2731110" }, { @@ -660,7 +751,7 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", "severity": "中程度", "subcategory": "インターネット", - "text": "Azure Front Door と Application Gateway を使用して HTTP/S アプリケーションを保護する場合は、Azure Front Door の Web アプリケーション ファイアウォール ポリシーを活用します。Application Gateway をロックダウンして、Azure Front Door からのトラフィックのみを受信します。", + "text": "Azure Front Door と Application Gateway を使用して HTTP/S アプリケーションを保護する場合は、Azure Front Door の Web アプリケーション ファイアウォール ポリシーを利用します。Application Gateway をロックダウンして、Azure Front Door からのトラフィックのみを受信します。", "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations" }, { @@ -669,7 +760,7 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "severity": "中程度", "subcategory": "インターネット", - "text": "Web アプリケーション ファイアウォールを使用して、インターネットに公開されているトラフィックをスキャンします。もう 1 つのオプションは、ロード バランサー、または Application Gateway やサードパーティ ソリューションなどのファイアウォール機能が組み込まれているリソースと共に使用することです。", + "text": "Web アプリケーション ファイアウォールを使用して、インターネットに公開されているトラフィックをスキャンします。別のオプションとして、ロード バランサーや、Application Gateway やサードパーティ ソリューションなどのファイアウォール機能が組み込まれているリソースと共に使用することもできます。", "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations" }, { @@ -687,7 +778,7 @@ "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", "severity": "中程度", "subcategory": "インターネット", - "text": "データ漏えいを防ぐには、Azure Private Link を使用して、Azure Blob Storage、Azure Files、Azure Data Lake Storage Gen2、Azure Data Factory などのサービスとしてのプラットフォーム リソースに安全にアクセスします。Azure プライベート エンドポイントは、VNet と Azure Storage、Azure Backup などのサービス間のトラフィックをセキュリティで保護するのにも役立ちます。VNet とプライベート エンドポイント対応サービス間のトラフィックは、Microsoft グローバル ネットワークを経由するため、パブリック インターネットへの公開が防止されます。", + "text": "データ漏えいを防ぐには、Azure Private Link を使用して、Azure Blob Storage、Azure Files、Azure Data Lake Storage Gen2、Azure Data Factory などのサービスとしてのプラットフォーム リソースに安全にアクセスします。Azure プライベート エンドポイントは、VNet と Azure Storage、Azure Backup などのサービス間のトラフィックをセキュリティで保護するのにも役立ちます。VNet とプライベート エンドポイント対応サービス間のトラフィックは、Microsoft グローバル ネットワークを経由するため、パブリック インターネットへの公開は防止されます。", "training": "https://learn.microsoft.com/training/modules/design-implement-private-access-to-azure-services/?source=recommendations" }, { @@ -750,7 +841,7 @@ "link": "https://me.sap.com/notes/2015553", "severity": "高い", "subcategory": "セグメンテーション", - "text": "SAP システムのデータベース管理システム (DBMS) とアプリケーション レイヤーを異なる VNet でホストし、それらを VNet ピアリングに接続することは、レイヤー間の過剰なネットワーク トラフィックによって生成される可能性があるため、お勧めしません。Azure 仮想ネットワーク内のサブネットを使用して、SAP アプリケーション レイヤーと DBMS レイヤーを分離することをお勧めします。", + "text": "SAP システムのデータベース管理システム (DBMS) レイヤーとアプリケーション レイヤーを異なる VNet でホストし、それらを VNet ピアリングに接続することは、レイヤー間の過剰なネットワーク トラフィックによって生成される可能性があるため、お勧めしません。Azure 仮想ネットワーク内のサブネットを使用して、SAP アプリケーション レイヤーと DBMS レイヤーを分離することをお勧めします。", "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity" }, { @@ -781,51 +872,56 @@ }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "209d490d-a477-4784-84d1-16785d2fa56c", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "高い", + "guid": "18dffcf3-248c-4039-a67c-dec8e3a5f804", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", + "severity": "中程度", "subcategory": "統治", - "text": "SAP on Azure スポーク サブスクリプションのロールベースのアクセス制御 (RBAC) ロールをカスタマイズして、偶発的なネットワーク関連の変更を回避します" + "text": "Azure、オンプレミス、またはその他のクラウド環境で Windows VM と Linux VM を実行している場合は、Azure Automation の更新管理センターを使用して、セキュリティ パッチを含むオペレーティング システムの更新プログラムを管理できます。", + "training": "https://learn.microsoft.com/azure/automation/update-management/overview" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "08951710-79a2-492a-adbc-06d7a401545b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", "severity": "中程度", "subcategory": "統治", - "text": "DMZ と NVA を SAP 資産の残りの部分から分離し、Azure Private Link を構成し、SAP on Azure リソースを安全に管理および制御します" + "text": "SAP は、SAP システムを保護するために即時のアクションを必要とする非常に重要なセキュリティ パッチまたはホット フィックスをリリースしているため、SAP セキュリティ OSS ノートを定期的に確認してください。", + "training": "https://support.sap.com/en/my-support/knowledge-base/security-notes-news.html" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "中程度", + "guid": "1b8b394e-ae64-4a74-8933-357b523ea0a0", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "低い", "subcategory": "統治", - "text": "SAP データベース サーバーの暗号化には、SAP HANA ネイティブ暗号化テクノロジを使用します。Azure SQL Database を使用している場合は、DBMS プロバイダーが提供する Transparent Data Encryption (TDE) を使用して、データとログ ファイルをセキュリティで保護し、バックアップも暗号化されるようにします。" + "text": "SQL Server 上の SAP システムではアカウントを使用しないため、SQL Server 上の SAP システム管理者アカウントを無効にすることができます。元のシステム管理者アカウントを無効にする前に、システム管理者権限を持つ別のユーザーがサーバーにアクセスできることを確認してください。" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "中程度", + "guid": "5a76a033-ced9-4eef-9a43-5e4f96634c8e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "高い", "subcategory": "統治", - "text": "Azure Storage の暗号化は既定で有効になっています" + "text": "xp_cmdshellを無効にします。SQL Server 機能xp_cmdshell、SQL Server 内部オペレーティング システムのコマンド シェルを有効にします。これは、セキュリティ監査における潜在的なリスクです。", + "training": "https://me.sap.com/notes/3019299/E" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "中程度", - "subcategory": "統治", - "text": " " + "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "高い", + "subcategory": "秘密", + "text": "Azrue での SAP HANA データベース サーバーの暗号化では、SAP HANA ネイティブ暗号化テクノロジが使用されます。さらに、Azure で SQL Server を使用している場合は、Transparent Data Encryption (TDE) を使用してデータとログ ファイルを保護し、バックアップも暗号化されるようにします。", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", "severity": "中程度", - "subcategory": "統治", - "text": " " + "subcategory": "秘密", + "text": "Azure Storage の暗号化は、すべての Azure Resource Manager とクラシック ストレージ アカウントに対して有効になっており、無効にすることはできません。データは既定で暗号化されるため、Azure Storage 暗号化を使用するためにコードやアプリケーションを変更する必要はありません。", + "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", @@ -833,95 +929,160 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/overview", "severity": "高い", "subcategory": "秘密", - "text": "Azure Key Vault を使用してシークレットと資格情報を格納する" + "text": "Azure Key Vault を使用してシークレットと資格情報を格納する", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", "guid": "829e2edb-2173-4676-aff6-691b4935ada4", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview-throttling", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", "severity": "中程度", "subcategory": "秘密", - "text": "デプロイが成功したら Azure リソースをロックして、承認されていない変更から保護することをお勧めします" + "text": "デプロイが成功したら、Azure リソースを LOCK して、承認されていない変更から保護することをお勧めします。また、カスタマイズされた Azure ポリシー (Custome ロール) を使用して、サブスクリプションごとに LOCK の制約とルールを適用することもできます。", + "training": "https://learn.microsoft.com/training/modules/use-azure-resource-manager/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", "guid": "2223ece8-1b12-4318-8a54-17415833fb4a", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", "severity": "中程度", "subcategory": "秘密", - "text": "論理的な削除ポリシーと消去ポリシーを有効にして Azure Key Vault をプロビジョニングし、削除されたオブジェクトの保持保護を許可します。" + "text": "論理的な削除ポリシーと消去ポリシーを有効にして Azure Key Vault をプロビジョニングし、削除されたオブジェクトの保持保護を許可します。", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", "guid": "e3c2df74-3165-4c3a-abe0-5bbe209d490d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中程度", + "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", + "severity": "高い", "subcategory": "秘密", - "text": "既存の要件、規制、コンプライアンス制御 (内部/外部) に基づいて、必要な Azure ポリシーと Azure RBAC ロールを決定します" + "text": "既存の要件、規制、コンプライアンス制御 (内部/外部) に基づいて、必要な Azure ポリシーと Azure RBAC ロールを決定します", + "training": "https://learn.microsoft.com/training/paths/describe-azure-management-governance/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", "guid": "a4777842-4d11-4678-9d2f-a56c56ad4840", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中程度", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "高い", "subcategory": "秘密", - "text": "Microsoft Defender for Cloud Standard for SAP を有効にする場合は、エンドポイント保護をインストールするポリシーから SAP データベース サーバーを除外してください。" + "text": "SAP 環境でMicrosoft Defender for Endpointを有効にする場合は、すべてのサーバーを対象とするのではなく、DBMS サーバー上のデータとログ ファイルを除外することをお勧めします。ターゲット ファイルを除外する場合は、DBMS ベンダーの推奨事項に従ってください。", + "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/microsoft-defender-endpoint-mde-for-sap-applications-on-windows/ba-p/3912268" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", "guid": "8fe72734-c486-4ba2-a0dc-0591cf65de8e", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中程度", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/just-in-time-access-overview?tabs=defender-for-container-arch-aks", + "severity": "高い", "subcategory": "秘密", - "text": "ジャストインタイムアクセス権を持つ SAP 管理者カスタム ロールを委任します。" + "text": "Microsoft Defender for Cloud の Just-In-Time アクセス権を持つ SAP 管理者カスタム ロールを委任します。", + "training": "https://learn.microsoft.com/training/modules/secure-vms-with-azure-security-center/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", "guid": "1309cccd-5792-466b-aca2-75faa1abfe9d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中程度", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "低い", "subcategory": "秘密", - "text": "サードパーティのセキュリティ製品を DIAG (SAP GUI)、RFC、および HTTPS の SPNEGO のセキュアネットワーク通信 (SNC) と統合することにより、転送中のデータを暗号化します。" + "text": "サードパーティのセキュリティ製品を DIAG (SAP GUI)、RFC、および SPNEGO for HTTPS のセキュアネットワーク通信 (SNC) と統合することにより、転送中のデータを暗号化します。", + "training": "https://learn.microsoft.com/azure/security/fundamentals/encryption-overview#encryption-of-data-in-transit" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "55d04c3c-4919-4cb1-a3d1-325ae124ba34", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", + "link": "https://learn.microsoft.com/azure/storage/common/storage-encryption-key-model-get?tabs=portal", "severity": "中程度", "subcategory": "秘密", - "text": "SAML 2.0 を使用した Azure Active Directory (Azure AD) では、SAP NetWeaver、SAP HANA、SAP Cloud Platform など、さまざまな SAP アプリケーションやプラットフォームに SSO を提供することもできます" + "text": "プリンシパル暗号化機能には既定で Microsoft マネージド キーを使用し、必要に応じてカスタマー マネージド キーを使用します。", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "df685edd-ce9b-4d3b-a0cd-b3b55eb2ec14", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中程度", + "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "link": "https://learn.microsoft.com/ja-jp/azure/key-vault/general/best-practices", + "severity": "高い", "subcategory": "秘密", - "text": "SAP データベースへの攻撃につながる可能性のある脆弱性を根絶するために、オペレーティング システムを強化してください。" + "text": "Azure Key Vault は、アプリケーションごと、環境ごと、リージョンごとに使用します。", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中程度", + "guid": "abc9634d-c44d-41e9-a530-e8444e16aa3c", + "link": "https://learn.microsoft.com/azure/key-vault/certificates/certificate-scenarios", + "severity": "高い", "subcategory": "秘密", - "text": "プリンシパル暗号化機能には既定で Microsoft マネージド キーを使用し、必要に応じてカスタマー マネージド キーを使用します。" + "text": "HANA 以外の Windows オペレーティング システムと Windows 以外のオペレーティング システムのディスク暗号化キーとシークレットを制御および管理するには、Azure Key Vault を使用します。SAP HANA は Azure Key Vault ではサポートされていないため、SAP ABAP キーや SSH キーなどの代替方法を使用する必要があります。", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/?source=recommendations" }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "severity": "中程度", "subcategory": "秘密", - "text": "Azure Key Vault は、アプリケーションごと、環境ごと、リージョンごとに使用します。" + "text": " " }, { "category": "セキュリティ、ガバナンス、コンプライアンス", - "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "209d490d-a477-4784-84d1-16785d2fa56c", + "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles", + "severity": "高い", + "subcategory": "安全", + "text": "SAP on Azure スポーク サブスクリプションのロールベースのアクセス制御 (RBAC) ロールをカスタマイズして、偶発的なネットワーク関連の変更を回避します", + "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations" + }, + { + "category": "セキュリティ、ガバナンス、コンプライアンス", + "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", + "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/", + "severity": "高い", + "subcategory": "安全", + "text": "DMZ と NVA を SAP 資産の残りの部分から分離し、Azure Private Link を構成し、SAP on Azure リソースを安全に管理および制御します", + "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal" + }, + { + "category": "セキュリティ、ガバナンス、コンプライアンス", + "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", + "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", + "severity": "低い", + "subcategory": "安全", + "text": "Azure で Microsoft マルウェア対策ソフトウェアを使用して、悪意のあるファイル、アドウェア、その他の脅威から仮想マシンを保護することを検討してください。", + "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/" + }, + { + "category": "セキュリティ、ガバナンス、コンプライアンス", + "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", + "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", + "severity": "低い", + "subcategory": "安全", + "text": "さらに強力な保護を行うには、Microsoft Defender for Endpointの使用を検討してください。", + "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations" + }, + { + "category": "セキュリティ、ガバナンス、コンプライアンス", + "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "severity": "高い", + "subcategory": "安全", + "text": "仮想ネットワーク ピアリングによってスポーク ネットワークに接続されているハブ仮想ネットワークを介してすべてのトラフィックを渡すことで、SAP アプリケーションとデータベース サーバーをインターネットまたはオンプレミス ネットワークから分離します。ピアリングされた仮想ネットワークにより、SAP on Azure ソリューションがパブリック インターネットから分離されることが保証されます。", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations" + }, + { + "category": "セキュリティ、ガバナンス、コンプライアンス", + "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "低い", + "subcategory": "安全", + "text": "SAP Fiori などのインターネットに接続するアプリケーションの場合は、セキュリティレベルを維持しながら、アプリケーション要件ごとに負荷を分散してください。レイヤー 7 セキュリティについては、Azure Marketplace で入手できるサードパーティの Web アプリケーション ファイアウォール (WAF) を使用できます。", + "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations" + }, + { + "category": "セキュリティ、ガバナンス、コンプライアンス", + "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", + "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions", "severity": "中程度", - "subcategory": "秘密", - "text": " " + "subcategory": "安全", + "text": "Azure Monitor for SAP solutions でセキュリティで保護された通信を有効にするには、ルート証明書またはサーバー証明書のいずれかを使用することを選択できます。ルート証明書を使用することを強くお勧めします。", + "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations" }, { "category": "貯蔵", @@ -934,7 +1095,7 @@ "metadata": { "name": "Azure Landing Zone Review", "state": "Preview", - "timestamp": "November 24, 2023" + "timestamp": "January 11, 2024" }, "severities": [ { diff --git a/checklists/sap_checklist.ko.json b/checklists/sap_checklist.ko.json index 5038ee792..4df3305dc 100644 --- a/checklists/sap_checklist.ko.json +++ b/checklists/sap_checklist.ko.json @@ -17,38 +17,6 @@ } ], "items": [ - { - "category": "비즈니스 연속성 및 재해 복구", - "guid": "aff6691b-4935-4ada-9222-3ece81b12318", - "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-reports", - "severity": "보통", - "subcategory": " ", - "text": "ASCS와 데이터베이스 클러스터를 단일/동일한 VM에 결합하지 마세요." - }, - { - "category": "비즈니스 연속성 및 재해 복구", - "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export?tabs=portal", - "severity": "보통", - "subcategory": " ", - "text": "로드 밸런서에서 유동 IP가 사용하도록 설정되어 있는지 확인합니다." - }, - { - "category": "비즈니스 연속성 및 재해 복구", - "guid": "cbe05bbe-209d-4490-ba47-778424d11678", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "보통", - "subcategory": " ", - "text": "동일한 가용성 집합에 서로 다른 역할의 서버를 혼합하지 마십시오. 중앙 서비스 VM, 데이터베이스 VM, 애플리케이션 VM을 자체 가용성 집합으로 유지" - }, - { - "category": "비즈니스 연속성 및 재해 복구", - "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "보통", - "subcategory": " ", - "text": "SAP SID당 하나의 근접 배치 그룹을 사용합니다. 그룹은 가용성 영역 또는 Azure 지역에 걸쳐 있지 않습니다." - }, { "category": "비즈니스 연속성 및 재해 복구", "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", @@ -71,7 +39,7 @@ "link": "https://www.microsoft.com/itshowcase/implementing-a-zero-trust-security-model-at-microsoft", "severity": "보통", "subcategory": " ", - "text": "HA 쌍의 두 VM이 모두 가용성 집합에 배포되거나 가용성 영역의 크기와 스토리지 구성이 동일해야 합니다" + "text": "HA 쌍의 두 VM이 모두 가용성 집합에 배포되거나 가용성 영역의 크기가 동일하고 스토리지 구성이 동일해야 합니다" }, { "category": "비즈니스 연속성 및 재해 복구", @@ -110,6 +78,129 @@ "subcategory": " ", "text": "네이티브 데이터베이스 복제는 Azure Site Recovery가 아닌 DR 사이트에 데이터를 동기화하는 데 사용해야 합니다" }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "8300cb30-766b-4084-b126-0dd8fb1269a1", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-architecture-scenario", + "severity": "높다", + "subcategory": "고가용성", + "text": "단일 장애 지점에 대한 SAP 소프트웨어의 가용성을 고려합니다. 여기에는 SAP NetWeaver 및 SAP S/4HANA 아키텍처, SAP ABAP 및 ASCS + SCS에서 사용되는 DBMS와 같은 애플리케이션 내의 단일 실패 지점이 포함됩니다. 또한 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" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "56402f11-ccbe-42c3-a2f6-c6f6f38ab579", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-supported-configurations", + "severity": "높다", + "subcategory": "고가용성", + "text": "SAP 및 SAP 데이터베이스의 경우 자동 장애 조치(failover) 클러스터를 구현하는 것이 좋습니다. Windows에서 Windows Server 장애 조치(failover) 클러스터링은 장애 조치(failover)를 지원합니다. Linux에서 Linux Pacemaker 또는 SIOS Protection Suite 및 Veritas InfoScale과 같은 타사 툴은 장애 조치를 지원합니다.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "afae6bec-2671-49ae-bc69-140b8ec8d320", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", + "severity": "높다", + "subcategory": "고가용성", + "text": "Azure는 기본 및 보조 VM이 DBMS 데이터에 대한 스토리지를 공유하는 아키텍처를 지원하지 않습니다. DBMS 계층의 경우 일반적인 아키텍처 패턴은 기본 및 보조 VM에서 사용하는 것과 다른 스토리지 스택을 사용하여 동시에 데이터베이스를 복제하는 것입니다.", + "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" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "ac614e95-6767-4bc3-b8a4-9953533da6ba", + "link": "https://learn.microsoft.com/azure/sap/workloads/dbms-guide-general", + "severity": "높다", + "subcategory": "고가용성", + "text": "DBMS 데이터 및 트랜잭션/다시 실행 로그 파일은 Azure 지원 블록 스토리지 또는 Azure NetApp Files에 저장됩니다. Azure Files 또는 Azure Premium Files는 DBMS 데이터 및/또는 SAP 워크로드가 있는 다시 실행 로그 파일에 대한 스토리지로 지원되지 않습니다.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-databases/2-explore-database-support-azure-for-sap-workloads" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "1f737179-8e7f-4e1a-a30c-e5a649a3092b", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-wsfc-shared-disk", + "severity": "높다", + "subcategory": "고가용성", + "text": "ASCS + SCS 구성 요소 및 특정 고가용성 시나리오에 대해 Windows에서 Azure 공유 디스크를 사용할 수 있습니다. SAP 애플리케이션 계층 구성 요소 및 DBMS 계층에 대해 장애 조치(failover) 클러스터를 별도로 설정합니다. Azure는 현재 SAP 애플리케이션 계층 구성 요소와 DBMS 계층을 하나의 장애 조치(failover) 클러스터로 결합하는 고가용성 아키텍처를 지원하지 않습니다.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "a78b3d31-3170-44f2-b5d7-651a29f4ccf5", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-standard-load-balancer-outbound-connections", + "severity": "높다", + "subcategory": "고가용성", + "text": "SAP ASCS(애플리케이션 계층 구성 요소) 및 DBMS 계층에 대한 대부분의 장애 조치(failover) 클러스터에는 장애 조치(failover) 클러스터에 대한 가상 IP 주소가 필요합니다. Azure Load Balancer는 다른 모든 경우에 대한 가상 IP 주소를 처리해야 합니다. 한 가지 설계 원칙은 클러스터 구성당 하나의 부하 분산 장치를 사용하는 것입니다. 부하 분산 장치의 표준 버전(표준 Load Balancer SKU)을 사용하는 것이 좋습니다.", + "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-ha-ports-overview?source=recommendations", + "severity": "높다", + "subcategory": "고가용성", + "text": "로드 밸런서에서 유동 IP가 사용하도록 설정되어 있는지 확인합니다.", + "training": "https://learn.microsoft.com/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "c47cc4f3-f105-452c-845e-9b307b3856c1", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "severity": "높다", + "subcategory": "고가용성", + "text": "고가용성 인프라를 배포하기 전에 선택한 지역에 따라 Azure 가용성 집합 또는 가용성 영역을 사용하여 배포할지 여부를 결정합니다.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "844f69c3-07e5-4ec1-bff7-4be27bcf5fea", + "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", + "severity": "높다", + "subcategory": "고가용성", + "text": "SAP 구성 요소(중앙 서비스, 애플리케이션 서버 및 데이터베이스)용 애플리케이션에 대한 인프라 SLA를 충족하려면 모든 구성 요소에 대해 동일한 고가용성 옵션(VM, 가용성 집합, 가용성 영역)을 선택해야 합니다." + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "cbe05bbe-209d-4490-ba47-778424d11678", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "높다", + "subcategory": "고가용성", + "text": "동일한 가용성 집합에 서로 다른 역할의 서버를 혼합하지 마십시오. 중앙 서비스 VM, 데이터베이스 VM, 애플리케이션 VM을 자체 가용성 집합으로 유지", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "f2201000-d045-40a6-a79a-d7cdc01b4d86", + "link": "https://learn.microsoft.com/azure/virtual-machines/co-location", + "severity": "보통", + "subcategory": "고가용성", + "text": "근접 배치 그룹을 사용하지 않는 한 Azure 가용성 영역 내에 Azure 가용성 집합을 배포할 수 없습니다.", + "training": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "9674e7c7-7796-4181-8920-09f4429543ba", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "높다", + "subcategory": "고가용성", + "text": "가용성 집합을 만들 때 사용 가능한 최대 장애 도메인 및 업데이트 도메인 수를 사용합니다. 예를 들어 하나의 가용성 집합에 두 개 이상의 VM을 배포하는 경우 Azure의 계획된 유지 관리 외에도 잠재적인 물리적 하드웨어 오류, 네트워크 중단 또는 전원 중단의 영향을 제한하기 위해 최대 장애 도메인 수(3개)와 충분한 업데이트 도메인을 사용합니다. 장애 도메인의 기본 수는 2개이며 나중에 온라인으로 변경할 수 없습니다.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "ae4ecb95-b70f-428f-8b9a-4c5b7e3478a2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "높다", + "subcategory": "고가용성", + "text": "가용성 집합 배포에서 Azure 근접 배치 그룹을 사용하는 경우 세 가지 SAP 구성 요소(중앙 서비스, 애플리케이션 서버 및 데이터베이스)가 모두 동일한 근접 배치 그룹에 있어야 합니다." + }, + { + "category": "비즈니스 연속성 및 재해 복구", + "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "높다", + "subcategory": "고가용성", + "text": "SAP SID당 하나의 근접 배치 그룹을 사용합니다. 그룹은 가용성 영역 또는 Azure 지역에 걸쳐 있지 않습니다." + }, { "category": "계산", "guid": "2829e2ed-b217-4367-9aff-6691b4935ada", @@ -174,7 +265,7 @@ "guid": "23181aa4-1742-4694-9ff8-ae7d7d474317", "severity": "보통", "subcategory": "신원", - "text": "SAP GUI 및 웹 브라우저 액세스를 위한 SSO의 경우 구성 및 유지 관리가 용이하여 SNC – Kerberos/SPNEGO(간단하고 보호된 GSSAPI 협상 메커니즘)를 구현합니다. X.509 클라이언트 인증서를 사용하는 SSO의 경우 SAP SSO 솔루션의 구성 요소인 SAP 보안 로그인 서버를 고려하십시오.", + "text": "SAP GUI 및 웹 브라우저 액세스를 위한 SSO의 경우 구성 및 유지 관리가 용이하기 때문에 SNC – Kerberos/SPNEGO(간단하고 보호된 GSSAPI 협상 메커니즘)를 구현합니다. X.509 클라이언트 인증서를 사용하는 SSO의 경우 SAP SSO 솔루션의 구성 요소인 SAP 보안 로그인 서버를 고려합니다.", "training": "https://learn.microsoft.com/training/modules/explore-identity-services/9-exercise-integrate-active-directory-sap-single-sign-on" }, { @@ -183,7 +274,7 @@ "link": "https://blogs.sap.com/2017/07/12/sap-single-sign-on-protect-your-sap-landscape-with-x.509-certificates/", "severity": "보통", "subcategory": "신원", - "text": "SAP GUI 및 웹 브라우저 액세스를 위한 SSO의 경우 구성 및 유지 관리가 용이하여 SNC – Kerberos/SPNEGO(간단하고 보호된 GSSAPI 협상 메커니즘)를 구현합니다. X.509 클라이언트 인증서를 사용하는 SSO의 경우 SAP SSO 솔루션의 구성 요소인 SAP 보안 로그인 서버를 고려하십시오." + "text": "SAP GUI 및 웹 브라우저 액세스를 위한 SSO의 경우 구성 및 유지 관리가 용이하기 때문에 SNC – Kerberos/SPNEGO(간단하고 보호된 GSSAPI 협상 메커니즘)를 구현합니다. X.509 클라이언트 인증서를 사용하는 SSO의 경우 SAP SSO 솔루션의 구성 요소인 SAP 보안 로그인 서버를 고려합니다." }, { "category": "ID 및 액세스", @@ -223,7 +314,7 @@ "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-hana-cloud-platform-identity-authentication-tutorial", "severity": "보통", "subcategory": "신원", - "text": "SAP IAS(Identity Authentication Service)가 필요한 SAP BTP 서비스 또는 SaaS 솔루션을 사용하는 경우 SAP Cloud Identity Authentication Services와 Azure AD 간에 SSO를 구현하여 해당 SAP 서비스에 액세스하는 것이 좋습니다. 이 통합을 통해 SAP IAS는 프록시 ID 공급자 역할을 하고 인증 요청을 중앙 사용자 저장소 및 ID 공급자인 Azure AD에 전달할 수 있습니다." + "text": "SAP IAS(Identity Authentication Service)가 필요한 SAP BTP 서비스 또는 SaaS 솔루션을 사용하는 경우 SAP Cloud Identity Authentication Services와 Azure AD 간에 SSO를 구현하여 해당 SAP 서비스에 액세스하는 것이 좋습니다. 이 통합을 통해 SAP IAS는 프록시 ID 공급자 역할을 하고 중앙 사용자 저장소 및 ID 공급자인 Azure AD에 인증 요청을 전달할 수 있습니다." }, { "category": "ID 및 액세스", @@ -265,7 +356,7 @@ "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", "severity": "높다", "subcategory": "구독", - "text": "구독을 배율 단위로 활용하고 리소스를 확장하고, 예를 들어 환경별로 구독을 배포하는 것이 좋습니다. 샌드박스, 비프로덕션, 프로덕션 ", + "text": "구독을 배율 단위로 활용하고 리소스를 확장하려면 환경별로 구독을 배포하는 것이 좋습니다. 샌드박스, 비프로덕션, 프로덕션 ", "training": "https://learn.microsoft.com/training/modules/configure-subscriptions/?source=recommendations" }, { @@ -359,7 +450,7 @@ "link": "https://learn.microsoft.com/azure/lighthouse/overview", "severity": "보통", "subcategory": "경영", - "text": "SAP 자산을 관리하여 고객과 파트너 관계를 맺는 경우 Azure Lighthouse를 사용하는 것이 좋습니다. Azure Lighthouse를 사용하면 관리 서비스 공급자가 Azure 네이티브 ID 서비스를 사용하여 고객 환경에 인증할 수 있습니다. 고객은 언제든지 액세스 권한을 취소하고 서비스 제공업체의 조치를 감사할 수 있으므로 제어권을 고객에게 부여합니다." + "text": "SAP 자산을 관리하여 고객과 파트너 관계를 맺는 경우 Azure Lighthouse를 사용하는 것이 좋습니다. Azure Lighthouse를 사용하면 관리 서비스 공급자가 Azure 네이티브 ID 서비스를 사용하여 고객 환경에 인증할 수 있습니다. 고객은 언제든지 액세스 권한을 취소하고 서비스 제공업체의 조치를 감사할 수 있으므로 고객의 손에 제어 권한을 부여합니다." }, { "category": "관리 및 모니터링", @@ -624,7 +715,7 @@ "link": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-delegate-subnet", "severity": "보통", "subcategory": "IP 플랜", - "text": "Azure는 VNet에서 여러 위임된 서브넷을 만드는 데 도움이 되지만 Azure NetApp Files용 VNet에는 위임된 서브넷이 하나만 존재할 수 있습니다. Azure NetApp Files에 위임된 서브넷을 두 개 이상 사용하는 경우 새 볼륨을 만들려는 시도가 실패합니다.", + "text": "Azure는 VNet에서 여러 위임된 서브넷을 만드는 데 도움이 되지만 Azure NetApp Files용 VNet에는 위임된 서브넷이 하나만 존재할 수 있습니다. Azure NetApp Files에 대해 둘 이상의 위임된 서브넷을 사용하는 경우 새 볼륨을 만들려는 시도가 실패합니다.", "training": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-network-topologies?source=recommendations" }, { @@ -687,7 +778,7 @@ "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", "severity": "보통", "subcategory": "인터넷", - "text": "데이터 유출을 방지하려면 Azure Private Link를 사용하여 Azure Blob Storage, Azure Files, Azure Data Lake Storage Gen2, Azure Data Factory 등과 같은 PaaS(Platform as a Service) 리소스에 안전하게 액세스합니다. Azure 프라이빗 엔드포인트는 VNet과 Azure Storage, Azure Backup 등과 같은 서비스 간의 트래픽을 보호하는 데도 도움이 될 수 있습니다. VNet과 프라이빗 엔드포인트 지원 서비스 간의 트래픽은 Microsoft 글로벌 네트워크를 통해 이동하므로 공용 인터넷에 노출되지 않습니다.", + "text": "데이터 유출을 방지하려면 Azure Private Link를 사용하여 Azure Blob Storage, Azure Files, Azure Data Lake Storage Gen2, Azure Data Factory 등과 같은 PaaS(Platform as a Service) 리소스에 안전하게 액세스합니다. Azure 프라이빗 엔드포인트는 VNet과 Azure Storage, Azure Backup 등과 같은 서비스 간의 트래픽을 보호하는 데도 도움이 될 수 있습니다. VNet과 프라이빗 엔드포인트 사용 서비스 간의 트래픽은 Microsoft 글로벌 네트워크를 통해 이동하므로 공용 인터넷에 노출되지 않습니다.", "training": "https://learn.microsoft.com/training/modules/design-implement-private-access-to-azure-services/?source=recommendations" }, { @@ -750,7 +841,7 @@ "link": "https://me.sap.com/notes/2015553", "severity": "높다", "subcategory": "세분화", - "text": "계층 간의 과도한 네트워크 트래픽으로 인해 발생할 수 있는 상당한 비용 때문에 SAP 시스템의 DBMS(데이터베이스 관리 시스템) 및 애플리케이션 계층을 서로 다른 VNet에 호스트하고 VNet 피어링과 연결하는 것은 권장되지 않습니다. Azure 가상 네트워크 내에서 서브넷을 사용하여 SAP 애플리케이션 계층과 DBMS 계층을 분리하는 것이 좋습니다.", + "text": "계층 간의 과도한 네트워크 트래픽으로 인해 발생할 수 있는 상당한 비용 때문에 다른 VNet에서 SAP 시스템의 DBMS(데이터베이스 관리 시스템) 및 애플리케이션 계층을 호스트하고 VNet 피어링과 연결하는 것은 권장되지 않습니다. Azure 가상 네트워크 내에서 서브넷을 사용하여 SAP 애플리케이션 계층과 DBMS 계층을 분리하는 것이 좋습니다.", "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity" }, { @@ -781,51 +872,56 @@ }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "209d490d-a477-4784-84d1-16785d2fa56c", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "높다", + "guid": "18dffcf3-248c-4039-a67c-dec8e3a5f804", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", + "severity": "보통", "subcategory": "지배구조", - "text": "실수로 인한 네트워크 관련 변경을 방지하기 위해 Azure의 SAP 스포크 구독에 대한 RBAC(역할 기반 액세스 제어) 역할 사용자 지정" + "text": "Azure, 온-프레미스 또는 기타 클라우드 환경에서 Windows 및 Linux VM을 실행하는 경우 Azure Automation의 업데이트 관리 센터를 사용하여 보안 패치를 포함한 운영 체제 업데이트를 관리할 수 있습니다.", + "training": "https://learn.microsoft.com/azure/automation/update-management/overview" }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "08951710-79a2-492a-adbc-06d7a401545b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", "severity": "보통", "subcategory": "지배구조", - "text": "나머지 SAP 자산에서 DMZ 및 NVA를 격리하고, Azure Private Link를 구성하고, Azure의 SAP 리소스를 안전하게 관리 및 제어합니다" + "text": "SAP는 SAP 시스템을 보호하기 위해 즉각적인 조치가 필요한 매우 중요한 보안 패치 또는 핫픽스를 릴리스하므로 SAP 보안 OSS 노트를 정기적으로 검토합니다.", + "training": "https://support.sap.com/en/my-support/knowledge-base/security-notes-news.html" }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "보통", + "guid": "1b8b394e-ae64-4a74-8933-357b523ea0a0", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "낮다", "subcategory": "지배구조", - "text": "SAP 데이터베이스 서버 암호화의 경우 SAP HANA 네이티브 암호화 기술을 사용합니다. Azure SQL Database를 사용하는 경우 DBMS 공급자가 제공하는 TDE(투명한 데이터 암호화)를 사용하여 데이터 및 로그 파일을 보호하고 백업도 암호화되도록 합니다." + "text": "SQL Server SAP의 경우 SQL Server SAP 시스템에서 계정을 사용하지 않으므로 SQL Server 시스템 관리자 계정을 사용하지 않도록 설정할 수 있습니다. 원래 시스템 관리자 계정을 비활성화하기 전에 시스템 관리자 권한이 있는 다른 사용자가 서버에 액세스할 수 있는지 확인합니다." }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "보통", + "guid": "5a76a033-ced9-4eef-9a43-5e4f96634c8e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "높다", "subcategory": "지배구조", - "text": "Azure Storage 암호화는 기본적으로 사용하도록 설정되어 있습니다" + "text": "xp_cmdshell 비활성화합니다. SQL Server 기능 xp_cmdshell SQL Server 내부 운영 체제 명령 셸을 사용할 수 있습니다. 이는 보안 감사에서 발생할 수 있는 잠재적 위험입니다.", + "training": "https://me.sap.com/notes/3019299/E" }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "보통", - "subcategory": "지배구조", - "text": " " + "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "높다", + "subcategory": "비밀", + "text": "Azrue에서 SAP HANA 데이터베이스 서버를 암호화하는 데는 SAP HANA 네이티브 암호화 기술이 사용됩니다. 또한 Azure에서 SQL Server를 사용하는 경우 TDE(투명한 데이터 암호화)를 사용하여 데이터 및 로그 파일을 보호하고 백업도 암호화되도록 합니다.", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security" }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", "severity": "보통", - "subcategory": "지배구조", - "text": " " + "subcategory": "비밀", + "text": "Azure Storage 암호화는 모든 Azure Resource Manager 및 클래식 스토리지 계정에 대해 사용하도록 설정되며 사용하지 않도록 설정할 수 없습니다. 데이터는 기본적으로 암호화되므로 Azure Storage 암호화를 사용하기 위해 코드 또는 애플리케이션을 수정할 필요가 없습니다.", + "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", @@ -833,95 +929,160 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/overview", "severity": "높다", "subcategory": "비밀", - "text": "Azure Key Vault를 사용하여 비밀 및 자격 증명 저장" + "text": "Azure Key Vault를 사용하여 비밀 및 자격 증명 저장", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", "guid": "829e2edb-2173-4676-aff6-691b4935ada4", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview-throttling", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", "severity": "보통", "subcategory": "비밀", - "text": "무단 변경으로부터 보호하기 위해 성공적인 배포 후 Azure 리소스를 잠그는 것이 좋습니다" + "text": "무단 변경으로부터 보호하기 위해 성공적인 배포 후 Azure 리소스를 잠그는 것이 좋습니다. 사용자 지정된 Azure 정책(Custome 역할)을 사용하여 구독별로 LOCK 제약 조건 및 규칙을 적용할 수도 있습니다.", + "training": "https://learn.microsoft.com/training/modules/use-azure-resource-manager/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", "guid": "2223ece8-1b12-4318-8a54-17415833fb4a", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", "severity": "보통", "subcategory": "비밀", - "text": "삭제된 개체에 대한 보존 보호를 허용하기 위해 일시 삭제 및 제거 정책을 사용하도록 설정된 Azure Key Vault를 프로비전합니다." + "text": "삭제된 개체에 대한 보존 보호를 허용하기 위해 일시 삭제 및 제거 정책을 사용하도록 설정된 Azure Key Vault를 프로비전합니다.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", "guid": "e3c2df74-3165-4c3a-abe0-5bbe209d490d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "보통", + "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", + "severity": "높다", "subcategory": "비밀", - "text": "기존 요구 사항에 따라 규정 및 규정 준수 제어(내부/외부) - 필요한 Azure 정책 및 Azure RBAC 역할 결정" + "text": "기존 요구 사항에 따라 규정 및 규정 준수 제어(내부/외부) - 필요한 Azure 정책 및 Azure RBAC 역할 결정", + "training": "https://learn.microsoft.com/training/paths/describe-azure-management-governance/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", "guid": "a4777842-4d11-4678-9d2f-a56c56ad4840", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "보통", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "높다", "subcategory": "비밀", - "text": "SAP용 클라우드용 Microsoft Defender 표준을 사용하도록 설정하는 경우 엔드포인트 보호를 설치하는 정책에서 SAP 데이터베이스 서버를 제외해야 합니다." + "text": "SAP 환경에서 엔드포인트용 Microsoft Defender 사용하도록 설정하는 경우 모든 서버를 대상으로 하는 대신 DBMS 서버에서 데이터 및 로그 파일을 제외하는 것이 좋습니다. 대상 파일을 제외할 때 DBMS 공급업체의 권장 사항을 따릅니다.", + "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/microsoft-defender-endpoint-mde-for-sap-applications-on-windows/ba-p/3912268" }, { "category": "보안, 거버넌스 및 규정 준수", "guid": "8fe72734-c486-4ba2-a0dc-0591cf65de8e", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "보통", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/just-in-time-access-overview?tabs=defender-for-container-arch-aks", + "severity": "높다", "subcategory": "비밀", - "text": "Just-In-Time 액세스 권한이 있는 SAP 관리자 사용자 지정 역할을 위임합니다." + "text": "클라우드용 Microsoft Defender의 Just-In-Time 액세스 권한이 있는 SAP 관리자 사용자 지정 역할을 위임합니다.", + "training": "https://learn.microsoft.com/training/modules/secure-vms-with-azure-security-center/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", "guid": "1309cccd-5792-466b-aca2-75faa1abfe9d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "보통", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "낮다", "subcategory": "비밀", - "text": "타사 보안 제품을 DIAG(SAP GUI)용 SNC(Secure Network Communications), RFC 및 HTTPS용 SPNEGO와 통합하여 전송 중인 데이터를 암호화합니다." + "text": "타사 보안 제품을 DIAG(SAP GUI)용 SNC(Secure Network Communications), RFC 및 HTTPS용 SPNEGO와 통합하여 전송 중인 데이터를 암호화합니다.", + "training": "https://learn.microsoft.com/azure/security/fundamentals/encryption-overview#encryption-of-data-in-transit" }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "55d04c3c-4919-4cb1-a3d1-325ae124ba34", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", + "link": "https://learn.microsoft.com/azure/storage/common/storage-encryption-key-model-get?tabs=portal", "severity": "보통", "subcategory": "비밀", - "text": "SAML 2.0을 사용하는 Azure AD(Azure Active Directory)는 SAP NetWeaver, SAP HANA 및 SAP Cloud Platform과 같은 다양한 SAP 애플리케이션 및 플랫폼에 SSO를 제공할 수도 있습니다" + "text": "보안 주체 암호화 기능을 위해 기본적으로 Microsoft 관리형 키를 사용하고 필요한 경우 고객 관리형 키를 사용합니다.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "df685edd-ce9b-4d3b-a0cd-b3b55eb2ec14", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "보통", + "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "link": "https://learn.microsoft.com/ja-jp/azure/key-vault/general/best-practices", + "severity": "높다", "subcategory": "비밀", - "text": "SAP 데이터베이스에 대한 공격으로 이어질 수 있는 취약성을 근절하기 위해 운영 체제를 강화해야 합니다." + "text": "애플리케이션, 환경, 지역당 Azure Key Vault를 사용합니다.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "보통", + "guid": "abc9634d-c44d-41e9-a530-e8444e16aa3c", + "link": "https://learn.microsoft.com/azure/key-vault/certificates/certificate-scenarios", + "severity": "높다", "subcategory": "비밀", - "text": "보안 주체 암호화 기능을 위해 기본적으로 Microsoft 관리형 키를 사용하고 필요한 경우 고객 관리형 키를 사용합니다." + "text": "비 HANA Windows 및 비 Windows 운영 체제에 대한 디스크 암호화 키 및 비밀을 제어하고 관리하려면 Azure Key Vault를 사용합니다. SAP HANA는 Azure Key Vault에서 지원되지 않으므로 SAP ABAP 또는 SSH 키와 같은 대체 방법을 사용해야 합니다.", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/?source=recommendations" }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "severity": "보통", "subcategory": "비밀", - "text": "애플리케이션, 환경, 지역당 Azure Key Vault를 사용합니다." + "text": " " }, { "category": "보안, 거버넌스 및 규정 준수", - "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "209d490d-a477-4784-84d1-16785d2fa56c", + "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles", + "severity": "높다", + "subcategory": "안전", + "text": "실수로 인한 네트워크 관련 변경을 방지하기 위해 Azure의 SAP 스포크 구독에 대한 RBAC(역할 기반 액세스 제어) 역할 사용자 지정", + "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations" + }, + { + "category": "보안, 거버넌스 및 규정 준수", + "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", + "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/", + "severity": "높다", + "subcategory": "안전", + "text": "나머지 SAP 자산에서 DMZ 및 NVA를 격리하고, Azure Private Link를 구성하고, Azure의 SAP 리소스를 안전하게 관리 및 제어합니다", + "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal" + }, + { + "category": "보안, 거버넌스 및 규정 준수", + "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", + "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", + "severity": "낮다", + "subcategory": "안전", + "text": "Azure에서 Microsoft 맬웨어 방지 소프트웨어를 사용하여 악성 파일, 애드웨어 및 기타 위협으로부터 가상 머신을 보호하는 것이 좋습니다.", + "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/" + }, + { + "category": "보안, 거버넌스 및 규정 준수", + "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", + "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", + "severity": "낮다", + "subcategory": "안전", + "text": "더욱 강력한 보호를 위해 엔드포인트용 Microsoft Defender 사용하는 것이 좋습니다.", + "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations" + }, + { + "category": "보안, 거버넌스 및 규정 준수", + "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "severity": "높다", + "subcategory": "안전", + "text": "가상 네트워크 피어링을 통해 스포크 네트워크에 연결된 허브 가상 네트워크를 통해 모든 트래픽을 전달하여 SAP 애플리케이션 및 데이터베이스 서버를 인터넷 또는 온-프레미스 네트워크에서 격리합니다. 피어링된 가상 네트워크는 Azure의 SAP 솔루션이 공용 인터넷에서 격리되도록 보장합니다.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations" + }, + { + "category": "보안, 거버넌스 및 규정 준수", + "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "낮다", + "subcategory": "안전", + "text": "SAP Fiori와 같은 인터넷 연결 애플리케이션의 경우 보안 수준을 유지하면서 애플리케이션 요구 사항에 따라 부하를 분산해야 합니다. 계층 7 보안의 경우 Azure Marketplace에서 사용할 수 있는 타사 WAF(Web Application Firewall)를 사용할 수 있습니다.", + "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations" + }, + { + "category": "보안, 거버넌스 및 규정 준수", + "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", + "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions", "severity": "보통", - "subcategory": "비밀", - "text": " " + "subcategory": "안전", + "text": "SAP용 Azure Monitor 솔루션에서 보안 통신을 사용하도록 설정하려면 루트 인증서 또는 서버 인증서를 사용하도록 선택할 수 있습니다. 루트 인증서를 사용하는 것이 좋습니다.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations" }, { "category": "보관", @@ -934,7 +1095,7 @@ "metadata": { "name": "Azure Landing Zone Review", "state": "Preview", - "timestamp": "November 24, 2023" + "timestamp": "January 11, 2024" }, "severities": [ { diff --git a/checklists/sap_checklist.pt.json b/checklists/sap_checklist.pt.json index fad52d784..cfbba1bcd 100644 --- a/checklists/sap_checklist.pt.json +++ b/checklists/sap_checklist.pt.json @@ -17,38 +17,6 @@ } ], "items": [ - { - "category": "Continuidade de negócios e recuperação de desastres", - "guid": "aff6691b-4935-4ada-9222-3ece81b12318", - "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-reports", - "severity": "Média", - "subcategory": " ", - "text": "Não combinar ASCS e cluster de banco de dados em uma única ou mesma VM" - }, - { - "category": "Continuidade de negócios e recuperação de desastres", - "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export?tabs=portal", - "severity": "Média", - "subcategory": " ", - "text": "Verifique se o IP flutuante está habilitado no balanceador de carga" - }, - { - "category": "Continuidade de negócios e recuperação de desastres", - "guid": "cbe05bbe-209d-4490-ba47-778424d11678", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "Média", - "subcategory": " ", - "text": "Não misture servidores de funções diferentes no mesmo conjunto de disponibilidade. Mantenha VMs de serviços centrais, VMs de banco de dados, VMs de aplicativos em seus próprios conjuntos de disponibilidade" - }, - { - "category": "Continuidade de negócios e recuperação de desastres", - "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "Média", - "subcategory": " ", - "text": "Use um grupo de posicionamento de proximidade por SAP SID. Os grupos não se estendem por zonas de disponibilidade ou regiões do Azure" - }, { "category": "Continuidade de negócios e recuperação de desastres", "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", @@ -63,7 +31,7 @@ "link": "https://learn.microsoft.com/security/benchmark/azure/security-control-incident-response", "severity": "Média", "subcategory": " ", - "text": "Usar um SKU do Standard Load Balancer na frente de clusters ASCS e DB" + "text": "Usar uma SKU do Standard Load Balancer na frente de clusters ASCS e DB" }, { "category": "Continuidade de negócios e recuperação de desastres", @@ -71,7 +39,7 @@ "link": "https://www.microsoft.com/itshowcase/implementing-a-zero-trust-security-model-at-microsoft", "severity": "Média", "subcategory": " ", - "text": "Ambas as VMs no par de HA devem ser implantadas em um conjunto de disponibilidade, ou as zonas de disponibilidade devem ter o mesmo tamanho e a mesma configuração de armazenamento" + "text": "Ambas as VMs no par de HAs devem ser implantadas em um conjunto de disponibilidade, ou as zonas de disponibilidade devem ter o mesmo tamanho e a mesma configuração de armazenamento" }, { "category": "Continuidade de negócios e recuperação de desastres", @@ -94,7 +62,7 @@ "guid": "81b12318-1a54-4174-8583-3fb4ae3c2df7", "severity": "Média", "subcategory": " ", - "text": "O CIDR para a rede virtual primária (VNet) não deve entrar em conflito ou se sobrepor ao CIDR da Vnet do site de DR" + "text": "O CIDR para a rede virtual primária (VNet) não deve entrar em conflito ou se sobrepor ao CIDR da Vnet do site de recuperação de desastres" }, { "category": "Continuidade de negócios e recuperação de desastres", @@ -110,6 +78,129 @@ "subcategory": " ", "text": "A replicação de banco de dados nativo deve ser usada para sincronizar dados com o site de recuperação de desastres, em vez do Azure Site Recovery" }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "8300cb30-766b-4084-b126-0dd8fb1269a1", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-architecture-scenario", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Considere a disponibilidade do software SAP em relação a pontos únicos de falha. Isso inclui pontos únicos de falha em aplicativos como SGBDs utilizados nas arquiteturas SAP NetWeaver e SAP S/4HANA, SAP ABAP e ASCS + SCS. Além disso, outras ferramentas, como o 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" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "56402f11-ccbe-42c3-a2f6-c6f6f38ab579", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-supported-configurations", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Para bancos de dados SAP e SAP, considere a implementação de clusters de failover automático. No Windows, o Clustering de Failover do Windows Server oferece suporte a failover. No Linux, Linux Pacemaker ou ferramentas de terceiros como SIOS Protection Suite e Veritas InfoScale suportam failover.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "afae6bec-2671-49ae-bc69-140b8ec8d320", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "O Azure não oferece suporte a arquiteturas nas quais as VMs primária e secundária compartilham armazenamento para dados DBMS. Para a camada DBMS, o padrão de arquitetura comum é replicar bancos de dados ao mesmo tempo e com pilhas de armazenamento diferentes daquelas que as VMs primária e secundária usam.", + "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" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "ac614e95-6767-4bc3-b8a4-9953533da6ba", + "link": "https://learn.microsoft.com/azure/sap/workloads/dbms-guide-general", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Os dados do DBMS e os arquivos de log de transação/refazer são armazenados no armazenamento em bloco com suporte do Azure ou nos Arquivos do Azure NetApp. Os Arquivos do Azure ou os Arquivos Premium do Azure não têm suporte como armazenamento para dados DBMS e/ou arquivos de log de refazer com a carga de trabalho SAP.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-databases/2-explore-database-support-azure-for-sap-workloads" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "1f737179-8e7f-4e1a-a30c-e5a649a3092b", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-wsfc-shared-disk", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Você pode usar discos compartilhados do Azure no Windows para componentes ASCS + SCS e cenários específicos de alta disponibilidade. Configure seus clusters de failover separadamente para componentes da camada de aplicativo SAP e a camada DBMS. No momento, o Azure não oferece suporte a arquiteturas de alta disponibilidade que combinam componentes da camada de aplicativo SAP e a camada DBMS em um cluster de failover.", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "a78b3d31-3170-44f2-b5d7-651a29f4ccf5", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-standard-load-balancer-outbound-connections", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "A maioria dos clusters de failover para ASCS (Application Layer Components, componentes da camada de aplicativo) SAP e a camada DBMS exigem um endereço IP virtual para um cluster de failover. O Balanceador de Carga do Azure deve manipular o endereço IP virtual para todos os outros casos. Um princípio de design é usar um balanceador de carga por configuração de cluster. Recomendamos que você use a versão padrão do balanceador de carga (SKU do Standard Load Balancer).", + "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-ha-ports-overview?source=recommendations", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Verifique se o IP flutuante está habilitado no balanceador de carga", + "training": "https://learn.microsoft.com/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "c47cc4f3-f105-452c-845e-9b307b3856c1", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Antes de implantar sua infraestrutura de alta disponibilidade, e dependendo da região escolhida, determine se deseja implantar com um conjunto de disponibilidade do Azure ou uma zona de disponibilidade.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "844f69c3-07e5-4ec1-bff7-4be27bcf5fea", + "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Se desejar atender aos SLAs de infraestrutura de seus aplicativos para componentes SAP (serviços centrais, servidores de aplicativos e bancos de dados), você deverá escolher as mesmas opções de alta disponibilidade (VMs, conjuntos de disponibilidade, zonas de disponibilidade) para todos os componentes." + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "cbe05bbe-209d-4490-ba47-778424d11678", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Não misture servidores de funções diferentes no mesmo conjunto de disponibilidade. Mantenha VMs de serviços centrais, VMs de banco de dados, VMs de aplicativos em seus próprios conjuntos de disponibilidade", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "f2201000-d045-40a6-a79a-d7cdc01b4d86", + "link": "https://learn.microsoft.com/azure/virtual-machines/co-location", + "severity": "Média", + "subcategory": "Alta disponibilidade", + "text": "Você não pode implantar conjuntos de disponibilidade do Azure em uma zona de disponibilidade do Azure, a menos que use grupos de posicionamento de proximidade.", + "training": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "9674e7c7-7796-4181-8920-09f4429543ba", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Ao criar conjuntos de disponibilidade, use o número máximo de domínios de falha e atualize domínios disponíveis. Por exemplo, se você implantar mais de duas VMs em um conjunto de disponibilidade, use o número máximo de domínios de falha (três) e domínios de atualização suficientes para limitar o efeito de possíveis falhas de hardware físico, interrupções de rede ou interrupções de energia, além da manutenção planejada do Azure. O número padrão de domínios de falha é dois e você não pode alterá-lo online mais tarde.", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "ae4ecb95-b70f-428f-8b9a-4c5b7e3478a2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Quando você usa grupos de posicionamento de proximidade do Azure em uma implantação de conjunto de disponibilidade, todos os três componentes SAP (serviços centrais, servidor de aplicativos e banco de dados) devem estar no mesmo grupo de posicionamento de proximidade." + }, + { + "category": "Continuidade de negócios e recuperação de desastres", + "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "Alto", + "subcategory": "Alta disponibilidade", + "text": "Use um grupo de posicionamento de proximidade por SAP SID. Os grupos não se estendem por zonas de disponibilidade ou regiões do Azure" + }, { "category": "Calcular", "guid": "2829e2ed-b217-4367-9aff-6691b4935ada", @@ -166,7 +257,7 @@ "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial", "severity": "Média", "subcategory": "Identidade", - "text": "Você pode implementar o SSO para SAP GUI usando o SAP NetWeaver SSO ou uma solução de parceiro.", + "text": "Você pode implementar o SSO no SAP GUI usando o SAP NetWeaver SSO ou uma solução de parceiro.", "training": "https://learn.microsoft.com/training/modules/explore-identity-services/8-exercise-integrate-azure-active-directory-sap-netweaver" }, { @@ -308,7 +399,7 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-resource-organization", "severity": "Média", "subcategory": "Assinaturas", - "text": "Aproveite a marca de recurso do Azure para categorização de custos e agrupamento de recursos (: BillTo, Departamento (ou Unidade de Negócios), Ambiente (Produção, Estágio, Desenvolvimento), Camada (Camada da Web, Camada de Aplicativo), Proprietário do Aplicativo, Nome do Projeto)", + "text": "Aproveite a marca de recurso do Azure para categorização de custos e agrupamento de recursos (: BillTo, Departamento (ou Unidade de Negócios), Ambiente (Produção, Estágio, Desenvolvimento), Camada (Camada da Web, Camada de Aplicativo), Proprietário do Aplicativo, ProjectName)", "training": "https://learn.microsoft.com/training/paths/implement-resource-mgmt-security/" }, { @@ -326,7 +417,7 @@ "link": "https://learn.microsoft.com/azure/azure-netapp-files/azacsnap-introduction", "severity": "Média", "subcategory": "BCDR", - "text": "Se você implantar o Azure NetApp Files para seu banco de dados HANA, Oracle ou DB2, use a ferramenta Azure Application Consistent Snapshot (AzAcSnap) para tirar instantâneos consistentes com o aplicativo. O AzAcSnap também suporta bancos de dados Oracle. Considere usar o AzAcSnap em uma VM central em vez de em VMs individuais." + "text": "Se você implantar os Arquivos NetApp do Azure para seu banco de dados HANA, Oracle ou DB2, use a ferramenta Azure Application Consistent Snapshot (AzAcSnap) para tirar instantâneos consistentes com o aplicativo. O AzAcSnap também suporta bancos de dados Oracle. Considere usar o AzAcSnap em uma VM central em vez de em VMs individuais." }, { "category": "Gestão e Monitoramento", @@ -342,7 +433,7 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel-multi-sid", "severity": "Média", "subcategory": "Gestão", - "text": "Não agrupe serviços de aplicativos diferentes no mesmo cluster. Por exemplo, não combine clusters de serviços centrais e DRBD no mesmo cluster. No entanto, você pode usar o mesmo cluster do Pacemaker para gerenciar aproximadamente cinco serviços centrais diferentes (cluster multi-SID).", + "text": "Não agrupe serviços de aplicativos diferentes no mesmo cluster. Por exemplo, não combine clusters DRBD e de serviços centrais no mesmo cluster. No entanto, você pode usar o mesmo cluster do Pacemaker para gerenciar aproximadamente cinco serviços centrais diferentes (cluster multi-SID).", "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" }, { @@ -359,7 +450,7 @@ "link": "https://learn.microsoft.com/azure/lighthouse/overview", "severity": "Média", "subcategory": "Gestão", - "text": "Se você faz parceria com clientes gerenciando suas propriedades SAP, considere o Farol do Azure. O Azure Lighthouse permite que os provedores de serviços gerenciados usem os serviços de identidade nativos do Azure para se autenticar no ambiente dos clientes. Ele coloca o controle nas mãos dos clientes, pois eles podem revogar o acesso a qualquer momento e auditar as ações dos prestadores de serviços." + "text": "Se você faz parceria com clientes gerenciando suas propriedades SAP, considere o Farol do Azure. O Azure Lighthouse permite que os provedores de serviços gerenciados usem os serviços de identidade nativos do Azure para se autenticar no ambiente dos clientes. Ele coloca o controle nas mãos dos clientes, porque eles podem revogar o acesso a qualquer momento e auditar as ações dos prestadores de serviços." }, { "category": "Gestão e Monitoramento", @@ -385,7 +476,7 @@ "link": "https://learn.microsoft.com/azure/sap/monitor/about-azure-monitor-sap-solutions", "severity": "Média", "subcategory": "Monitorização", - "text": "Use o Azure Monitor para soluções SAP para monitorar suas cargas de trabalho SAP (SAP HANA, clusters SUSE de alta disponibilidade e sistemas SQL) no Azure. Considere complementar o Azure Monitor para soluções SAP com o SAP Solution Manager.", + "text": "Use as soluções do Azure Monitor for SAP para monitorar suas cargas de trabalho SAP (SAP HANA, clusters SUSE de alta disponibilidade e sistemas SQL) no Azure. Considere complementar o Azure Monitor para soluções SAP com o SAP Solution Manager.", "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations" }, { @@ -534,7 +625,7 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", "severity": "Média", "subcategory": "DNS", - "text": "Se o DNS ou o nome virtual da máquina virtual não for alterado durante a migração para o Azure, o DNS em segundo plano e os nomes virtuais conectam muitas interfaces do sistema no cenário SAP, e os clientes só às vezes estão cientes das interfaces que os desenvolvedores definem ao longo do tempo. Os desafios de conexão surgem entre vários sistemas quando os nomes virtuais ou DNS são alterados após as migrações, e é recomendável manter os aliases DNS para evitar esses tipos de dificuldades.", + "text": "Se o DNS ou o nome virtual da máquina virtual não for alterado durante a migração para o Azure, o DNS em segundo plano e os nomes virtuais conectam muitas interfaces do sistema no cenário SAP, e os clientes só às vezes estão cientes das interfaces que os desenvolvedores definem ao longo do tempo. Surgem desafios de conexão entre vários sistemas quando os nomes virtuais ou DNS mudam após as migrações, e é recomendável manter os aliases DNS para evitar esses tipos de dificuldades.", "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/4-explore-name-resolution" }, { @@ -543,7 +634,7 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", "severity": "Média", "subcategory": "DNS", - "text": "Use zonas DNS diferentes para distinguir cada ambiente (sandbox, desenvolvimento, pré-produção e produção) uns dos outros. A exceção é para implantações SAP com sua própria VNet; aqui, zonas DNS privadas podem não ser necessárias.", + "text": "Use zonas DNS diferentes para distinguir cada ambiente (sandbox, desenvolvimento, pré-produção e produção) um do outro. A exceção é para implantações SAP com sua própria VNet; aqui, zonas DNS privadas podem não ser necessárias.", "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/4-explore-name-resolution" }, { @@ -588,7 +679,7 @@ "link": "https://learn.microsoft.com/azure/architecture/networking/hub-spoke-vwan-architecture", "severity": "Média", "subcategory": "Híbrido", - "text": "A WAN virtual gerencia a conectividade entre VNets spoke para topologias baseadas em WAN virtual (não há necessidade de configurar o roteamento definido pelo usuário [UDR] ou NVAs) e a taxa de transferência máxima de rede para o tráfego de VNet-to-VNet no mesmo hub virtual é de 50 gigabits por segundo. Se necessário, as zonas de aterrissagem SAP podem usar o emparelhamento de VNet para se conectar a outras zonas de aterrissagem e superar essa limitação de largura de banda.", + "text": "A WAN virtual gerencia a conectividade entre VNets spoke para topologias baseadas em WAN virtual (não há necessidade de configurar o roteamento definido pelo usuário [UDR] ou NVAs), e a taxa de transferência máxima de rede para o tráfego de VNet-to-VNet no mesmo hub virtual é de 50 gigabits por segundo. Se necessário, as zonas de aterrissagem SAP podem usar o emparelhamento de VNet para se conectar a outras zonas de aterrissagem e superar essa limitação de largura de banda.", "training": "https://learn.microsoft.com/training/modules/hub-and-spoke-network-architecture/?source=recommendations" }, { @@ -624,7 +715,7 @@ "link": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-delegate-subnet", "severity": "Média", "subcategory": "Plano IP", - "text": "Embora o Azure ajude você a criar várias sub-redes delegadas em uma rede virtual, somente uma sub-rede delegada pode existir em uma rede virtual para arquivos do Azure NetApp. As tentativas de criar um novo volume falharão se você usar mais de uma sub-rede delegada para Arquivos do Azure NetApp.", + "text": "Embora o Azure ajude você a criar várias sub-redes delegadas em uma rede virtual, apenas uma sub-rede delegada pode existir em uma rede virtual para arquivos do Azure NetApp. As tentativas de criar um novo volume falharão se você usar mais de uma sub-rede delegada para Arquivos do Azure NetApp.", "training": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-network-topologies?source=recommendations" }, { @@ -660,7 +751,7 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", "severity": "Média", "subcategory": "Internet", - "text": "Aproveite as políticas do Firewall de Aplicativo Web no Azure Front Door ao usar o Azure Front Door e o Gateway de Aplicativo para proteger aplicativos HTTP/S. Bloqueie o Gateway de Aplicativo para receber tráfego somente do Azure Front Door.", + "text": "Aproveite as políticas do Web Application Firewall no Azure Front Door quando estiver usando o Azure Front Door e o Application Gateway para proteger aplicativos HTTP/S. Bloqueie o Gateway de Aplicativo para receber tráfego somente do Azure Front Door.", "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations" }, { @@ -705,7 +796,7 @@ "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-multivip-overview", "severity": "Média", "subcategory": "Segmentação", - "text": "Verifique se as implantações internas do Balanceador de Carga do Azure estão configuradas para usar o DSR (Direct Server Return). Essa configuração reduzirá a latência quando as configurações internas do balanceador de carga forem usadas para configurações de alta disponibilidade na camada DBMS.", + "text": "Verifique se as implantações internas do Azure Load Balancer estão configuradas para usar DSR (Direct Server Return). Essa configuração reduzirá a latência quando as configurações internas do balanceador de carga forem usadas para configurações de alta disponibilidade na camada DBMS.", "training": "https://learn.microsoft.com/ja-jp/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations" }, { @@ -714,7 +805,7 @@ "link": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works", "severity": "Média", "subcategory": "Segmentação", - "text": "Você pode usar regras ASG (grupo de segurança de aplicativo) e NSG para definir listas de controle de acesso de segurança de rede entre o aplicativo SAP e as camadas DBMS. Os ASGs agrupam máquinas virtuais para ajudar a gerenciar sua segurança.", + "text": "Você pode usar as regras ASG (grupo de segurança de aplicativo) e NSG para definir listas de controle de acesso de segurança de rede entre o aplicativo SAP e as camadas DBMS. Os ASGs agrupam máquinas virtuais para ajudar a gerenciar sua segurança.", "training": "https://learn.microsoft.com/training/modules/configure-network-security-groups/?source=recommendations" }, { @@ -777,55 +868,60 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/rise-integration", "severity": "Média", "subcategory": "Segmentação", - "text": "Para implantações SAP RISE/ECS, o emparelhamento virtual é a maneira preferencial de estabelecer conectividade com o ambiente existente do Azure do cliente. Tanto a vnet do SAP quanto a(s) vnet(s) do cliente são protegidas com grupos de segurança de rede (NSG), permitindo a comunicação nas portas SAP e de banco de dados por meio do emparelhamento vnet" + "text": "Para implantações SAP RISE/ECS, o emparelhamento virtual é a maneira preferida de estabelecer conectividade com o ambiente existente do Azure do cliente. Tanto a vnet do SAP quanto a(s) vnet(s) do cliente são protegidas com grupos de segurança de rede (NSG), permitindo a comunicação nas portas SAP e de banco de dados por meio do emparelhamento vnet" }, { "category": "Segurança, Governança e Compliance", - "guid": "209d490d-a477-4784-84d1-16785d2fa56c", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "Alto", + "guid": "18dffcf3-248c-4039-a67c-dec8e3a5f804", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", + "severity": "Média", "subcategory": "Governança", - "text": "Personalizar funções RBAC (controle de acesso baseado em função) para SAP em assinaturas do Azure spoke para evitar alterações acidentais relacionadas à rede" + "text": "Se você executar VMs do Windows e Linux no Azure, no local ou em outros ambientes de nuvem, poderá usar o Centro de gerenciamento de atualizações na Automação do Azure para gerenciar atualizações do sistema operacional, incluindo patches de segurança.", + "training": "https://learn.microsoft.com/azure/automation/update-management/overview" }, { "category": "Segurança, Governança e Compliance", - "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "08951710-79a2-492a-adbc-06d7a401545b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", "severity": "Média", "subcategory": "Governança", - "text": "Isole DMZs e NVAs do restante do estado SAP, configure o Azure Private Link e gerencie e controle com segurança os recursos do SAP no Azure" + "text": "Analise rotineiramente as notas de OSS de segurança do SAP porque o SAP lança patches de segurança altamente críticos, ou hot fixes, que exigem ação imediata para proteger seus sistemas SAP.", + "training": "https://support.sap.com/en/my-support/knowledge-base/security-notes-news.html" }, { "category": "Segurança, Governança e Compliance", - "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "Média", + "guid": "1b8b394e-ae64-4a74-8933-357b523ea0a0", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "Baixo", "subcategory": "Governança", - "text": "Para criptografia do servidor de banco de dados SAP, use a tecnologia de criptografia nativa do SAP HANA. Se você estiver usando o Banco de Dados SQL do Azure, use a TDE (Criptografia de Dados Transparente) oferecida pelo provedor DBMS para proteger seus dados e arquivos de log e garantir que os backups também sejam criptografados." + "text": "Para SAP no SQL Server, você pode desabilitar a conta de administrador do sistema do SQL Server porque os sistemas SAP no SQL Server não usam a conta. Certifique-se de que outro usuário com direitos de administrador do sistema possa acessar o servidor antes de desabilitar a conta de administrador do sistema original." }, { "category": "Segurança, Governança e Compliance", - "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "Média", + "guid": "5a76a033-ced9-4eef-9a43-5e4f96634c8e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "Alto", "subcategory": "Governança", - "text": "A criptografia do Armazenamento do Azure está habilitada por padrão" + "text": "Desative xp_cmdshell. O recurso do SQL Server xp_cmdshell habilita um shell de comando do sistema operacional interno do SQL Server. É um risco potencial em auditorias de segurança.", + "training": "https://me.sap.com/notes/3019299/E" }, { "category": "Segurança, Governança e Compliance", - "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "Média", - "subcategory": "Governança", - "text": " " + "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "Alto", + "subcategory": "Segredos", + "text": "A criptografia de servidores de banco de dados SAP HANA no Azrue usa a tecnologia de criptografia nativa do SAP HANA. Além disso, se você estiver usando o SQL Server no Azure, use a TDE (Criptografia de Dados Transparente) para proteger seus dados e arquivos de log e garantir que seus backups também sejam criptografados.", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security" }, { "category": "Segurança, Governança e Compliance", - "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", "severity": "Média", - "subcategory": "Governança", - "text": " " + "subcategory": "Segredos", + "text": "A criptografia de Armazenamento do Azure está habilitada para todas as contas clássicas e do Gerenciador de Recursos do Azure e não pode ser desabilitada. Como seus dados são criptografados por padrão, você não precisa modificar seu código ou aplicativos para usar a criptografia do Armazenamento do Azure.", + "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", @@ -833,95 +929,160 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/overview", "severity": "Alto", "subcategory": "Segredos", - "text": "Usar o Cofre de Chaves do Azure para armazenar seus segredos e credenciais" + "text": "Usar o Cofre de Chaves do Azure para armazenar seus segredos e credenciais", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", "guid": "829e2edb-2173-4676-aff6-691b4935ada4", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview-throttling", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", "severity": "Média", "subcategory": "Segredos", - "text": "É recomendável BLOQUEAR os Recursos do Azure após a implantação bem-sucedida para proteger contra alterações não autorizadas" + "text": "É recomendável BLOQUEAR os Recursos do Azure após a implantação bem-sucedida para proteger contra alterações não autorizadas. Você também pode impor restrições e regras LOCK em sua base por assinatura usando políticas personalizadas do Azure (função Personalizada).", + "training": "https://learn.microsoft.com/training/modules/use-azure-resource-manager/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", "guid": "2223ece8-1b12-4318-8a54-17415833fb4a", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", "severity": "Média", "subcategory": "Segredos", - "text": "Provisione o Cofre de Chaves do Azure com as políticas de exclusão e limpeza suaves habilitadas para permitir a proteção de retenção para objetos excluídos." + "text": "Provisione o Cofre de Chaves do Azure com as políticas de exclusão e limpeza suaves habilitadas para permitir a proteção de retenção para objetos excluídos.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", "guid": "e3c2df74-3165-4c3a-abe0-5bbe209d490d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Média", + "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", + "severity": "Alto", "subcategory": "Segredos", - "text": "Com base nos requisitos existentes, controles normativos e de conformidade (internos/externos) - Determine quais Políticas do Azure e a função RBAC do Azure são necessárias" + "text": "Com base nos requisitos existentes, controles normativos e de conformidade (internos/externos) - Determine quais Políticas do Azure e a função RBAC do Azure são necessárias", + "training": "https://learn.microsoft.com/training/paths/describe-azure-management-governance/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", "guid": "a4777842-4d11-4678-9d2f-a56c56ad4840", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Média", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "Alto", "subcategory": "Segredos", - "text": "Ao habilitar o Microsoft Defender for Cloud Standard for SAP, certifique-se de excluir os servidores de banco de dados SAP de qualquer política que instale a proteção de ponto de extremidade." + "text": "Ao habilitar o Microsoft Defender for Endpoint no ambiente SAP, recomende excluir arquivos de dados e de log em servidores DBMS em vez de direcionar todos os servidores. Siga as recomendações do fornecedor do DBMS ao excluir arquivos de destino.", + "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/microsoft-defender-endpoint-mde-for-sap-applications-on-windows/ba-p/3912268" }, { "category": "Segurança, Governança e Compliance", "guid": "8fe72734-c486-4ba2-a0dc-0591cf65de8e", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Média", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/just-in-time-access-overview?tabs=defender-for-container-arch-aks", + "severity": "Alto", "subcategory": "Segredos", - "text": "Delegue uma função personalizada de administrador SAP com acesso just-in-time." + "text": "Delegue uma função personalizada de administrador SAP com acesso just-in-time do Microsoft Defender for Cloud.", + "training": "https://learn.microsoft.com/training/modules/secure-vms-with-azure-security-center/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", "guid": "1309cccd-5792-466b-aca2-75faa1abfe9d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Média", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "Baixo", "subcategory": "Segredos", - "text": "criptografar dados em trânsito integrando o produto de segurança de terceiros com comunicações de rede seguras (SNC) para DIAG (SAP GUI), RFC e SPNEGO para HTTPS" + "text": "criptografar dados em trânsito integrando o produto de segurança de terceiros com comunicações de rede seguras (SNC) para DIAG (SAP GUI), RFC e SPNEGO para HTTPS", + "training": "https://learn.microsoft.com/azure/security/fundamentals/encryption-overview#encryption-of-data-in-transit" }, { "category": "Segurança, Governança e Compliance", - "guid": "55d04c3c-4919-4cb1-a3d1-325ae124ba34", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", + "link": "https://learn.microsoft.com/azure/storage/common/storage-encryption-key-model-get?tabs=portal", "severity": "Média", "subcategory": "Segredos", - "text": "O Azure Active Directory (Azure AD) com SAML 2.0 também pode fornecer SSO para uma variedade de aplicativos e plataformas SAP, como SAP NetWeaver, SAP HANA e SAP Cloud Platform" + "text": "O padrão é chaves gerenciadas pela Microsoft para a funcionalidade de criptografia principal e use chaves gerenciadas pelo cliente quando necessário.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", - "guid": "df685edd-ce9b-4d3b-a0cd-b3b55eb2ec14", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Média", + "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "link": "https://learn.microsoft.com/ja-jp/azure/key-vault/general/best-practices", + "severity": "Alto", "subcategory": "Segredos", - "text": "Certifique-se de proteger o sistema operacional para erradicar vulnerabilidades que podem levar a ataques no banco de dados SAP." + "text": "Use um Cofre de Chaves do Azure por aplicativo, por ambiente, por região.", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", - "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "Média", + "guid": "abc9634d-c44d-41e9-a530-e8444e16aa3c", + "link": "https://learn.microsoft.com/azure/key-vault/certificates/certificate-scenarios", + "severity": "Alto", "subcategory": "Segredos", - "text": "O padrão é chaves gerenciadas pela Microsoft para a funcionalidade de criptografia principal e use chaves gerenciadas pelo cliente quando necessário." + "text": "Para controlar e gerenciar chaves de criptografia de disco e segredos para sistemas operacionais Windows e não Windows HANA, use o Cofre de Chaves do Azure. O SAP HANA não tem suporte com o Cofre de Chaves do Azure, portanto, você deve usar métodos alternativos, como chaves SAP ABAP ou SSH.", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/?source=recommendations" }, { "category": "Segurança, Governança e Compliance", - "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "severity": "Média", "subcategory": "Segredos", - "text": "Use um Cofre de Chaves do Azure por aplicativo, por ambiente, por região." + "text": " " }, { "category": "Segurança, Governança e Compliance", - "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "209d490d-a477-4784-84d1-16785d2fa56c", + "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles", + "severity": "Alto", + "subcategory": "Segurança", + "text": "Personalizar funções RBAC (controle de acesso baseado em função) para SAP em assinaturas spoke do Azure para evitar alterações acidentais relacionadas à rede", + "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations" + }, + { + "category": "Segurança, Governança e Compliance", + "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", + "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/", + "severity": "Alto", + "subcategory": "Segurança", + "text": "Isole DMZs e NVAs do restante do estado SAP, configure o Azure Private Link e gerencie e controle com segurança os recursos do SAP no Azure", + "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal" + }, + { + "category": "Segurança, Governança e Compliance", + "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", + "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", + "severity": "Baixo", + "subcategory": "Segurança", + "text": "Considere usar o software antimalware da Microsoft no Azure para proteger suas máquinas virtuais contra arquivos mal-intencionados, adware e outras ameaças.", + "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/" + }, + { + "category": "Segurança, Governança e Compliance", + "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", + "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", + "severity": "Baixo", + "subcategory": "Segurança", + "text": "Para obter uma proteção ainda mais poderosa, considere usar o Microsoft Defender for Endpoint.", + "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations" + }, + { + "category": "Segurança, Governança e Compliance", + "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "severity": "Alto", + "subcategory": "Segurança", + "text": "Isole os servidores de aplicativo e banco de dados SAP da Internet ou da rede local passando todo o tráfego pela rede virtual de hub, que está conectada à rede spoke por emparelhamento de rede virtual. As redes virtuais emparelhadas garantem que a solução SAP no Azure seja isolada da Internet pública.", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations" + }, + { + "category": "Segurança, Governança e Compliance", + "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "Baixo", + "subcategory": "Segurança", + "text": "Para aplicativos voltados para a Internet, como o SAP Fiori, certifique-se de distribuir a carga por requisitos de aplicativo, mantendo os níveis de segurança. Para segurança de Camada 7, você pode usar um WAF (Web Application Firewall) de terceiros disponível no Azure Marketplace.", + "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations" + }, + { + "category": "Segurança, Governança e Compliance", + "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", + "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions", "severity": "Média", - "subcategory": "Segredos", - "text": " " + "subcategory": "Segurança", + "text": "Para habilitar a comunicação segura no Azure Monitor para soluções SAP, você pode optar por usar um certificado raiz ou um certificado de servidor. É altamente recomendável que você use certificados raiz.", + "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations" }, { "category": "Armazenamento", @@ -934,7 +1095,7 @@ "metadata": { "name": "Azure Landing Zone Review", "state": "Preview", - "timestamp": "November 24, 2023" + "timestamp": "January 11, 2024" }, "severities": [ { diff --git a/checklists/sap_checklist.zh-Hant.json b/checklists/sap_checklist.zh-Hant.json index 9b0e064a0..f45ce677b 100644 --- a/checklists/sap_checklist.zh-Hant.json +++ b/checklists/sap_checklist.zh-Hant.json @@ -17,38 +17,6 @@ } ], "items": [ - { - "category": "業務連續性和災難恢復", - "guid": "aff6691b-4935-4ada-9222-3ece81b12318", - "link": "https://learn.microsoft.com/azure/active-directory/reports-monitoring/overview-reports", - "severity": "中等", - "subcategory": " ", - "text": "不要將 ASCS 和資料庫群集合並到單個/同一 VM 上" - }, - { - "category": "業務連續性和災難恢復", - "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", - "link": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export?tabs=portal", - "severity": "中等", - "subcategory": " ", - "text": "確保在負載均衡器上啟用了浮動IP" - }, - { - "category": "業務連續性和災難恢復", - "guid": "cbe05bbe-209d-4490-ba47-778424d11678", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "中等", - "subcategory": " ", - "text": "不要在同一可用性集中混合使用不同角色的伺服器。將中央服務 VM、資料庫 VM、應用程式 VM 保留在其自己的可用性集中" - }, - { - "category": "業務連續性和災難恢復", - "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", - "link": "https://learn.microsoft.com/azure/security-center/", - "severity": "中等", - "subcategory": " ", - "text": "每個 SAP SID 使用一個鄰近放置組。組不跨可用性區域或 Azure 區域" - }, { "category": "業務連續性和災難恢復", "guid": "80dc0591-cf65-4de8-b130-9cccd579266b", @@ -94,14 +62,14 @@ "guid": "81b12318-1a54-4174-8583-3fb4ae3c2df7", "severity": "中等", "subcategory": " ", - "text": "主虛擬網路 (VNet) 的 CIDR 不應與 DR 網站的 Vnet 的 CIDR 衝突或重疊" + "text": "主虛擬網路 (VNet) 的 CIDR 不應與DR網站的 VNet 的 CIDR 衝突或重疊" }, { "category": "業務連續性和災難恢復", "guid": "43165c3a-cbe0-45bb-b209-d490da477784", "severity": "中等", "subcategory": " ", - "text": "使用 Site Recovery 將應用程式伺服器複製到 DR 網站。Site Recovery 還有助於將中心服務群集 VM 複製到DR網站。調用DR時,需要在DR網站上重新配置Linux Pacemaker群集(例如,替換VIP或SBD、運行 corosync.conf等)。" + "text": "使用 Site Recovery 將應用程式伺服器複製到 DR 網站。Site Recovery 還有助於將中心服務群集 VM 複製到DR網站。調用DR時,需要在DR網站上重新配置Linux Pacemaker群集(例如,替換VIP或SBD、運行 corosync.conf 等)。" }, { "category": "業務連續性和災難恢復", @@ -110,6 +78,129 @@ "subcategory": " ", "text": "應使用本機資料庫複製將數據同步到DR網站,而不是 Azure Site Recovery" }, + { + "category": "業務連續性和災難恢復", + "guid": "8300cb30-766b-4084-b126-0dd8fb1269a1", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-architecture-scenario", + "severity": "高", + "subcategory": "高可用性", + "text": "考慮針對單點故障的 SAP 軟體的可用性。這包括應用程式內的單點故障,例如 SAP NetWeaver 和 SAP S/4HANA 架構中使用的 DBMS、SAP ABAP 和 ASCS + SCS。此外,還有其他工具,例如 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" + }, + { + "category": "業務連續性和災難恢復", + "guid": "56402f11-ccbe-42c3-a2f6-c6f6f38ab579", + "link": "https://learn.microsoft.com/azure/sap/workloads/planning-supported-configurations", + "severity": "高", + "subcategory": "高可用性", + "text": "對於 SAP 和 SAP 資料庫,請考慮實現自動故障轉移群集。在 Windows 中,Windows Server 故障轉移群集支援故障轉移。在 Linux 中,Linux Pacemaker 或第三方工具(如 SIOS Protection Suite 和 Veritas InfoScale)支援故障轉移。", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "業務連續性和災難恢復", + "guid": "afae6bec-2671-49ae-bc69-140b8ec8d320", + "link": "https://learn.microsoft.com/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows", + "severity": "高", + "subcategory": "高可用性", + "text": "Azure 不支援主 VM 和輔助 VM 共用 DBMS 數據存儲的體系結構。對於 DBMS 層,常見的體系結構模式是同時複製資料庫,並使用與主 VM 和輔助 VM 使用的儲存堆疊不同的儲存堆疊。", + "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" + }, + { + "category": "業務連續性和災難恢復", + "guid": "ac614e95-6767-4bc3-b8a4-9953533da6ba", + "link": "https://learn.microsoft.com/azure/sap/workloads/dbms-guide-general", + "severity": "高", + "subcategory": "高可用性", + "text": "DBMS 數據和事務/重做日誌檔存儲在 Azure 支援的塊存儲或 Azure NetApp 檔中。不支援將 Azure 檔案儲存或 Azure 高級檔儲存作為 SAP 工作負載的 DBMS 資料和/或重做日誌檔的存儲。", + "training": "https://learn.microsoft.com/training/modules/explore-azure-databases/2-explore-database-support-azure-for-sap-workloads" + }, + { + "category": "業務連續性和災難恢復", + "guid": "1f737179-8e7f-4e1a-a30c-e5a649a3092b", + "link": "https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-wsfc-shared-disk", + "severity": "高", + "subcategory": "高可用性", + "text": "可以在 Windows 中將 Azure 共用磁碟用於 ASCS + SCS 元件和特定的高可用性方案。為 SAP 應用程式層元件和 DBMS 層單獨設置故障轉移群集。Azure 目前不支援將 SAP 應用程式層元件和 DBMS 層合併到一個故障轉移群集中的高可用性體系結構。", + "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" + }, + { + "category": "業務連續性和災難恢復", + "guid": "a78b3d31-3170-44f2-b5d7-651a29f4ccf5", + "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-standard-load-balancer-outbound-connections", + "severity": "高", + "subcategory": "高可用性", + "text": "SAP 應用程式層元件 (ASCS) 和 DBMS 層的大多數故障轉移群集都需要故障轉移群集的虛擬 IP 位址。 對於所有其他情況,Azure 負載均衡器應處理虛擬IP位址。一個設計原則是每個群集配置使用一個負載均衡器。建議使用負載均衡器的標準版本(標準負載均衡器 SKU)。", + "training": "https://learn.microsoft.com/training/modules/implement-high-availability-for-sap-workloads-azure/?source=recommendations" + }, + { + "category": "業務連續性和災難恢復", + "guid": "1a541741-5833-4fb4-ae3c-2df743165c3a", + "link": "https://learn.microsoft.com/azure/load-balancer/load-balancer-ha-ports-overview?source=recommendations", + "severity": "高", + "subcategory": "高可用性", + "text": "確保在負載均衡器上啟用了浮動IP", + "training": "https://learn.microsoft.com/training/modules/load-balancing-non-https-traffic-azure/?source=recommendations" + }, + { + "category": "業務連續性和災難恢復", + "guid": "c47cc4f3-f105-452c-845e-9b307b3856c1", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability", + "severity": "高", + "subcategory": "高可用性", + "text": "在部署高可用性基礎結構之前,根據所選區域,確定是使用 Azure 可用性集還是可用性區域進行部署。", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "業務連續性和災難恢復", + "guid": "844f69c3-07e5-4ec1-bff7-4be27bcf5fea", + "link": "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services?lang=1", + "severity": "高", + "subcategory": "高可用性", + "text": "如果要滿足 SAP 元件(中央服務、應用程式伺服器和資料庫)應用程式的基礎結構 SLA,則必須為所有元件選擇相同的高可用性選項(VM、可用性集、可用性區域)。" + }, + { + "category": "業務連續性和災難恢復", + "guid": "cbe05bbe-209d-4490-ba47-778424d11678", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "高", + "subcategory": "高可用性", + "text": "不要在同一可用性集中混合使用不同角色的伺服器。將中央服務 VM、資料庫 VM、應用程式 VM 保留在其自己的可用性集中", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "業務連續性和災難恢復", + "guid": "f2201000-d045-40a6-a79a-d7cdc01b4d86", + "link": "https://learn.microsoft.com/azure/virtual-machines/co-location", + "severity": "中等", + "subcategory": "高可用性", + "text": "除非使用鄰近放置組,否則無法在 Azure 可用性區域中部署 Azure 可用性集。", + "training": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios" + }, + { + "category": "業務連續性和災難恢復", + "guid": "9674e7c7-7796-4181-8920-09f4429543ba", + "link": "https://learn.microsoft.com/azure/virtual-machines/availability-set-overview", + "severity": "高", + "subcategory": "高可用性", + "text": "創建可用性集時,請使用可用的容錯域和更新域的最大數量。例如,如果在一個可用性集中部署兩個以上的 VM,則除了 Azure 計劃內維護外,還要使用最大數量的容錯域(三個)和足夠的更新域來限制潛在的物理硬體故障、網路中斷或電源中斷的影響。容錯域的預設數量為 2,以後無法連線更改。", + "training": "https://learn.microsoft.com/training/modules/configure-virtual-machine-availability/?source=recommendations" + }, + { + "category": "業務連續性和災難恢復", + "guid": "ae4ecb95-b70f-428f-8b9a-4c5b7e3478a2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "高", + "subcategory": "高可用性", + "text": "在可用性集部署中使用 Azure 鄰近放置組時,所有三個 SAP 元件(中央服務、應用程式伺服器和資料庫)都應位於同一鄰近放置組中。" + }, + { + "category": "業務連續性和災難恢復", + "guid": "5d2fa56c-56ad-4484-88fe-72734c486ba2", + "link": "https://learn.microsoft.com/azure/sap/workloads/proximity-placement-scenarios", + "severity": "高", + "subcategory": "高可用性", + "text": "每個 SAP SID 使用一個鄰近放置組。組不跨可用性區域或 Azure 區域" + }, { "category": "計算", "guid": "2829e2ed-b217-4367-9aff-6691b4935ada", @@ -149,7 +240,7 @@ "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-netweaver-tutorial", "severity": "中等", "subcategory": "身份", - "text": "使用 SAML 對基於 SAP NetWeaver 的 Web 應用程式(如 SAP Fiori 和 SAP Web GUI)實施 SSO。", + "text": "使用 SAML 實現對基於 SAP NetWeaver 的 Web 應用程式(如 SAP Fiori 和 SAP Web GUI)的 SSO。", "training": "https://learn.microsoft.com/training/modules/explore-identity-services/8-exercise-integrate-azure-active-directory-sap-netweaver" }, { @@ -157,7 +248,7 @@ "guid": "9eb54dad-7861-4e1c-973a-f3bb003fc9c1", "severity": "中等", "subcategory": "身份", - "text": "使用 SAML 對基於 SAP NetWeaver 的 Web 應用程式(如 SAP Fiori 和 SAP Web GUI)實施 SSO。", + "text": "使用 SAML 實現對基於 SAP NetWeaver 的 Web 應用程式(如 SAP Fiori 和 SAP Web GUI)的 SSO。", "training": "https://learn.microsoft.com/training/modules/explore-identity-services/6-exercise-integrate-azure-active-directory-sap-fiori" }, { @@ -231,7 +322,7 @@ "link": "https://learn.microsoft.com/azure/active-directory/saas-apps/sap-hana-cloud-platform-tutorial", "severity": "中等", "subcategory": "身份", - "text": "實現SAP BTP 的 SSO" + "text": "實現對 SAP BTP 的 SSO" }, { "category": "標識和訪問", @@ -291,7 +382,7 @@ "link": "https://learn.microsoft.com/azure/quotas/quickstart-increase-quota-portal", "severity": "高", "subcategory": "訂閱", - "text": "如果部署到可用性區域,請確保在配額獲得批准后,VM 的區域部署可用。提交支援請求,其中包含所需的訂閱、VM 系列、CPU 數量和可用性區域。" + "text": "如果部署到可用性區域,請確保在批准配額后,VM 的區域部署可用。提交支援請求,其中包含所需的訂閱、VM 系列、CPU 數量和可用性區域。" }, { "category": "管理組和訂閱", @@ -342,7 +433,7 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-guide-rhel-multi-sid", "severity": "中等", "subcategory": "管理", - "text": "不要在同一集群中對不同的應用程式服務進行分組。例如,不要將DRBD和中央服務群集合並到同一個群集上。但是,可以使用同一個 Pacemaker 群集來管理大約五個不同的中心服務(多 SID 群集)。", + "text": "不要在同一集群中對不同的應用程式服務進行分組。例如,不要將DRBD和中央服務群集合並到同一個群集上。但是,可以使用同一個 Pacemaker 群集來管理大約五個不同的中央服務(多 SID 群集)。", "training": "https://learn.microsoft.com/training/modules/implement-ha-sap-netweaver-anydb/?source=recommendations" }, { @@ -412,7 +503,7 @@ "link": "https://learn.microsoft.com/azure/network-watcher/connection-monitor-overview", "severity": "中等", "subcategory": "監測", - "text": "使用 Azure 網路觀察程式中的連接監視器來監視 SAP 資料庫和應用程式伺服器的延遲指標。或者使用 Azure Monitor 收集和顯示網路延遲度量值。", + "text": "使用 Azure 網路觀察程式中的連接監視器監視 SAP 資料庫和應用程式伺服器的延遲指標。或者使用 Azure Monitor 收集和顯示網路延遲度量值。", "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/collecting-and-displaying-niping-network-latency-measurements/ba-p/1833979" }, { @@ -438,7 +529,7 @@ "link": "https://learn.microsoft.com/azure/sap/workloads/high-availability-zones", "severity": "高", "subcategory": "監測", - "text": "對於每個 Azure 訂閱,請在區域部署之前對 Azure 可用性區域運行延遲測試,以選擇用於在 Azure 上部署 SAP 的低延遲區域。", + "text": "對於每個 Azure 訂閱,請在區域部署之前在 Azure 可用性區域上運行延遲測試,以選擇用於在 Azure 上部署 SAP 的低延遲區域。", "training": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/AvZone-Latency-Test" }, { @@ -534,7 +625,7 @@ "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-network-topology-and-connectivity", "severity": "中等", "subcategory": "DNS解析", - "text": "如果在遷移到 Azure 期間未更改虛擬機器的 DNS 或虛擬名稱,則後台 DNS 和虛擬名稱會連接 SAP 環境中的許多系統介面,並且客戶有時只會知道開發人員隨時間推移定義的介面。遷移后,當虛擬名稱或 DNS 名稱發生更改時,各種系統之間會出現連接挑戰,建議保留 DNS 別名以防止出現這些類型的困難。", + "text": "如果在遷移到 Azure 期間未更改虛擬機器的 DNS 或虛擬名稱,則後台 DNS 和虛擬名稱會連接 SAP 環境中的許多系統介面,並且客戶有時只知道開發人員隨時間推移定義的介面。遷移后,當虛擬名稱或 DNS 名稱發生更改時,各種系統之間會出現連接挑戰,建議保留 DNS 別名以防止出現這些類型的困難。", "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/4-explore-name-resolution" }, { @@ -570,7 +661,7 @@ "link": "https://learn.microsoft.com/training/modules/introduction-azure-virtual-wan/?source=recommendations", "severity": "中等", "subcategory": "混合", - "text": "在需要跨 Azure 區域和本地位置進行全球傳輸連接的新網路、大型網路或全球網路中的 Azure 部署使用虛擬 WAN。使用此方法,無需手動為 Azure 網路設置可傳遞路由,並且可以遵循 Azure 上的 SAP 部署的標準。", + "text": "在需要跨 Azure 區域和本地位置進行全球傳輸連接的新網路、大型網路或全球網路中,將虛擬 WAN 用於 Azure 部署。使用此方法,無需手動為 Azure 網路設置可傳遞路由,並且可以遵循 Azure 上的 SAP 部署的標準。", "training": "https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about" }, { @@ -633,7 +724,7 @@ "link": "https://learn.microsoft.com/azure/well-architected/services/networking/azure-firewall?toc=%2Fazure%2Ffirewall%2Ftoc.json&bc=%2Fazure%2Ffirewall%2Fbreadcrumb%2Ftoc.json", "severity": "中等", "subcategory": "互聯網", - "text": "使用 Azure 防火牆管理發往 Internet 的 Azure 出站流量、非 HTTP/S 入站連接和東/西流量篩選(如果組織需要)", + "text": "使用 Azure 防火牆管理發往 Internet、非 HTTP/S 入站連接和東西方流量篩選的 Azure 出站流量(如果組織需要)", "training": "https://learn.microsoft.com/training/paths/secure-networking-infrastructure/" }, { @@ -660,7 +751,7 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/afds/afds-overview", "severity": "中等", "subcategory": "互聯網", - "text": "使用 Azure Front Door 和應用程式閘道保護 HTTP/S 應用程式時,利用 Azure Front Door 中的 Web 應用程式防火牆策略。鎖定應用程式閘道以僅接收來自 Azure Front Door 的流量。", + "text": "使用 Azure Front Door 和應用程式閘道來保護 HTTP/S 應用程式時,請利用 Azure Front Door 中的 Web 應用程式防火牆策略。鎖定應用程式閘道以僅接收來自 Azure Front Door 的流量。", "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations" }, { @@ -669,7 +760,7 @@ "link": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview", "severity": "中等", "subcategory": "互聯網", - "text": "當流量暴露給 Internet 時,使用 Web 應用程式防火牆掃描流量。另一種選擇是將其與負載均衡器或具有內置防火牆功能(如應用程式閘道或第三方解決方案)的資源一起使用。", + "text": "當流量暴露在互聯網上時,使用 Web 應用程式防火牆掃描流量。另一種選擇是將其與負載均衡器或具有內置防火牆功能(如應用程式閘道或第三方解決方案)的資源一起使用。", "training": "https://learn.microsoft.com/training/modules/introduction-azure-web-application-firewall/?source=recommendations" }, { @@ -678,7 +769,7 @@ "link": "https://learn.microsoft.com/azure/frontdoor/front-door-overview", "severity": "中等", "subcategory": "互聯網", - "text": "在需要跨 Azure 區域和本地位置進行全球傳輸連接的新網路、大型網路或全球網路中的 Azure 部署使用虛擬 WAN。使用此方法,無需手動為 Azure 網路設置可傳遞路由,並且可以遵循 Azure 上的 SAP 部署的標準。", + "text": "在需要跨 Azure 區域和本地位置進行全球傳輸連接的新網路、大型網路或全球網路中,將虛擬 WAN 用於 Azure 部署。使用此方法,無需手動為 Azure 網路設置可傳遞路由,並且可以遵循 Azure 上的 SAP 部署的標準。", "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/10-explore-azure-front-door" }, { @@ -687,7 +778,7 @@ "link": "https://learn.microsoft.com/azure/virtual-network/vnet-integration-for-azure-services", "severity": "中等", "subcategory": "互聯網", - "text": "若要防止數據洩露,請使用 Azure 專用連結安全地訪問平臺即服務資源,例如 Azure Blob 存儲、Azure 檔存儲、Azure Data Lake Storage Gen2、Azure 數據工廠等。Azure 專用終結點還可以幫助保護 VNet 與 Azure 存儲、Azure 備份等服務之間的流量。VNet 與啟用了專用終結點的服務之間的流量通過 Microsoft 全球網路傳輸,從而防止其暴露在公共 Internet 上。", + "text": "若要防止數據洩露,請使用 Azure 專用連結安全地訪問平臺即服務資源,例如 Azure Blob 存儲、Azure 檔存儲、Azure Data Lake Storage Gen2、Azure 數據工廠等。Azure 專用終結點還可以幫助保護 VNet 與 Azure 存儲、Azure 備份等服務之間的流量。VNet 與啟用了專用終結點的服務之間的流量通過 Microsoft 全球網路傳輸,從而防止其暴露給公共 Internet。", "training": "https://learn.microsoft.com/training/modules/design-implement-private-access-to-azure-services/?source=recommendations" }, { @@ -781,51 +872,56 @@ }, { "category": "安全性、治理與合規性", - "guid": "209d490d-a477-4784-84d1-16785d2fa56c", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "高", + "guid": "18dffcf3-248c-4039-a67c-dec8e3a5f804", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", + "severity": "中等", "subcategory": "統轄", - "text": "為 Azure 上的 SAP 分支訂閱自定義基於角色的訪問控制 (RBAC) 角色,以避免與網路相關的意外更改" + "text": "如果在 Azure、本地或其他雲環境中運行 Windows 和 Linux VM,則可以使用 Azure 自動化中的更新管理中心來管理作業系統更新,包括安全修補程式。", + "training": "https://learn.microsoft.com/azure/automation/update-management/overview" }, { "category": "安全性、治理與合規性", - "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "08951710-79a2-492a-adbc-06d7a401545b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-security-operations", "severity": "中等", "subcategory": "統轄", - "text": "將 DMZ 和 NVA 與 SAP 資產的其餘部分隔離開來,配置 Azure 專用連結,並安全地管理和控制 Azure 上的 SAP 資源" + "text": "請定期查看 SAP 安全 OSS 說明,因為 SAP 會發佈高度關鍵的安全補丁或熱修復程式,需要立即採取措施來保護 SAP 系統。", + "training": "https://support.sap.com/en/my-support/knowledge-base/security-notes-news.html" }, { "category": "安全性、治理與合規性", - "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "中等", + "guid": "1b8b394e-ae64-4a74-8933-357b523ea0a0", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "低", "subcategory": "統轄", - "text": "對於 SAP 資料庫伺服器加密,請使用 SAP HANA 本機加密技術。如果使用的是 Azure SQL 資料庫,請使用 DBMS 提供者提供的透明數據加密 (TDE) 來保護數據和日誌檔,並確保備份也已加密。" + "text": "對於 SQL Server 上的 SAP,可以禁用 SQL Server 系統管理員帳戶,因為 SQL Server 上的 SAP 系統不使用該帳戶。在禁用原始系統管理員帳戶之前,請確保具有系統管理員許可權的其他使用者可以訪問伺服器。" }, { "category": "安全性、治理與合規性", - "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "中等", + "guid": "5a76a033-ced9-4eef-9a43-5e4f96634c8e", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security", + "severity": "高", "subcategory": "統轄", - "text": "默認情況下,Azure 儲存加密處於啟用狀態" + "text": "禁用xp_cmdshell。SQL Server 功能xp_cmdshell啟用 SQL Server 內部作業系統命令行介面。這是安全審計中的潛在風險。", + "training": "https://me.sap.com/notes/3019299/E" }, { "category": "安全性、治理與合規性", - "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", - "severity": "中等", - "subcategory": "統轄", - "text": " " + "guid": "cf65de8e-1309-4ccc-b579-266bcca275fa", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "高", + "subcategory": "秘密", + "text": "在 Azrue 上加密 SAP HANA 資料庫伺服器使用 SAP HANA 原生加密技術。此外,如果在 Azure 上使用 SQL Server,請使用透明數據加密 (TDE) 來保護數據和日誌檔,並確保備份也已加密。", + "training": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/sap-lza-database-security" }, { "category": "安全性、治理與合規性", - "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", - "link": "https://learn.microsoft.com/azure/governance/policy/overview", + "guid": "a1abfe9d-55d0-44c3-a491-9cb1b3d1325a", + "link": "https://learn.microsoft.com/azure/storage/common/storage-service-encryption", "severity": "中等", - "subcategory": "統轄", - "text": " " + "subcategory": "秘密", + "text": "已為所有 Azure 資源管理器和經典記憶體啟用 Azure 儲存加密,並且無法禁用。由於數據預設是加密的,因此無需修改代碼或應用程式即可使用 Azure 儲存加密。", + "training": "https://learn.microsoft.com/training/modules/encrypt-sector-data/?source=recommendations" }, { "category": "安全性、治理與合規性", @@ -833,95 +929,160 @@ "link": "https://learn.microsoft.com/azure/key-vault/general/overview", "severity": "高", "subcategory": "秘密", - "text": "使用 Azure Key Vault 儲存機密和憑據" + "text": "使用 Azure Key Vault 儲存機密和憑據", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "安全性、治理與合規性", "guid": "829e2edb-2173-4676-aff6-691b4935ada4", - "link": "https://learn.microsoft.com/azure/key-vault/general/overview-throttling", + "link": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json", "severity": "中等", "subcategory": "秘密", - "text": "建議在成功部署后鎖定 Azure 資源,以防止未經授權的更改" + "text": "建議在成功部署后鎖定 Azure 資源,以防止未經授權的更改。還可以使用自定義的 Azure 策略(自定義角色)在每個訂閱的基礎上強制實施 LOCK 約束和規則。", + "training": "https://learn.microsoft.com/training/modules/use-azure-resource-manager/?source=recommendations" }, { "category": "安全性、治理與合規性", "guid": "2223ece8-1b12-4318-8a54-17415833fb4a", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "link": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview", "severity": "中等", "subcategory": "秘密", - "text": "預配 Azure Key Vault 並啟用軟刪除和清除策略,以允許對已刪除物件進行保留保護。" + "text": "預配啟用軟刪除和清除策略的 Azure Key Vault,以允許對已刪除物件進行保留保護。", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "安全性、治理與合規性", "guid": "e3c2df74-3165-4c3a-abe0-5bbe209d490d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中等", + "link": "https://learn.microsoft.com/azure/role-based-access-control/security-controls-policy", + "severity": "高", "subcategory": "秘密", - "text": "根據現有要求、法規和合規性控制(內部/外部) - 確定所需的 Azure 策略和 Azure RBAC 角色" + "text": "根據現有要求、法規和合規性控制(內部/外部) - 確定所需的 Azure 策略和 Azure RBAC 角色", + "training": "https://learn.microsoft.com/training/paths/describe-azure-management-governance/?source=recommendations" }, { "category": "安全性、治理與合規性", "guid": "a4777842-4d11-4678-9d2f-a56c56ad4840", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中等", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "高", "subcategory": "秘密", - "text": "啟用適用於 SAP 的 Microsoft Defender for Cloud Standard 時,請確保從安裝終結點保護的任何策略中排除 SAP 資料庫伺服器。" + "text": "在 SAP 環境中啟用 Microsoft Defender for Endpoint 時,建議排除 DBMS 伺服器上的數據和日誌檔,而不是面向所有伺服器。在排除目標檔時,請遵循 DBMS 供應商的建議。", + "training": "https://techcommunity.microsoft.com/t5/running-sap-applications-on-the/microsoft-defender-endpoint-mde-for-sap-applications-on-windows/ba-p/3912268" }, { "category": "安全性、治理與合規性", "guid": "8fe72734-c486-4ba2-a0dc-0591cf65de8e", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中等", + "link": "https://learn.microsoft.com/azure/defender-for-cloud/just-in-time-access-overview?tabs=defender-for-container-arch-aks", + "severity": "高", "subcategory": "秘密", - "text": "委派具有即時訪問許可權的 SAP 管理員自定義角色。" + "text": "委派具有 Microsoft Defender for Cloud 實時訪問許可權的 SAP 管理員自定義角色。", + "training": "https://learn.microsoft.com/training/modules/secure-vms-with-azure-security-center/?source=recommendations" }, { "category": "安全性、治理與合規性", "guid": "1309cccd-5792-466b-aca2-75faa1abfe9d", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中等", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "低", "subcategory": "秘密", - "text": "通過將第三方安全產品與用於 DIAG (SAP GUI)、RFC 和用於 HTTPS 的 SPNEGO 的安全網路通信 (SNC) 集成,對傳輸中的數據進行加密" + "text": "通過將第三方安全產品與用於 DIAG (SAP GUI)、RFC 和用於 HTTPS 的 SPNEGO 的安全網路通信 (SNC) 集成,對傳輸中的數據進行加密", + "training": "https://learn.microsoft.com/azure/security/fundamentals/encryption-overview#encryption-of-data-in-transit" }, { "category": "安全性、治理與合規性", - "guid": "55d04c3c-4919-4cb1-a3d1-325ae124ba34", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", + "link": "https://learn.microsoft.com/azure/storage/common/storage-encryption-key-model-get?tabs=portal", "severity": "中等", "subcategory": "秘密", - "text": "具有 SAML 2.0 的 Azure Active Directory (Azure AD) 還可以為一系列 SAP 應用程式和平臺(如 SAP NetWeaver、SAP HANA 和 SAP Cloud Platform)提供 SSO" + "text": "預設使用 Microsoft 管理的金鑰以實現主體加密功能,並在需要時使用客戶管理的金鑰。", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "安全性、治理與合規性", - "guid": "df685edd-ce9b-4d3b-a0cd-b3b55eb2ec14", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中等", + "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "link": "https://learn.microsoft.com/ja-jp/azure/key-vault/general/best-practices", + "severity": "高", "subcategory": "秘密", - "text": "請確保強化操作系統,以消除可能導致對 SAP 資料庫進行攻擊的漏洞。" + "text": "每個應用程式、每個環境、每個區域使用 Azure Key Vault。", + "training": "https://learn.microsoft.com/training/modules/manage-secrets-with-azure-key-vault/?source=recommendations" }, { "category": "安全性、治理與合規性", - "guid": "eeaa3592-829e-42ed-a217-3676aff6691b", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", - "severity": "中等", + "guid": "abc9634d-c44d-41e9-a530-e8444e16aa3c", + "link": "https://learn.microsoft.com/azure/key-vault/certificates/certificate-scenarios", + "severity": "高", "subcategory": "秘密", - "text": "預設使用 Microsoft 管理的金鑰以實現主體加密功能,並在需要時使用客戶管理的金鑰。" + "text": "若要控制和管理非 HANA Windows 和非 Windows 作業系統的磁碟加密密鑰和機密,請使用 Azure Key Vault。Azure Key Vault 不支援 SAP HANA,因此必須使用 SAP ABAP 或 SSH 密鑰等備用方法。", + "training": "https://learn.microsoft.com/training/modules/configure-and-manage-azure-key-vault/?source=recommendations" }, { "category": "安全性、治理與合規性", - "guid": "4935ada4-2223-4ece-a1b1-23181a541741", + "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", "severity": "中等", "subcategory": "秘密", - "text": "每個應用程式、每個環境、每個區域使用 Azure Key Vault。" + "text": " " }, { "category": "安全性、治理與合規性", - "guid": "5833fb4a-e3c2-4df7-9316-5c3acbe05bbe", - "link": "https://learn.microsoft.com/azure/key-vault/general/best-practices", + "guid": "209d490d-a477-4784-84d1-16785d2fa56c", + "link": "https://learn.microsoft.com/azure/role-based-access-control/built-in-roles", + "severity": "高", + "subcategory": "安全", + "text": "為 Azure 上的 SAP 分支訂閱自定義基於角色的訪問控制 (RBAC) 角色,以避免與網路相關的意外更改", + "training": "https://learn.microsoft.com/training/modules/secure-azure-resources-with-rbac/?source=recommendations" + }, + { + "category": "安全性、治理與合規性", + "guid": "56ad4840-8fe7-4273-9c48-6ba280dc0591", + "link": "https://blogs.sap.com/2019/07/21/sap-security-operations-on-azure/", + "severity": "高", + "subcategory": "安全", + "text": "將 DMZ 和 NVA 與 SAP 資產的其餘部分隔離開來,配置 Azure 專用連結,並安全地管理和控制 Azure 上的 SAP 資源", + "training": "https://learn.microsoft.com/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal" + }, + { + "category": "安全性、治理與合規性", + "guid": "e124ba34-df68-45ed-bce9-bd3bb0cdb3b5", + "link": "https://learn.microsoft.com/en-us/training/modules/secure-vms-with-azure-security-center/?source=recommendations", + "severity": "低", + "subcategory": "安全", + "text": "請考慮在 Azure 上使用 Microsoft 反惡意軟體來保護虛擬機免受惡意檔、廣告軟體和其他威脅的侵害。", + "training": "https://azure.microsoft.com/blog/deploying-antimalware-solutions-on-azure-virtual-machines/" + }, + { + "category": "安全性、治理與合規性", + "guid": "5eb2ec14-eeaa-4359-8829-e2edb2173676", + "link": "https://learn.microsoft.com/microsoft-365/security/defender-endpoint/microsoft-defender-endpoint?view=o365-worldwide", + "severity": "低", + "subcategory": "安全", + "text": "若要獲得更強大的保護,請考慮使用 Microsoft Defender for Endpoint。", + "training": "https://learn.microsoft.com/training/modules/implement-endpoint-protection-use-microsoft-defender/?source=recommendations" + }, + { + "category": "安全性、治理與合規性", + "guid": "87a924c4-25c2-419f-a2f0-96c7c4fe4525", + "link": "https://learn.microsoft.com/azure/architecture/guide/sap/sap-whole-landscape", + "severity": "高", + "subcategory": "安全", + "text": "通過將所有流量傳遞到中心虛擬網路(通過虛擬網路對等互連連接到分支網路),將 SAP 應用程式和資料庫伺服器與 Internet 或本地網路隔離開來。對等互連虛擬網路保證 Azure 上的 SAP 解決方案與公共 Internet 隔離。", + "training": "https://learn.microsoft.com/training/modules/explore-azure-networking/?source=recommendations" + }, + { + "category": "安全性、治理與合規性", + "guid": "491ca1c4-3d40-42c0-9d85-b8933999590b", + "link": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/sap/eslz-security-governance-and-compliance", + "severity": "低", + "subcategory": "安全", + "text": "對於面向 Internet 的應用程式(如 SAP Fiori),請確保在保持安全級別的同時,按應用程式要求分配負載。對於第 7 層安全性,可以使用 Azure 市場中提供的第三方 Web 應用程式防火牆 (WAF)。", + "training": "https://learn.microsoft.com/training/modules/simplify-cloud-procurement-governance-azure-marketplace/?source=recommendations" + }, + { + "category": "安全性、治理與合規性", + "guid": "9fc945b9-0527-47af-8200-9d652fe02fcc", + "link": "https://learn.microsoft.com/azure/sap/monitor/enable-tls-azure-monitor-sap-solutions", "severity": "中等", - "subcategory": "秘密", - "text": " " + "subcategory": "安全", + "text": "若要在用於 SAP 解決方案的 Azure Monitor 中啟用安全通信,可以選擇使用根證書或伺服器證書。我們強烈建議您使用根證書。", + "training": "https://learn.microsoft.com/training/modules/implement-azure-monitoring-sap-workloads-azure-virtual-machines/?source=recommendations" }, { "category": "存儲", @@ -934,7 +1095,7 @@ "metadata": { "name": "Azure Landing Zone Review", "state": "Preview", - "timestamp": "November 24, 2023" + "timestamp": "January 11, 2024" }, "severities": [ { diff --git a/spreadsheet/macrofree/checklist.en.master.xlsx b/spreadsheet/macrofree/checklist.en.master.xlsx index 6462abce7..7fd75b560 100644 Binary files a/spreadsheet/macrofree/checklist.en.master.xlsx and b/spreadsheet/macrofree/checklist.en.master.xlsx differ diff --git a/spreadsheet/macrofree/sap_checklist.en.xlsx b/spreadsheet/macrofree/sap_checklist.en.xlsx index ec19239a6..17c6501b5 100644 Binary files a/spreadsheet/macrofree/sap_checklist.en.xlsx and b/spreadsheet/macrofree/sap_checklist.en.xlsx differ diff --git a/spreadsheet/macrofree/sap_checklist.es.xlsx b/spreadsheet/macrofree/sap_checklist.es.xlsx index 0af70462a..4069564ad 100644 Binary files a/spreadsheet/macrofree/sap_checklist.es.xlsx and b/spreadsheet/macrofree/sap_checklist.es.xlsx differ diff --git a/spreadsheet/macrofree/sap_checklist.ja.xlsx b/spreadsheet/macrofree/sap_checklist.ja.xlsx index 956adbe4f..5c4de7dcc 100644 Binary files a/spreadsheet/macrofree/sap_checklist.ja.xlsx and b/spreadsheet/macrofree/sap_checklist.ja.xlsx differ diff --git a/spreadsheet/macrofree/sap_checklist.ko.xlsx b/spreadsheet/macrofree/sap_checklist.ko.xlsx index 2d30bbd79..921c7ce67 100644 Binary files a/spreadsheet/macrofree/sap_checklist.ko.xlsx and b/spreadsheet/macrofree/sap_checklist.ko.xlsx differ diff --git a/spreadsheet/macrofree/sap_checklist.pt.xlsx b/spreadsheet/macrofree/sap_checklist.pt.xlsx index a5bfe5193..72e2c172c 100644 Binary files a/spreadsheet/macrofree/sap_checklist.pt.xlsx and b/spreadsheet/macrofree/sap_checklist.pt.xlsx differ diff --git a/spreadsheet/macrofree/sap_checklist.zh-Hant.xlsx b/spreadsheet/macrofree/sap_checklist.zh-Hant.xlsx index b2150f722..bb5a4884f 100644 Binary files a/spreadsheet/macrofree/sap_checklist.zh-Hant.xlsx and b/spreadsheet/macrofree/sap_checklist.zh-Hant.xlsx differ diff --git a/workbooks/alz_checklist.en_network_counters.json b/workbooks/alz_checklist.en_network_counters.json index e84733dc7..8c022ff86 100644 --- a/workbooks/alz_checklist.en_network_counters.json +++ b/workbooks/alz_checklist.en_network_counters.json @@ -749,7 +749,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}" + "resultVal": "{Query18Stats:$.Success}" } } ] @@ -768,7 +768,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}" + "resultVal": "{Query18Stats:$.Total}" } } ] @@ -806,7 +806,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query10Stats:$.Success}+{Query11Stats:$.Success}" + "resultVal": "{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}" } } ] @@ -825,7 +825,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query10Stats:$.Total}+{Query11Stats:$.Total}" + "resultVal": "{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}" } } ] @@ -863,7 +863,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query18Stats:$.Success}" + "resultVal": "{Query23Stats:$.Success}" } } ] @@ -882,7 +882,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query18Stats:$.Total}" + "resultVal": "{Query23Stats:$.Total}" } } ] @@ -977,7 +977,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query23Stats:$.Success}" + "resultVal": "{Query10Stats:$.Success}+{Query11Stats:$.Success}" } } ] @@ -996,7 +996,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query23Stats:$.Total}" + "resultVal": "{Query10Stats:$.Total}+{Query11Stats:$.Total}" } } ] @@ -1034,7 +1034,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.Success}" + "resultVal": "{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}" } } ] @@ -1053,7 +1053,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.Total}" + "resultVal": "{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}" } } ] @@ -1091,7 +1091,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}" + "resultVal": "{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.Success}" } } ] @@ -1110,7 +1110,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}" + "resultVal": "{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.Total}" } } ] @@ -1148,7 +1148,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.Total}+{Query23Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}" + "resultVal": "{Query18Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query23Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.Total}" } } ] @@ -1167,7 +1167,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.Success}+{Query23Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}" + "resultVal": "{Query18Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query23Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.Success}" } } ] @@ -1241,34 +1241,34 @@ "style": "tabs", "links": [ { - "id": "bff2cb3f-8087-4319-a8cf-810034b5b293", + "id": "35f07a09-028c-4254-b496-52deb79b50df", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Internet ({Tab0Success:value}/{Tab0Total:value})", + "linkLabel": "PaaS ({Tab0Success:value}/{Tab0Total:value})", "subTarget": "tab0", - "preText": "Internet", + "preText": "PaaS", "style": "primary" }, { - "id": "31df8a1c-944b-4f7f-ae74-860e423c17bd", + "id": "8a3ea40d-843e-458a-a272-ceb877b7aa0d", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "IP plan ({Tab1Success:value}/{Tab1Total:value})", + "linkLabel": "Hub and spoke ({Tab1Success:value}/{Tab1Total:value})", "subTarget": "tab1", - "preText": "IP plan", + "preText": "Hub and spoke", "style": "primary" }, { - "id": "ccaa8035-700c-4618-8eed-51dd284ac094", + "id": "afe943e2-6bbc-4ef7-85cb-64954d1d06aa", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS ({Tab2Success:value}/{Tab2Total:value})", + "linkLabel": "Virtual WAN ({Tab2Success:value}/{Tab2Total:value})", "subTarget": "tab2", - "preText": "PaaS", + "preText": "Virtual WAN", "style": "primary" }, { - "id": "8c4c21c1-51c2-484f-921c-538c48517027", + "id": "a302f87e-2c70-4c74-b83a-ebd3f5de6400", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Segmentation ({Tab3Success:value}/{Tab3Total:value})", @@ -1277,30 +1277,30 @@ "style": "primary" }, { - "id": "913805f4-47d7-4cac-9fcc-c5ef17d4a132", + "id": "2a341f64-dfc2-4ab1-b220-fe169764b328", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN ({Tab4Success:value}/{Tab4Total:value})", + "linkLabel": "IP plan ({Tab4Success:value}/{Tab4Total:value})", "subTarget": "tab4", - "preText": "Virtual WAN", + "preText": "IP plan", "style": "primary" }, { - "id": "f962687c-e0f3-4801-816b-cdc957dbaeb9", + "id": "2aae6146-3c29-4e0f-b437-3a60bbb9651b", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hybrid ({Tab5Success:value}/{Tab5Total:value})", + "linkLabel": "Internet ({Tab5Success:value}/{Tab5Total:value})", "subTarget": "tab5", - "preText": "Hybrid", + "preText": "Internet", "style": "primary" }, { - "id": "771d3851-8fc2-44a2-979a-b5a54d145cb2", + "id": "1e46bce1-edbf-438a-9700-aff0b3586cba", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hub and spoke ({Tab6Success:value}/{Tab6Total:value})", + "linkLabel": "Hybrid ({Tab6Success:value}/{Tab6Total:value})", "subTarget": "tab6", - "preText": "Hub and spoke", + "preText": "Hybrid", "style": "primary" } ] @@ -1316,22 +1316,22 @@ { "type": 1, "content": { - "json": "## Internet" + "json": "## PaaS" }, "name": "tab0title" }, { "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." + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." }, - "name": "querytext12" + "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/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", @@ -1380,20 +1380,42 @@ ] } }, - "name": "query12" + "name": "query18" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hub and spoke" + }, + "name": "tab1title" }, { "type": 1, "content": { - "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." + "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." }, - "name": "querytext13" + "name": "querytext0" }, { "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 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": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1442,20 +1464,20 @@ ] } }, - "name": "query13" + "name": "query0" }, { "type": 1, "content": { - "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." + "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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." }, - "name": "querytext14" + "name": "querytext1" }, { "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/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": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1504,20 +1526,20 @@ ] } }, - "name": "query14" + "name": "query1" }, { "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) for further information." + "json": "Consider the limit of routes per route table (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." }, - "name": "querytext15" + "name": "querytext2" }, { "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/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": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1566,20 +1588,20 @@ ] } }, - "name": "query15" + "name": "query2" }, { "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." + "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." }, - "name": "querytext16" + "name": "querytext3" }, { "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' | 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": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1628,20 +1650,42 @@ ] } }, - "name": "query16" + "name": "query3" + } + ] + }, + "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" }, { "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": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext17" + "name": "querytext23" }, { "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/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", @@ -1690,16 +1734,16 @@ ] } }, - "name": "query17" + "name": "query23" } ] }, "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab0" + "value": "tab2" }, - "name": "tab0" + "name": "tab2" }, { "type": 12, @@ -1710,22 +1754,22 @@ { "type": 1, "content": { - "json": "## IP plan" + "json": "## Segmentation" }, - "name": "tab1title" + "name": "tab3title" }, { "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 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." }, - "name": "querytext10" + "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/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", @@ -1774,20 +1818,20 @@ ] } }, - "name": "query10" + "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": "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": "querytext11" + "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/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", @@ -1836,42 +1880,20 @@ ] } }, - "name": "query11" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab1" - }, - "name": "tab1" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## PaaS" - }, - "name": "tab2title" + "name": "query20" }, { "type": 1, "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) 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": "querytext18" + "name": "querytext21" }, { "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/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", @@ -1920,42 +1942,20 @@ ] } }, - "name": "query18" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab2" - }, - "name": "tab2" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Segmentation" - }, - "name": "tab3title" + "name": "query21" }, { "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." + "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." }, - "name": "querytext19" + "name": "querytext22" }, { "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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2004,20 +2004,42 @@ ] } }, - "name": "query19" + "name": "query22" + } + ] + }, + "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": "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": "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": "querytext20" + "name": "querytext10" }, { "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/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", @@ -2066,20 +2088,20 @@ ] } }, - "name": "query20" + "name": "query10" }, { "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": "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": "querytext21" + "name": "querytext11" }, { "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' | 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", @@ -2128,20 +2150,42 @@ ] } }, - "name": "query21" + "name": "query11" + } + ] + }, + "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": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) 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." }, - "name": "querytext22" + "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,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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", @@ -2190,42 +2234,20 @@ ] } }, - "name": "query22" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab3" - }, - "name": "tab3" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Virtual WAN" - }, - "name": "tab4title" + "name": "query12" }, { "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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." }, - "name": "querytext23" + "name": "querytext13" }, { "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/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", @@ -2274,42 +2296,20 @@ ] } }, - "name": "query23" - } - ] - }, - "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": "query13" }, { "type": 1, "content": { - "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." + "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "name": "querytext4" + "name": "querytext14" }, { "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' | 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", @@ -2358,20 +2358,20 @@ ] } }, - "name": "query4" + "name": "query14" }, { "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." + "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) for further information." }, - "name": "querytext5" + "name": "querytext15" }, { "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/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", @@ -2420,20 +2420,20 @@ ] } }, - "name": "query5" + "name": "query15" }, { "type": 1, "content": { - "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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." + "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." }, - "name": "querytext6" + "name": "querytext16" }, { "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/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", @@ -2482,20 +2482,20 @@ ] } }, - "name": "query6" + "name": "query16" }, { "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 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": "querytext7" + "name": "querytext17" }, { "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' | 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", @@ -2544,20 +2544,42 @@ ] } }, - "name": "query7" + "name": "query17" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab5" + }, + "name": "tab5" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hybrid" + }, + "name": "tab6title" }, { "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 you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext8" + "name": "querytext4" }, { "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/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", @@ -2606,20 +2628,20 @@ ] } }, - "name": "query8" + "name": "query4" }, { "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": "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." }, - "name": "querytext9" + "name": "querytext5" }, { "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/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", @@ -2668,42 +2690,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": "## Hub and spoke" - }, - "name": "tab6title" + "name": "query5" }, { "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." + "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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." }, - "name": "querytext0" + "name": "querytext6" }, { "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/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", @@ -2752,20 +2752,20 @@ ] } }, - "name": "query0" + "name": "query6" }, { "type": 1, "content": { - "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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." + "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": "querytext1" + "name": "querytext7" }, { "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/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", @@ -2814,20 +2814,20 @@ ] } }, - "name": "query1" + "name": "query7" }, { "type": 1, "content": { - "json": "Consider the limit of routes per route table (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." + "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": "querytext2" + "name": "querytext8" }, { "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/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", @@ -2876,20 +2876,20 @@ ] } }, - "name": "query2" + "name": "query8" }, { "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." + "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": "querytext3" + "name": "querytext9" }, { "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,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", @@ -2938,7 +2938,7 @@ ] } }, - "name": "query3" + "name": "query9" } ] }, diff --git a/workbooks/alz_checklist.en_network_counters_template.json b/workbooks/alz_checklist.en_network_counters_template.json index 22b2375df..ded98c87d 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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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,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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| 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/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\": \"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\": \"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\": \"{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.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\": \"{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.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\": \"{Query10Stats:$.Success}+{Query11Stats:$.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\": \"{Query10Stats:$.Total}+{Query11Stats:$.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\": \"{Query18Stats:$.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\": \"{Query18Stats:$.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\": \"{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.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\": \"{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.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\": \"{Query23Stats:$.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\": \"{Query23Stats:$.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\": \"{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.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\": \"{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.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\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.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}\"\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\": \"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\": \"{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query18Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.Total}+{Query23Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.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\": \"{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query18Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.Success}+{Query23Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.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\": \"bff2cb3f-8087-4319-a8cf-810034b5b293\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet ({Tab0Success:value}/{Tab0Total:value})\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"31df8a1c-944b-4f7f-ae74-860e423c17bd\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan ({Tab1Success:value}/{Tab1Total:value})\",\n \"subTarget\": \"tab1\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ccaa8035-700c-4618-8eed-51dd284ac094\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS ({Tab2Success:value}/{Tab2Total:value})\",\n \"subTarget\": \"tab2\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"8c4c21c1-51c2-484f-921c-538c48517027\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation ({Tab3Success:value}/{Tab3Total:value})\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"913805f4-47d7-4cac-9fcc-c5ef17d4a132\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN ({Tab4Success:value}/{Tab4Total:value})\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"f962687c-e0f3-4801-816b-cdc957dbaeb9\",\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\": \"771d3851-8fc2-44a2-979a-b5a54d145cb2\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke ({Tab6Success:value}/{Tab6Total:value})\",\n \"subTarget\": \"tab6\",\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\": \"## Internet\"\n },\n \"name\": \"tab0title\"\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.\"\n },\n \"name\": \"querytext12\"\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\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext13\"\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\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext14\"\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\": \"query14\"\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) for further information.\"\n },\n \"name\": \"querytext15\"\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\": \"query15\"\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.\"\n },\n \"name\": \"querytext16\"\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\": \"query16\"\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\": \"querytext17\"\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\": \"query17\"\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\": \"## IP plan\"\n },\n \"name\": \"tab1title\"\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\": \"querytext10\"\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\": \"query10\"\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\": \"querytext11\"\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\": \"query11\"\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\": \"## PaaS\"\n },\n \"name\": \"tab2title\"\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/app-service/networking-features) 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\": \"querytext18\"\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\": \"query18\"\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\": \"## Segmentation\"\n },\n \"name\": \"tab3title\"\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.\"\n },\n \"name\": \"querytext19\"\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\": \"query19\"\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\": \"querytext20\"\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\": \"query20\"\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\": \"querytext21\"\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\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) 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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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 },\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\": \"## Virtual WAN\"\n },\n \"name\": \"tab4title\"\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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) 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/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\": \"query23\"\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\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) 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\": \"querytext4\"\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\": \"query4\"\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.\"\n },\n \"name\": \"querytext5\"\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\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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.\"\n },\n \"name\": \"querytext6\"\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\": \"query6\"\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\": \"querytext7\"\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\": \"query7\"\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\": \"querytext8\"\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\": \"query8\"\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\": \"querytext9\"\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\": \"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.\"\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\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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.\"\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\": \"Consider the limit of routes per route table (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.\"\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.\"\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 },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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,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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| 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/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\": \"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\": \"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\": \"{Query18Stats:$.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\": \"{Query18Stats:$.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}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.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}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.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\": \"{Query23Stats:$.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\": \"{Query23Stats:$.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\": \"{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.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\": \"{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.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\": \"{Query10Stats:$.Success}+{Query11Stats:$.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\": \"{Query10Stats:$.Total}+{Query11Stats:$.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\": \"{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.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\": \"{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.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\": \"{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.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\": \"{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.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\": \"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\": \"{Query18Stats:$.Total}+{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query23Stats:$.Total}+{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.Total}+{Query10Stats:$.Total}+{Query11Stats:$.Total}+{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.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\": \"{Query18Stats:$.Success}+{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query23Stats:$.Success}+{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.Success}+{Query10Stats:$.Success}+{Query11Stats:$.Success}+{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.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\": \"35f07a09-028c-4254-b496-52deb79b50df\",\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\": \"8a3ea40d-843e-458a-a272-ceb877b7aa0d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke ({Tab1Success:value}/{Tab1Total:value})\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"afe943e2-6bbc-4ef7-85cb-64954d1d06aa\",\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\": \"a302f87e-2c70-4c74-b83a-ebd3f5de6400\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation ({Tab3Success:value}/{Tab3Total:value})\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"2a341f64-dfc2-4ab1-b220-fe169764b328\",\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\": \"2aae6146-3c29-4e0f-b437-3a60bbb9651b\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet ({Tab5Success:value}/{Tab5Total:value})\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"1e46bce1-edbf-438a-9700-aff0b3586cba\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid ({Tab6Success:value}/{Tab6Total:value})\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Hybrid\",\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/app-service/networking-features) 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\": \"querytext18\"\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\": \"query18\"\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\": \"## Hub and spoke\"\n },\n \"name\": \"tab1title\"\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.\"\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\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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.\"\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\": \"Consider the limit of routes per route table (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.\"\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.\"\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 },\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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) 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/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\": \"query23\"\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\": \"## Segmentation\"\n },\n \"name\": \"tab3title\"\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.\"\n },\n \"name\": \"querytext19\"\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\": \"query19\"\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\": \"querytext20\"\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\": \"query20\"\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\": \"querytext21\"\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\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) 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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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 },\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\": \"querytext10\"\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\": \"query10\"\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\": \"querytext11\"\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\": \"query11\"\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.\"\n },\n \"name\": \"querytext12\"\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\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext13\"\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\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext14\"\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\": \"query14\"\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) for further information.\"\n },\n \"name\": \"querytext15\"\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\": \"query15\"\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.\"\n },\n \"name\": \"querytext16\"\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\": \"query16\"\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\": \"querytext17\"\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\": \"query17\"\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\": \"## Hybrid\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) 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\": \"querytext4\"\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\": \"query4\"\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.\"\n },\n \"name\": \"querytext5\"\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\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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.\"\n },\n \"name\": \"querytext6\"\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\": \"query6\"\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\": \"querytext7\"\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\": \"query7\"\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\": \"querytext8\"\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\": \"query8\"\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\": \"querytext9\"\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\": \"query9\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\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 43ce1f777..a24f96f21 100644 --- a/workbooks/alz_checklist.en_network_tabcounters.json +++ b/workbooks/alz_checklist.en_network_tabcounters.json @@ -70,61 +70,61 @@ "style": "tabs", "links": [ { - "id": "cefaac0c-d207-4c42-9a7d-75d2f86d1f7d", + "id": "9481f56b-abfd-4262-8a7c-d9a1f738d1e3", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hub and spoke", + "linkLabel": "Virtual WAN", "subTarget": "tab0", - "preText": "Hub and spoke", + "preText": "Virtual WAN", "style": "primary" }, { - "id": "87c13089-5aaf-44df-95a0-1037fa8ea326", + "id": "254839ab-5719-49ba-9056-ba52ddbfbf0e", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hybrid", + "linkLabel": "PaaS", "subTarget": "tab1", - "preText": "Hybrid", + "preText": "PaaS", "style": "primary" }, { - "id": "f8da229c-21e4-41e4-93f9-a0db2edfc8fd", + "id": "080e94dc-2a70-4423-9de4-58f6ce9dee18", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Segmentation", + "linkLabel": "Hybrid", "subTarget": "tab2", - "preText": "Segmentation", + "preText": "Hybrid", "style": "primary" }, { - "id": "bda372ef-4c44-4dfa-b744-8112289085a1", + "id": "21719327-f800-4e78-a6cf-30a6e3ea37f9", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS", + "linkLabel": "Internet", "subTarget": "tab3", - "preText": "PaaS", + "preText": "Internet", "style": "primary" }, { - "id": "f5c27a70-6301-4cba-89c3-9f69fc37893f", + "id": "456aa0e5-3657-4627-9b74-36ebdd0233a4", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN", + "linkLabel": "Hub and spoke", "subTarget": "tab4", - "preText": "Virtual WAN", + "preText": "Hub and spoke", "style": "primary" }, { - "id": "44cda46e-7086-4d59-870d-691604dbe547", + "id": "16f325de-6441-4e8b-8719-a16b31b56ffd", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Internet", + "linkLabel": "Segmentation", "subTarget": "tab5", - "preText": "Internet", + "preText": "Segmentation", "style": "primary" }, { - "id": "ed560364-b2db-4766-80be-67632a817e9d", + "id": "74fbb015-3f4b-4617-b0d4-d0e557c3a0a4", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "IP plan", @@ -153,9 +153,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query0Stats", + "name": "Query23Stats", "type": 1, - "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())", + "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}" ], @@ -169,9 +169,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query0FullyCompliant", + "name": "Query23FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query0Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query23Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -181,65 +181,199 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query1Stats", + "name": "Tab0Success", "type": 1, - "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())", - "crossComponentResources": [ - "{Subscription}" - ], "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "{Query23Stats:$.Success}" + } + } + ] }, { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query1FullyCompliant", + "name": "Tab0Total", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query1Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 }, - "queryType": 8 + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "{Query23Stats:$.Total}" + } + } + ] }, { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query2Stats", + "name": "Tab0Percent", "type": 1, - "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())", - "crossComponentResources": [ - "{Subscription}" - ], "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query2FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query2Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "round(100*{Tab0Success}/{Tab0Total})" + } + } + ] + } + ], + "style": "pills", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + "name": "TabInvisibleParameters" + }, + { + "type": 1, + "content": { + "json": "## Virtual WAN" + }, + "customWidth": "50", + "name": "tab0title" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab0Percent}\\\", \\\"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" }, - "queryType": 8 + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } }, + "subtitleContent": { + "columnMatch": "Column2" + }, + "showBorder": true + } + }, + "customWidth": "50", + "name": "TabPercentTile" + }, + { + "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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." + }, + "name": "querytext23" + }, + { + "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", + "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": "query23" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "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": "Query3Stats", + "name": "Query18Stats", "type": 1, - "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())", + "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}" ], @@ -253,9 +387,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query3FullyCompliant", + "name": "Query18FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query3Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query18Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -265,7 +399,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab0Success", + "name": "Tab1Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -276,7 +410,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}" + "resultVal": "{Query18Stats:$.Success}" } } ] @@ -284,7 +418,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab0Total", + "name": "Tab1Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -295,7 +429,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}" + "resultVal": "{Query18Stats:$.Total}" } } ] @@ -303,7 +437,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab0Percent", + "name": "Tab1Percent", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -314,7 +448,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab0Success}/{Tab0Total})" + "resultVal": "round(100*{Tab1Success}/{Tab1Total})" } } ] @@ -329,16 +463,16 @@ { "type": 1, "content": { - "json": "## Hub and spoke" + "json": "## PaaS" }, "customWidth": "50", - "name": "tab0title" + "name": "tab1title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab0Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab1Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", "size": 3, "queryType": 8, "visualization": "tiles", @@ -370,15 +504,15 @@ { "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." + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." }, - "name": "querytext0" + "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 == '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 = 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", @@ -427,202 +561,16 @@ ] } }, - "name": "query0" - }, - { - "type": 1, - "content": { - "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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." - }, - "name": "querytext1" - }, - { - "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", - "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": "query1" - }, - { - "type": 1, - "content": { - "json": "Consider the limit of routes per route table (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." - }, - "name": "querytext2" - }, - { - "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", - "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": "query2" - }, - { - "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." - }, - "name": "querytext3" - }, - { - "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", - "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": "query3" + "name": "query18" } ] }, "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab0" + "value": "tab1" }, - "name": "tab0" + "name": "tab1" }, { "type": 12, @@ -809,7 +757,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab1Success", + "name": "Tab2Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -828,7 +776,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab1Total", + "name": "Tab2Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -847,7 +795,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab1Percent", + "name": "Tab2Percent", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -858,7 +806,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab1Success}/{Tab1Total})" + "resultVal": "round(100*{Tab2Success}/{Tab2Total})" } } ] @@ -876,13 +824,13 @@ "json": "## Hybrid" }, "customWidth": "50", - "name": "tab1title" + "name": "tab2title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab1Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab2Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", "size": 3, "queryType": 8, "visualization": "tiles", @@ -1288,9 +1236,9 @@ "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab1" + "value": "tab2" }, - "name": "tab1" + "name": "tab2" }, { "type": 12, @@ -1309,9 +1257,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query19Stats", + "name": "Query12Stats", "type": 1, - "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())", + "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())", "crossComponentResources": [ "{Subscription}" ], @@ -1325,9 +1273,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query19FullyCompliant", + "name": "Query12FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query19Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query12Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1337,9 +1285,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query20Stats", + "name": "Query13Stats", "type": 1, - "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())", + "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())", "crossComponentResources": [ "{Subscription}" ], @@ -1353,9 +1301,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query20FullyCompliant", + "name": "Query13FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query20Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query13Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1365,9 +1313,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query21Stats", + "name": "Query14Stats", "type": 1, - "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())", + "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())", "crossComponentResources": [ "{Subscription}" ], @@ -1381,9 +1329,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query21FullyCompliant", + "name": "Query14FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query21Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query14Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1393,9 +1341,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query22Stats", + "name": "Query15Stats", "type": 1, - "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| 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/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())", "crossComponentResources": [ "{Subscription}" ], @@ -1409,9 +1357,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query22FullyCompliant", + "name": "Query15FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query22Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query15Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1421,26 +1369,63 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab2Success", + "name": "Query16Stats", "type": 1, + "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())", + "crossComponentResources": [ + "{Subscription}" + ], "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.Success}" - } - } - ] + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" }, { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab2Total", + "name": "Query16FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query16Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query17Stats", + "type": 1, + "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())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query17FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query17Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab3Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1451,7 +1436,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.Total}" + "resultVal": "{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}" } } ] @@ -1459,7 +1444,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab2Percent", + "name": "Tab3Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1470,7 +1455,26 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab2Success}/{Tab2Total})" + "resultVal": "{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}" + } + } + ] + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab3Percent", + "type": 1, + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "criteriaData": [ + { + "criteriaContext": { + "operator": "Default", + "resultValType": "expression", + "resultVal": "round(100*{Tab3Success}/{Tab3Total})" } } ] @@ -1485,16 +1489,16 @@ { "type": 1, "content": { - "json": "## Segmentation" + "json": "## Internet" }, "customWidth": "50", - "name": "tab2title" + "name": "tab3title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab2Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab3Percent}\\\", \\\"Column2\\\": \\\"Percent of successful checks\\\"}\",\"transformers\":null}", "size": 3, "queryType": 8, "visualization": "tiles", @@ -1526,15 +1530,15 @@ { "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." + "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." }, - "name": "querytext19" + "name": "querytext12" }, { "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 == '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", @@ -1583,20 +1587,20 @@ ] } }, - "name": "query19" + "name": "query12" }, { "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": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." }, - "name": "querytext20" + "name": "querytext13" }, { "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/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", @@ -1645,20 +1649,20 @@ ] } }, - "name": "query20" + "name": "query13" }, { "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 Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "name": "querytext21" + "name": "querytext14" }, { "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.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", @@ -1707,20 +1711,20 @@ ] } }, - "name": "query21" + "name": "query14" }, { "type": 1, "content": { - "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) 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) for further information." }, - "name": "querytext22" + "name": "querytext15" }, { "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,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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", @@ -1769,16 +1773,140 @@ ] } }, - "name": "query22" + "name": "query15" + }, + { + "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." + }, + "name": "querytext16" + }, + { + "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", + "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": "query16" + }, + { + "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." + }, + "name": "querytext17" + }, + { + "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", + "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": "query17" } ] }, "conditionalVisibility": { "parameterName": "VisibleTab", "comparison": "isEqualTo", - "value": "tab2" + "value": "tab3" }, - "name": "tab2" + "name": "tab3" }, { "type": 12, @@ -1797,9 +1925,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query18Stats", + "name": "Query0Stats", "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/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())", "crossComponentResources": [ "{Subscription}" ], @@ -1813,9 +1941,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query18FullyCompliant", + "name": "Query0FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query18Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query0Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -1825,26 +1953,91 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab3Success", + "name": "Query1Stats", "type": 1, + "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())", + "crossComponentResources": [ + "{Subscription}" + ], "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 }, - "criteriaData": [ - { - "criteriaContext": { - "operator": "Default", - "resultValType": "expression", - "resultVal": "{Query18Stats:$.Success}" - } - } - ] - }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab3Total", + "name": "Query1FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query1Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query2Stats", + "type": 1, + "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())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query2FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query2Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query3Stats", + "type": 1, + "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())", + "crossComponentResources": [ + "{Subscription}" + ], + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Query3FullyCompliant", + "type": 1, + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query3Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "isHiddenWhenLocked": true, + "timeContext": { + "durationMs": 86400000 + }, + "queryType": 8 + }, + { + "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", + "version": "KqlParameterItem/1.0", + "name": "Tab4Success", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1855,7 +2048,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query18Stats:$.Total}" + "resultVal": "{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}" } } ] @@ -1863,7 +2056,7 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Tab3Percent", + "name": "Tab4Total", "type": 1, "isHiddenWhenLocked": true, "timeContext": { @@ -1874,7 +2067,26 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "round(100*{Tab3Success}/{Tab3Total})" + "resultVal": "{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.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})" } } ] @@ -1889,16 +2101,16 @@ { "type": 1, "content": { - "json": "## PaaS" + "json": "## Hub and spoke" }, "customWidth": "50", - "name": "tab3title" + "name": "tab4title" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"Column1\\\": \\\"{Tab3Percent}\\\", \\\"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", @@ -1930,15 +2142,15 @@ { "type": 1, "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) 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." }, - "name": "querytext18" + "name": "querytext0" }, { "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 == 'RouteServerSubnet' | 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", @@ -1987,176 +2199,144 @@ ] } }, - "name": "query18" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab3" - }, - "name": "tab3" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ + "name": "query0" + }, { - "type": 9, + "type": 1, "content": { - "version": "KqlParameterItem/1.0", + "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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." + }, + "name": "querytext1" + }, + { + "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", + "size": 4, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", "crossComponentResources": [ "{Subscription}" ], - "parameters": [ - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query23Stats", - "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": "Query23FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query23Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "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": "{Query23Stats:$.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": "{Query23Stats:$.Total}" + "gridSettings": { + "formatters": [ + { + "columnMatch": "id", + "formatter": 0, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" } } - ] - }, - { - "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})" - } + { + "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" + } + ] } - ] - } - ], - "style": "pills", - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" + } + ] + } }, - "name": "TabInvisibleParameters" + "name": "query1" }, { "type": 1, "content": { - "json": "## Virtual WAN" + "json": "Consider the limit of routes per route table (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." }, - "customWidth": "50", - "name": "tab4title" + "name": "querytext2" }, { "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" + "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": 4, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", + "crossComponentResources": [ + "{Subscription}" + ], + "gridSettings": { + "formatters": [ + { + "columnMatch": "id", + "formatter": 0, + "numberFormat": { + "unit": 0, + "options": { + "style": "decimal" + } + } }, - "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" + } + ] } } - }, - "subtitleContent": { - "columnMatch": "Column2" - }, - "showBorder": true + ] } }, - "customWidth": "50", - "name": "TabPercentTile" + "name": "query2" }, { "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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) 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." }, - "name": "querytext23" + "name": "querytext3" }, { "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' | 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": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2205,7 +2385,7 @@ ] } }, - "name": "query23" + "name": "query3" } ] }, @@ -2233,65 +2413,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query12Stats", - "type": 1, - "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())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query12FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query12Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query13Stats", - "type": 1, - "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())", - "crossComponentResources": [ - "{Subscription}" - ], - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 1, - "resourceType": "microsoft.resourcegraph/resources" - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query13FullyCompliant", - "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query13Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", - "isHiddenWhenLocked": true, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 8 - }, - { - "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", - "version": "KqlParameterItem/1.0", - "name": "Query14Stats", + "name": "Query19Stats", "type": 1, - "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())", + "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())", "crossComponentResources": [ "{Subscription}" ], @@ -2305,9 +2429,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query14FullyCompliant", + "name": "Query19FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query14Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query19Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2317,9 +2441,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query15Stats", + "name": "Query20Stats", "type": 1, - "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())", + "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())", "crossComponentResources": [ "{Subscription}" ], @@ -2333,9 +2457,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query15FullyCompliant", + "name": "Query20FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query15Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query20Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2345,9 +2469,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query16Stats", + "name": "Query21Stats", "type": 1, - "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())", + "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())", "crossComponentResources": [ "{Subscription}" ], @@ -2361,9 +2485,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query16FullyCompliant", + "name": "Query21FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query16Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query21Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2373,9 +2497,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query17Stats", + "name": "Query22Stats", "type": 1, - "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())", + "query": "Resources | where type=='microsoft.network/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| 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}" ], @@ -2389,9 +2513,9 @@ { "id": "daf05c62-1d5b-4325-b241-d7ee468f23eb", "version": "KqlParameterItem/1.0", - "name": "Query17FullyCompliant", + "name": "Query22FullyCompliant", "type": 1, - "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query17Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", + "query": "{\"version\":\"1.0.0\",\"content\":\"{\\\"value\\\": \\\"{Query22Stats:$.FullyCompliant}\\\"}\",\"transformers\":null}", "isHiddenWhenLocked": true, "timeContext": { "durationMs": 86400000 @@ -2412,7 +2536,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.Success}" + "resultVal": "{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.Success}" } } ] @@ -2431,7 +2555,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.Total}" + "resultVal": "{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.Total}" } } ] @@ -2465,7 +2589,7 @@ { "type": 1, "content": { - "json": "## Internet" + "json": "## Segmentation" }, "customWidth": "50", "name": "tab5title" @@ -2506,139 +2630,15 @@ { "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." - }, - "name": "querytext12" - }, - { - "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", - "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": "query12" - }, - { - "type": 1, - "content": { - "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." - }, - "name": "querytext13" - }, - { - "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", - "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": "query13" - }, - { - "type": 1, - "content": { - "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) 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." }, - "name": "querytext14" + "name": "querytext19" }, { "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/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", @@ -2687,20 +2687,20 @@ ] } }, - "name": "query14" + "name": "query19" }, { "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) for further information." + "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": "querytext15" + "name": "querytext20" }, { "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/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", @@ -2749,20 +2749,20 @@ ] } }, - "name": "query15" + "name": "query20" }, { "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." + "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": "querytext16" + "name": "querytext21" }, { "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/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", @@ -2811,20 +2811,20 @@ ] } }, - "name": "query16" + "name": "query21" }, { "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": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." }, - "name": "querytext17" + "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,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/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -2873,7 +2873,7 @@ ] } }, - "name": "query17" + "name": "query22" } ] }, diff --git a/workbooks/alz_checklist.en_network_tabcounters_template.json b/workbooks/alz_checklist.en_network_tabcounters_template.json index 0e437e214..fc3e6e62f 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\": \"cefaac0c-d207-4c42-9a7d-75d2f86d1f7d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"87c13089-5aaf-44df-95a0-1037fa8ea326\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"f8da229c-21e4-41e4-93f9-a0db2edfc8fd\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"bda372ef-4c44-4dfa-b744-8112289085a1\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab3\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"f5c27a70-6301-4cba-89c3-9f69fc37893f\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"44cda46e-7086-4d59-870d-691604dbe547\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"ed560364-b2db-4766-80be-67632a817e9d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab6\",\n \"preText\": \"IP plan\",\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\": \"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\": \"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}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.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}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.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\": \"## Hub and spoke\"\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\": \"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.\"\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\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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.\"\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\": \"Consider the limit of routes per route table (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.\"\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.\"\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 },\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\": \"Query4Stats\",\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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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,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\": \"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\": \"{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{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\": \"{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{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\": \"## Hybrid\"\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\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) 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\": \"querytext4\"\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\": \"query4\"\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.\"\n },\n \"name\": \"querytext5\"\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\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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.\"\n },\n \"name\": \"querytext6\"\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\": \"query6\"\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\": \"querytext7\"\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\": \"query7\"\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\": \"querytext8\"\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\": \"query8\"\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\": \"querytext9\"\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\": \"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\": \"Query19Stats\",\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\": \"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/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\": \"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/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\": \"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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| 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\": \"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\": \"{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.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\": \"{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.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\": \"## Segmentation\"\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\": \"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.\"\n },\n \"name\": \"querytext19\"\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\": \"query19\"\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\": \"querytext20\"\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\": \"query20\"\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\": \"querytext21\"\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\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) 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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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 },\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\": \"Query18Stats\",\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\": \"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\": \"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\": \"{Query18Stats:$.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\": \"{Query18Stats:$.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\": \"## PaaS\"\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\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) 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\": \"querytext18\"\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\": \"query18\"\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\": \"Query23Stats\",\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\": \"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\": \"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\": \"{Query23Stats:$.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\": \"{Query23Stats:$.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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) 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/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\": \"query23\"\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\": \"Query12Stats\",\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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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\": \"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\": \"{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.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\": \"{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.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\": \"## Internet\"\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 Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.\"\n },\n \"name\": \"querytext12\"\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\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext13\"\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\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext14\"\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\": \"query14\"\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) for further information.\"\n },\n \"name\": \"querytext15\"\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\": \"query15\"\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.\"\n },\n \"name\": \"querytext16\"\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\": \"query16\"\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\": \"querytext17\"\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\": \"query17\"\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\": \"Query10Stats\",\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\": \"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/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\": \"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\": \"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\": \"{Query10Stats:$.Success}+{Query11Stats:$.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\": \"{Query10Stats:$.Total}+{Query11Stats:$.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\": \"querytext10\"\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\": \"query10\"\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\": \"querytext11\"\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\": \"query11\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\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\": \"9481f56b-abfd-4262-8a7c-d9a1f738d1e3\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"254839ab-5719-49ba-9056-ba52ddbfbf0e\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab1\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"080e94dc-2a70-4423-9de4-58f6ce9dee18\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"21719327-f800-4e78-a6cf-30a6e3ea37f9\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"456aa0e5-3657-4627-9b74-36ebdd0233a4\",\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\": \"16f325de-6441-4e8b-8719-a16b31b56ffd\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"74fbb015-3f4b-4617-b0d4-d0e557c3a0a4\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab6\",\n \"preText\": \"IP plan\",\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\": \"Query23Stats\",\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\": \"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\": \"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\": \"{Query23Stats:$.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\": \"{Query23Stats:$.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\": \"## Virtual WAN\"\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\": \"For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) 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/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\": \"query23\"\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\": \"Query18Stats\",\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\": \"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\": \"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\": \"{Query18Stats:$.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\": \"{Query18Stats:$.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\": \"## PaaS\"\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\": \"Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) 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\": \"querytext18\"\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\": \"query18\"\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\": \"Query4Stats\",\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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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,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\": \"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\": \"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\": \"{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query8Stats:$.Success}+{Query9Stats:$.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\": \"{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query8Stats:$.Total}+{Query9Stats:$.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\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) 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\": \"querytext4\"\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\": \"query4\"\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.\"\n },\n \"name\": \"querytext5\"\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\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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.\"\n },\n \"name\": \"querytext6\"\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\": \"query6\"\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\": \"querytext7\"\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\": \"query7\"\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\": \"querytext8\"\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\": \"query8\"\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\": \"querytext9\"\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\": \"query9\"\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\": \"Query12Stats\",\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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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/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\": \"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\": \"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\": \"{Query12Stats:$.Success}+{Query13Stats:$.Success}+{Query14Stats:$.Success}+{Query15Stats:$.Success}+{Query16Stats:$.Success}+{Query17Stats:$.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\": \"{Query12Stats:$.Total}+{Query13Stats:$.Total}+{Query14Stats:$.Total}+{Query15Stats:$.Total}+{Query16Stats:$.Total}+{Query17Stats:$.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\": \"## Internet\"\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 Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information.\"\n },\n \"name\": \"querytext12\"\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\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext13\"\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\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext14\"\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\": \"query14\"\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) for further information.\"\n },\n \"name\": \"querytext15\"\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\": \"query15\"\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.\"\n },\n \"name\": \"querytext16\"\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\": \"query16\"\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\": \"querytext17\"\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\": \"query17\"\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\": \"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\": \"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\": \"{Query0Stats:$.Success}+{Query1Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.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\": \"{Query0Stats:$.Total}+{Query1Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.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\": \"## Hub and spoke\"\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\": \"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.\"\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\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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.\"\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\": \"Consider the limit of routes per route table (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.\"\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.\"\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 },\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\": \"Query19Stats\",\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\": \"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/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\": \"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/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\": \"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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg)| 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\": \"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\": \"{Query19Stats:$.Success}+{Query20Stats:$.Success}+{Query21Stats:$.Success}+{Query22Stats:$.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\": \"{Query19Stats:$.Total}+{Query20Stats:$.Total}+{Query21Stats:$.Total}+{Query22Stats:$.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\": \"## Segmentation\"\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 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.\"\n },\n \"name\": \"querytext19\"\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\": \"query19\"\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\": \"querytext20\"\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\": \"query20\"\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\": \"querytext21\"\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\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) 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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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 },\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\": \"Query10Stats\",\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\": \"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/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\": \"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\": \"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\": \"{Query10Stats:$.Success}+{Query11Stats:$.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\": \"{Query10Stats:$.Total}+{Query11Stats:$.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\": \"querytext10\"\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\": \"query10\"\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\": \"querytext11\"\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\": \"query11\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\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 f5319f09d..31606ed67 100644 --- a/workbooks/alz_checklist.en_network_workbook.json +++ b/workbooks/alz_checklist.en_network_workbook.json @@ -70,43 +70,43 @@ "style": "tabs", "links": [ { - "id": "88960169-4e71-4469-bb9f-7fe506dcc995", + "id": "081f3d57-3bc2-4f33-8742-1e932f031913", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Internet", + "linkLabel": "Hub and spoke", "subTarget": "tab0", - "preText": "Internet", + "preText": "Hub and spoke", "style": "primary" }, { - "id": "bd47742a-bc2a-4fff-9a20-fe9bd6fcc48a", + "id": "24c0b94a-bf12-45a5-bb10-73b50835225a", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "IP plan", + "linkLabel": "PaaS", "subTarget": "tab1", - "preText": "IP plan", + "preText": "PaaS", "style": "primary" }, { - "id": "4459248d-85c5-4a68-be0b-6eafb7a1465f", + "id": "36297861-96c4-4393-a4c1-54ce3121f843", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Virtual WAN", + "linkLabel": "Internet", "subTarget": "tab2", - "preText": "Virtual WAN", + "preText": "Internet", "style": "primary" }, { - "id": "252e8c43-5445-4d49-87cb-5f13c83341ce", + "id": "a1e106ad-57c7-41e3-a977-741dea3c5670", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hybrid", + "linkLabel": "IP plan", "subTarget": "tab3", - "preText": "Hybrid", + "preText": "IP plan", "style": "primary" }, { - "id": "9a063e90-4430-49a2-80c4-122bf5676aa1", + "id": "3825edc7-7e68-48e4-9397-131ba188013a", "cellValue": "VisibleTab", "linkTarget": "parameter", "linkLabel": "Segmentation", @@ -115,21 +115,21 @@ "style": "primary" }, { - "id": "75c1ad0d-db2b-4790-b07b-5d23227bf0d1", + "id": "d5c3f2f6-303f-4a8e-bacf-131e19c1f7b0", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Hub and spoke", + "linkLabel": "Virtual WAN", "subTarget": "tab5", - "preText": "Hub and spoke", + "preText": "Virtual WAN", "style": "primary" }, { - "id": "e0a39b3d-70a4-4ac9-8ed5-18897f323044", + "id": "6e188e69-7e5c-4bbb-8f47-32767258825d", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "PaaS", + "linkLabel": "Hybrid", "subTarget": "tab6", - "preText": "PaaS", + "preText": "Hybrid", "style": "primary" } ] @@ -145,22 +145,22 @@ { "type": 1, "content": { - "json": "## Internet" + "json": "## Hub and spoke" }, "name": "tab0title" }, { "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." + "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." }, - "name": "querytext12" + "name": "querytext0" }, { "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' | 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", @@ -209,20 +209,20 @@ ] } }, - "name": "query12" + "name": "query0" }, { "type": 1, "content": { - "json": "Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." + "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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." }, - "name": "querytext13" + "name": "querytext1" }, { "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' | 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", @@ -271,20 +271,20 @@ ] } }, - "name": "query13" + "name": "query1" }, { "type": 1, "content": { - "json": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." + "json": "Consider the limit of routes per route table (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." }, - "name": "querytext14" + "name": "querytext2" }, { "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/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", @@ -333,20 +333,20 @@ ] } }, - "name": "query14" + "name": "query2" }, { "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) for further information." + "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." }, - "name": "querytext15" + "name": "querytext3" }, { "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/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", @@ -395,20 +395,42 @@ ] } }, - "name": "query15" + "name": "query3" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab0" + }, + "name": "tab0" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## PaaS" + }, + "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." + "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) can help to educate yourself on this." }, - "name": "querytext16" + "name": "querytext18" }, { "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,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", @@ -457,20 +479,42 @@ ] } }, - "name": "query16" + "name": "query18" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab1" + }, + "name": "tab1" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Internet" + }, + "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": "Use Azure Bastion in a subnet /26 or larger. Check [this link](https://learn.microsoft.com/azure/bastion/bastion-faq#subnet) for further information." }, - "name": "querytext17" + "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/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", @@ -519,42 +563,20 @@ ] } }, - "name": "query17" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab0" - }, - "name": "tab0" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## IP plan" - }, - "name": "tab1title" + "name": "query12" }, { "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 FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information." }, - "name": "querytext10" + "name": "querytext13" }, { "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.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", @@ -603,20 +625,20 @@ ] } }, - "name": "query10" + "name": "query13" }, { "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": "Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information." }, - "name": "querytext11" + "name": "querytext14" }, { "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.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", @@ -665,42 +687,20 @@ ] } }, - "name": "query11" - } - ] - }, - "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": "query14" }, { "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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-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) for further information." }, - "name": "querytext23" + "name": "querytext15" }, { "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/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", @@ -749,42 +749,20 @@ ] } }, - "name": "query23" - } - ] - }, - "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" + "name": "query15" }, { "type": 1, "content": { - "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) 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." }, - "name": "querytext4" + "name": "querytext16" }, { "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' | 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", @@ -833,20 +811,20 @@ ] } }, - "name": "query4" + "name": "query16" }, { "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." + "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": "querytext5" + "name": "querytext17" }, { "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' | 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", @@ -895,20 +873,42 @@ ] } }, - "name": "query5" + "name": "query17" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab2" + }, + "name": "tab2" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## IP plan" + }, + "name": "tab3title" }, { "type": 1, "content": { - "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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." + "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": "querytext6" + "name": "querytext10" }, { "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/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", @@ -957,20 +957,20 @@ ] } }, - "name": "query6" + "name": "query10" }, { "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": "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": "querytext7" + "name": "querytext11" }, { "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 | 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", @@ -1019,20 +1019,42 @@ ] } }, - "name": "query7" + "name": "query11" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab3" + }, + "name": "tab3" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Segmentation" + }, + "name": "tab4title" }, { "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": "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." }, - "name": "querytext8" + "name": "querytext19" }, { "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' | 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", @@ -1081,20 +1103,20 @@ ] } }, - "name": "query8" + "name": "query19" }, { "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 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": "querytext9" + "name": "querytext20" }, { "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 == '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", @@ -1143,42 +1165,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": "## Segmentation" - }, - "name": "tab4title" + "name": "query20" }, { "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." + "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": "querytext19" + "name": "querytext21" }, { "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/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", @@ -1227,20 +1227,20 @@ ] } }, - "name": "query19" + "name": "query21" }, { "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": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." }, - "name": "querytext20" + "name": "querytext22" }, { "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/virtualnetworks' | project id,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 0, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1289,20 +1289,42 @@ ] } }, - "name": "query20" + "name": "query22" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab4" + }, + "name": "tab4" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Virtual WAN" + }, + "name": "tab5title" }, { "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": "For outbound Internet traffic protection and filtering, deploy Azure Firewall in secured hubs. Check [this link](https://learn.microsoft.com/azure/virtual-wan/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) can help to educate yourself on this." }, - "name": "querytext21" + "name": "querytext23" }, { "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/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", @@ -1351,20 +1373,42 @@ ] } }, - "name": "query21" + "name": "query23" + } + ] + }, + "conditionalVisibility": { + "parameterName": "VisibleTab", + "comparison": "isEqualTo", + "value": "tab5" + }, + "name": "tab5" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "items": [ + { + "type": 1, + "content": { + "json": "## Hybrid" + }, + "name": "tab6title" }, { "type": 1, "content": { - "json": "The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) can help to educate yourself on this." + "json": "Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) for further information.. [This training](https://learn.microsoft.com/learn/modules/design-implement-azure-expressroute/) can help to educate yourself on this." }, - "name": "querytext22" + "name": "querytext4" }, { "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,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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", @@ -1413,42 +1457,20 @@ ] } }, - "name": "query22" - } - ] - }, - "conditionalVisibility": { - "parameterName": "VisibleTab", - "comparison": "isEqualTo", - "value": "tab4" - }, - "name": "tab4" - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 1, - "content": { - "json": "## Hub and spoke" - }, - "name": "tab5title" + "name": "query4" }, { "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." + "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." }, - "name": "querytext0" + "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 == '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/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", @@ -1497,20 +1519,20 @@ ] } }, - "name": "query0" + "name": "query5" }, { "type": 1, "content": { - "json": "When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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." + "json": "Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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." }, - "name": "querytext1" + "name": "querytext6" }, { "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/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", @@ -1559,20 +1581,20 @@ ] } }, - "name": "query1" + "name": "query6" }, { "type": 1, "content": { - "json": "Consider the limit of routes per route table (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." + "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": "querytext2" + "name": "querytext7" }, { "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/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", @@ -1621,20 +1643,20 @@ ] } }, - "name": "query2" + "name": "query7" }, { "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." + "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": "querytext3" + "name": "querytext8" }, { "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/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", @@ -1683,42 +1705,20 @@ ] } }, - "name": "query3" - } - ] - }, - "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" + "name": "query8" }, { "type": 1, "content": { - "json": "Don't enable virtual network service endpoints by default on all subnets. Check [this link](https://learn.microsoft.com/azure/app-service/networking-features) for further information.. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/?source=learn) 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": "querytext18" + "name": "querytext9" }, { "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,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", @@ -1767,7 +1767,7 @@ ] } }, - "name": "query18" + "name": "query9" } ] }, diff --git a/workbooks/alz_checklist.en_network_workbook_template.json b/workbooks/alz_checklist.en_network_workbook_template.json index b513bdeba..977c554d8 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\": \"88960169-4e71-4469-bb9f-7fe506dcc995\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"bd47742a-bc2a-4fff-9a20-fe9bd6fcc48a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab1\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"4459248d-85c5-4a68-be0b-6eafb7a1465f\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"252e8c43-5445-4d49-87cb-5f13c83341ce\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab3\",\n \"preText\": \"Hybrid\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"9a063e90-4430-49a2-80c4-122bf5676aa1\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"75c1ad0d-db2b-4790-b07b-5d23227bf0d1\",\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\": \"e0a39b3d-70a4-4ac9-8ed5-18897f323044\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab6\",\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\": 1,\n \"content\": {\n \"json\": \"## Internet\"\n },\n \"name\": \"tab0title\"\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.\"\n },\n \"name\": \"querytext12\"\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\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext13\"\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\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext14\"\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\": \"query14\"\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) for further information.\"\n },\n \"name\": \"querytext15\"\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\": \"query15\"\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.\"\n },\n \"name\": \"querytext16\"\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\": \"query16\"\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\": \"querytext17\"\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\": \"query17\"\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\": \"## IP plan\"\n },\n \"name\": \"tab1title\"\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\": \"querytext10\"\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\": \"query10\"\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\": \"querytext11\"\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\": \"query11\"\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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) 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/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\": \"query23\"\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\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) 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\": \"querytext4\"\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\": \"query4\"\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.\"\n },\n \"name\": \"querytext5\"\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\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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.\"\n },\n \"name\": \"querytext6\"\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\": \"query6\"\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\": \"querytext7\"\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\": \"query7\"\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\": \"querytext8\"\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\": \"query8\"\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\": \"querytext9\"\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\": \"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\": \"## Segmentation\"\n },\n \"name\": \"tab4title\"\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.\"\n },\n \"name\": \"querytext19\"\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\": \"query19\"\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\": \"querytext20\"\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\": \"query20\"\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\": \"querytext21\"\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\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) 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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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 },\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\": \"## Hub and spoke\"\n },\n \"name\": \"tab5title\"\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.\"\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\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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.\"\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\": \"Consider the limit of routes per route table (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.\"\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.\"\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 },\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/app-service/networking-features) 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\": \"querytext18\"\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\": \"query18\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\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\": \"081f3d57-3bc2-4f33-8742-1e932f031913\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hub and spoke\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Hub and spoke\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"24c0b94a-bf12-45a5-bb10-73b50835225a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"PaaS\",\n \"subTarget\": \"tab1\",\n \"preText\": \"PaaS\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"36297861-96c4-4393-a4c1-54ce3121f843\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Internet\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Internet\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"a1e106ad-57c7-41e3-a977-741dea3c5670\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"IP plan\",\n \"subTarget\": \"tab3\",\n \"preText\": \"IP plan\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"3825edc7-7e68-48e4-9397-131ba188013a\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Segmentation\",\n \"subTarget\": \"tab4\",\n \"preText\": \"Segmentation\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"d5c3f2f6-303f-4a8e-bacf-131e19c1f7b0\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Virtual WAN\",\n \"subTarget\": \"tab5\",\n \"preText\": \"Virtual WAN\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"6e188e69-7e5c-4bbb-8f47-32767258825d\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Hybrid\",\n \"subTarget\": \"tab6\",\n \"preText\": \"Hybrid\",\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\": \"## Hub and spoke\"\n },\n \"name\": \"tab0title\"\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.\"\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\": \"When connecting spoke virtual networks to the central hub virtual network, consider VNet peering limits (500), 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.\"\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\": \"Consider the limit of routes per route table (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.\"\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.\"\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 },\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/app-service/networking-features) 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\": \"querytext18\"\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\": \"query18\"\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\": \"## Internet\"\n },\n \"name\": \"tab2title\"\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.\"\n },\n \"name\": \"querytext12\"\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\": \"query12\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use FQDN-based network rules and Azure Firewall with DNS proxy to filter egress traffic to the Internet over protocols not supported by application rules. Check [this link](https://learn.microsoft.com/azure/firewall/fqdn-filtering-network-rules) for further information.\"\n },\n \"name\": \"querytext13\"\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\": \"query13\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Use Azure Firewall Premium for additional security and protection. Check [this link](https://learn.microsoft.com/azure/firewall/premium-features) for further information.\"\n },\n \"name\": \"querytext14\"\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\": \"query14\"\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) for further information.\"\n },\n \"name\": \"querytext15\"\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\": \"query15\"\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.\"\n },\n \"name\": \"querytext16\"\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\": \"query16\"\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\": \"querytext17\"\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\": \"query17\"\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\": \"## IP plan\"\n },\n \"name\": \"tab3title\"\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\": \"querytext10\"\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\": \"query10\"\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\": \"querytext11\"\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\": \"query11\"\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\": \"## Segmentation\"\n },\n \"name\": \"tab4title\"\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.\"\n },\n \"name\": \"querytext19\"\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\": \"query19\"\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\": \"querytext20\"\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\": \"query20\"\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\": \"querytext21\"\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\": \"query21\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"The application team should use application security groups at the subnet-level NSGs to help protect multi-tier VMs within the landing zone. [This training](https://learn.microsoft.com/learn/paths/implement-network-security/) 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,resourceGroup,name,subnets=properties.subnets | mv-expand subnets | project id,name,subnetName=subnets.name,subnetNsg=subnets.properties.networkSecurityGroup | where not (subnetName in ('GatewaySubnet', 'AzureFirewallSubnet', 'RouteServerSubnet', 'AzureBastionSubnet')) | extend compliant = isnotnull(subnetNsg) | 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 },\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\": \"## Virtual WAN\"\n },\n \"name\": \"tab5title\"\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/virtual-wan-about) for further information.. [This training](https://learn.microsoft.com/learn/paths/secure-networking-infrastructure/) 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/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\": \"query23\"\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\": \"## Hybrid\"\n },\n \"name\": \"tab6title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Ensure that you're using the right SKU for the ExpressRoute/VPN gateways based on bandwidth and performance requirements. Check [this link](https://learn.microsoft.com/azure/expressroute/expressroute-routing) 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\": \"querytext4\"\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\": \"query4\"\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.\"\n },\n \"name\": \"querytext5\"\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\": \"query5\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Leverage the Local SKU of ExpressRoute to reduce the cost of your circuits, if your circuits' 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.\"\n },\n \"name\": \"querytext6\"\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\": \"query6\"\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\": \"querytext7\"\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\": \"query7\"\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\": \"querytext8\"\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\": \"query8\"\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\": \"querytext9\"\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\": \"query9\"\n }\n ]\n },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab6\"\n },\n \"name\": \"tab6\"\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_template.json b/workbooks/appdelivery_checklist.en_network_counters_workbook_template.json index 3a015b083..a20d2357e 100644 --- a/workbooks/appdelivery_checklist.en_network_counters_workbook_template.json +++ b/workbooks/appdelivery_checklist.en_network_counters_workbook_template.json @@ -357,7 +357,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query9Stats:$.Success}" + "resultVal": "{Query1Stats:$.Success}+{Query8Stats:$.Success}" } } ] @@ -376,7 +376,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query9Stats:$.Total}" + "resultVal": "{Query1Stats:$.Total}+{Query8Stats:$.Total}" } } ] @@ -414,7 +414,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query1Stats:$.Success}+{Query8Stats:$.Success}" + "resultVal": "{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}" } } ] @@ -433,7 +433,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query1Stats:$.Total}+{Query8Stats:$.Total}" + "resultVal": "{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}" } } ] @@ -471,7 +471,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}" + "resultVal": "{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query9Stats:$.Success}" } } ] @@ -490,7 +490,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}" + "resultVal": "{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query9Stats:$.Total}" } } ] @@ -528,7 +528,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query9Stats:$.Total}+{Query1Stats:$.Total}+{Query8Stats:$.Total}+{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}" + "resultVal": "{Query1Stats:$.Total}+{Query8Stats:$.Total}+{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query9Stats:$.Total}" } } ] @@ -547,7 +547,7 @@ "criteriaContext": { "operator": "Default", "resultValType": "expression", - "resultVal": "{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query9Stats:$.Success}+{Query1Stats:$.Success}+{Query8Stats:$.Success}+{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}" + "resultVal": "{Query1Stats:$.Success}+{Query8Stats:$.Success}+{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query9Stats:$.Success}" } } ] @@ -621,30 +621,30 @@ "style": "tabs", "links": [ { - "id": "5f628b8a-893d-4df9-bdc9-d141576347f1", + "id": "cf0b3103-4467-409c-a9d1-02072d5af267", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Front Door ({Tab0Success:value}/{Tab0Total:value})", + "linkLabel": "Load Balancer ({Tab0Success:value}/{Tab0Total:value})", "subTarget": "tab0", - "preText": "Front Door", + "preText": "Load Balancer", "style": "primary" }, { - "id": "15539446-d759-42b0-8a9e-161bdb3129d8", + "id": "d4cf26ae-3ea8-4eac-a410-aecf04df6466", "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" }, { - "id": "476014fd-446e-439b-8b70-0eb6d1f54411", + "id": "6886f8f6-7dfc-4cdd-bf92-1451454b3cec", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "App Gateway ({Tab2Success:value}/{Tab2Total:value})", + "linkLabel": "Front Door ({Tab2Success:value}/{Tab2Total:value})", "subTarget": "tab2", - "preText": "App Gateway", + "preText": "Front Door", "style": "primary" } ] @@ -660,22 +660,22 @@ { "type": 1, "content": { - "json": "## Front Door" + "json": "## Load Balancer" }, "name": "tab0title" }, { "type": 1, "content": { - "json": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." + "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": "querytext5" + "name": "querytext1" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "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 | 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", @@ -724,20 +724,20 @@ ] } }, - "name": "query5" + "name": "query1" }, { "type": 1, "content": { - "json": "Disable health probes when there is only one origin in an Azure Front Door origin group. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group) for further information." + "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": "querytext6" + "name": "querytext8" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "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 | 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", @@ -786,20 +786,42 @@ ] } }, - "name": "query6" + "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": "## App Gateway" + }, + "name": "tab1title" }, { "type": 1, "content": { - "json": "Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes) for further information." + "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": "querytext7" + "name": "querytext0" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "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 | 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", @@ -848,20 +870,20 @@ ] } }, - "name": "query7" + "name": "query0" }, { "type": 1, "content": { - "json": "Use managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates) for further information." + "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": "querytext9" + "name": "querytext2" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "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 | 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", @@ -910,42 +932,20 @@ ] } }, - "name": "query9" - } - ] - }, - "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": "query2" }, { "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": "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": "querytext1" + "name": "querytext3" }, { "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/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", @@ -994,20 +994,20 @@ ] } }, - "name": "query1" + "name": "query3" }, { "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": "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": "querytext8" + "name": "querytext4" }, { "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 = (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", @@ -1056,7 +1056,7 @@ ] } }, - "name": "query8" + "name": "query4" } ] }, @@ -1076,22 +1076,22 @@ { "type": 1, "content": { - "json": "## App Gateway" + "json": "## Front Door" }, "name": "tab2title" }, { "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": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." }, - "name": "querytext0" + "name": "querytext5" }, { "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/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 | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1140,20 +1140,20 @@ ] } }, - "name": "query0" + "name": "query5" }, { "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": "Disable health probes when there is only one origin in an Azure Front Door origin group. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group) for further information." }, - "name": "querytext2" + "name": "querytext6" }, { "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": "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 | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1202,20 +1202,20 @@ ] } }, - "name": "query2" + "name": "query6" }, { "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": "Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes) for further information." }, - "name": "querytext3" + "name": "querytext7" }, { "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": "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 | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1264,20 +1264,20 @@ ] } }, - "name": "query3" + "name": "query7" }, { "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": "Use managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates) for further information." }, - "name": "querytext4" + "name": "querytext9" }, { "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": "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 | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -1326,7 +1326,7 @@ ] } }, - "name": "query4" + "name": "query9" } ] }, diff --git a/workbooks/appdelivery_checklist.en_network_counters_workbook_template_template.json b/workbooks/appdelivery_checklist.en_network_counters_workbook_template_template.json index be61bdea7..a3db7610e 100644 --- a/workbooks/appdelivery_checklist.en_network_counters_workbook_template_template.json +++ b/workbooks/appdelivery_checklist.en_network_counters_workbook_template_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/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| 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\": \"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| 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\": \"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| 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/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\": \"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\": \"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| 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\": \"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\": \"{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query9Stats:$.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\": \"{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query9Stats:$.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}+{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\": \"{Query1Stats:$.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\": \"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\": \"{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.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\": \"{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.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\": \"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\": \"{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query9Stats:$.Total}+{Query1Stats:$.Total}+{Query8Stats:$.Total}+{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.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\": \"{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query9Stats:$.Success}+{Query1Stats:$.Success}+{Query8Stats:$.Success}+{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.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\": \"5f628b8a-893d-4df9-bdc9-d141576347f1\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Front Door ({Tab0Success:value}/{Tab0Total:value})\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Front Door\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"15539446-d759-42b0-8a9e-161bdb3129d8\",\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 \"id\": \"476014fd-446e-439b-8b70-0eb6d1f54411\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App Gateway ({Tab2Success:value}/{Tab2Total:value})\",\n \"subTarget\": \"tab2\",\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\": \"## Front Door\"\n },\n \"name\": \"tab0title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) 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/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 | 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 \"type\": 1,\n \"content\": {\n \"json\": \"Disable health probes when there is only one origin in an Azure Front Door origin group. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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\": \"Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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 managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates) for further information.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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\": \"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\": \"querytext8\"\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\": \"query8\"\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\": \"## App Gateway\"\n },\n \"name\": \"tab2title\"\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 },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\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/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| 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\": \"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| 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\": \"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| 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/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\": \"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\": \"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| 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\": \"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}+{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\": \"{Query1Stats:$.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\": \"{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.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}\"\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\": \"{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query9Stats:$.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\": \"{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query9Stats:$.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\": \"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}+{Query8Stats:$.Total}+{Query0Stats:$.Total}+{Query2Stats:$.Total}+{Query3Stats:$.Total}+{Query4Stats:$.Total}+{Query5Stats:$.Total}+{Query6Stats:$.Total}+{Query7Stats:$.Total}+{Query9Stats:$.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}+{Query8Stats:$.Success}+{Query0Stats:$.Success}+{Query2Stats:$.Success}+{Query3Stats:$.Success}+{Query4Stats:$.Success}+{Query5Stats:$.Success}+{Query6Stats:$.Success}+{Query7Stats:$.Success}+{Query9Stats:$.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\": \"cf0b3103-4467-409c-a9d1-02072d5af267\",\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\": \"d4cf26ae-3ea8-4eac-a410-aecf04df6466\",\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 \"id\": \"6886f8f6-7dfc-4cdd-bf92-1451454b3cec\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Front Door ({Tab2Success:value}/{Tab2Total:value})\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Front Door\",\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\": \"querytext8\"\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\": \"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\": \"## 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 },\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\": \"## Front Door\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) 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/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 | 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 \"type\": 1,\n \"content\": {\n \"json\": \"Disable health probes when there is only one origin in an Azure Front Door origin group. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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\": \"Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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 managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates) for further information.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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\": \"tab2\"\n },\n \"name\": \"tab2\"\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_template.json b/workbooks/appdelivery_checklist.en_network_workbook_template.json index 89f1c971e..209ef28d7 100644 --- a/workbooks/appdelivery_checklist.en_network_workbook_template.json +++ b/workbooks/appdelivery_checklist.en_network_workbook_template.json @@ -70,30 +70,30 @@ "style": "tabs", "links": [ { - "id": "859ab144-3622-4d05-b136-7645bc35e634", + "id": "0bc350c3-4440-4a1e-8fd6-93908d0310a4", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "App Gateway", + "linkLabel": "Load Balancer", "subTarget": "tab0", - "preText": "App Gateway", + "preText": "Load Balancer", "style": "primary" }, { - "id": "0cb15dec-00a2-4875-b24f-76ded7c35981", + "id": "8f11ce82-4b27-4aac-ba3e-259508a3bf95", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Load Balancer", + "linkLabel": "Front Door", "subTarget": "tab1", - "preText": "Load Balancer", + "preText": "Front Door", "style": "primary" }, { - "id": "d2f756b1-ce30-4266-bedb-4997d700121b", + "id": "1dc46cf5-faee-4946-9409-04d5347a4717", "cellValue": "VisibleTab", "linkTarget": "parameter", - "linkLabel": "Front Door", + "linkLabel": "App Gateway", "subTarget": "tab2", - "preText": "Front Door", + "preText": "App Gateway", "style": "primary" } ] @@ -109,22 +109,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", @@ -173,20 +173,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": "querytext8" }, { "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", @@ -235,20 +235,42 @@ ] } }, - "name": "query2" + "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": "## Front Door" + }, + "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": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." }, - "name": "querytext3" + "name": "querytext5" }, { "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/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 | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -297,20 +319,20 @@ ] } }, - "name": "query3" + "name": "query5" }, { "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": "Disable health probes when there is only one origin in an Azure Front Door origin group. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group) for further information." }, - "name": "querytext4" + "name": "querytext6" }, { "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": "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 | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -359,42 +381,20 @@ ] } }, - "name": "query4" - } - ] - }, - "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": "Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes) 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": "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 | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -443,20 +443,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": "Use managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates) for further information." }, - "name": "querytext8" + "name": "querytext9" }, { "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": "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 | extend onlyFailed = {OnlyFailed:label} | where compliant == 0 or not (onlyFailed == 1) | project-away onlyFailed", "size": 4, "queryType": 1, "resourceType": "microsoft.resourcegraph/resources", @@ -505,7 +505,7 @@ ] } }, - "name": "query8" + "name": "query9" } ] }, @@ -525,22 +525,22 @@ { "type": 1, "content": { - "json": "## Front Door" + "json": "## App Gateway" }, "name": "tab2title" }, { "type": 1, "content": { - "json": "Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) for further information." + "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": "querytext5" + "name": "querytext0" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "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 | 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", @@ -589,20 +589,20 @@ ] } }, - "name": "query5" + "name": "query0" }, { "type": 1, "content": { - "json": "Disable health probes when there is only one origin in an Azure Front Door origin group. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group) for further information." + "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": "querytext6" + "name": "querytext2" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "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 | 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", @@ -651,20 +651,20 @@ ] } }, - "name": "query6" + "name": "query2" }, { "type": 1, "content": { - "json": "Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes) 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": "querytext7" + "name": "querytext3" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "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 | 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", @@ -713,20 +713,20 @@ ] } }, - "name": "query7" + "name": "query3" }, { "type": 1, "content": { - "json": "Use managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates) 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": "querytext9" + "name": "querytext4" }, { "type": 3, "content": { "version": "KqlItem/1.0", - "query": "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 | 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", @@ -775,7 +775,7 @@ ] } }, - "name": "query9" + "name": "query4" } ] }, diff --git a/workbooks/appdelivery_checklist.en_network_workbook_template_template.json b/workbooks/appdelivery_checklist.en_network_workbook_template_template.json index a7ec43477..31ce02bba 100644 --- a/workbooks/appdelivery_checklist.en_network_workbook_template_template.json +++ b/workbooks/appdelivery_checklist.en_network_workbook_template_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\": \"859ab144-3622-4d05-b136-7645bc35e634\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App Gateway\",\n \"subTarget\": \"tab0\",\n \"preText\": \"App Gateway\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"0cb15dec-00a2-4875-b24f-76ded7c35981\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Load Balancer\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Load Balancer\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"d2f756b1-ce30-4266-bedb-4997d700121b\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Front Door\",\n \"subTarget\": \"tab2\",\n \"preText\": \"Front Door\",\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 },\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\": \"querytext8\"\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\": \"query8\"\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\": \"## Front Door\"\n },\n \"name\": \"tab2title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) 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/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 | 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 \"type\": 1,\n \"content\": {\n \"json\": \"Disable health probes when there is only one origin in an Azure Front Door origin group. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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\": \"Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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 managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates) for further information.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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\": \"tab2\"\n },\n \"name\": \"tab2\"\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\": \"0bc350c3-4440-4a1e-8fd6-93908d0310a4\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Load Balancer\",\n \"subTarget\": \"tab0\",\n \"preText\": \"Load Balancer\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"8f11ce82-4b27-4aac-ba3e-259508a3bf95\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"Front Door\",\n \"subTarget\": \"tab1\",\n \"preText\": \"Front Door\",\n \"style\": \"primary\"\n },\n {\n \"id\": \"1dc46cf5-faee-4946-9409-04d5347a4717\",\n \"cellValue\": \"VisibleTab\",\n \"linkTarget\": \"parameter\",\n \"linkLabel\": \"App Gateway\",\n \"subTarget\": \"tab2\",\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\": \"querytext8\"\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\": \"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\": \"## Front Door\"\n },\n \"name\": \"tab1title\"\n },\n {\n \"type\": 1,\n \"content\": {\n \"json\": \"Deploy your WAF profiles for Front Door in 'Prevention' mode. Check [this link](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-policy-settings) 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/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 | 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 \"type\": 1,\n \"content\": {\n \"json\": \"Disable health probes when there is only one origin in an Azure Front Door origin group. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#disable-health-probes-when-theres-only-one-origin-in-an-origin-group) for further information.\"\n },\n \"name\": \"querytext6\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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\": \"Use HEAD health probes with Azure Front Door, to reduce the traffic that Front Door sends to your application. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-head-health-probes) for further information.\"\n },\n \"name\": \"querytext7\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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 managed TLS certificates with Azure Front Door. Reduce operational cost and risk of outages due to certificate renewals. Check [this link](https://learn.microsoft.com/azure/frontdoor/best-practices#use-managed-tls-certificates) for further information.\"\n },\n \"name\": \"querytext9\"\n },\n {\n \"type\": 3,\n \"content\": {\n \"version\": \"KqlItem/1.0\",\n \"query\": \"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 | 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\": \"## App Gateway\"\n },\n \"name\": \"tab2title\"\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 },\n \"conditionalVisibility\": {\n \"parameterName\": \"VisibleTab\",\n \"comparison\": \"isEqualTo\",\n \"value\": \"tab2\"\n },\n \"name\": \"tab2\"\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')]"