Repository: bridgecrewio/checkov

Issue:
Azure App Service Plan - Ensure that the App Service Plan is zone redundant
**Describe the issue**
It seems that there are no checks to ensure that [azurerm_service_plan](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/service_plan) are deployed in a zone-redundant way.

**Examples**

````hcl
resource "azurerm_service_plan" "example" {
  name = "example"
  resource_group_name = azurerm_resource_group.example.name
  location = azurerm_resource_group.example.location
  os_type = "Linux"
  sku_name = "P1v2"
  zone_balancing_enabled = true
}
````

**Version (please complete the following information):**
N/A

**Additional context**

To enhance the resiliency and reliability of your business-critical workloads, it's recommended that you deploy your new App Service Plans with zone-redundancy. Follow the steps to [redeploy to availability zone support](https://learn.microsoft.com/en-us/azure/reliability/reliability-app-service?tabs=graph%2Ccli#create-a-resource-with-availability-zone-enabled), configure your pipelines to redeploy your WebApp on the new App Services Plan, and then use a [Blue-Green deployment](https://learn.microsoft.com/en-us/azure/spring-apps/concepts-blue-green-deployment-strategies) approach to failover to the new site.

By distributing your applications across multiple availability zones, you can ensure their continued operation even in the event of a datacenter-level failure. For more information on availability zone support in Azure App Service, see [Availability zone support](https://learn.microsoft.com/en-us/azure/reliability/reliability-app-service?tabs=graph%2Ccli#availability-zone-support).

There's no additional cost associated with enabling availability zones. Pricing for a zone redundant App Service is the same as a single zone App Service. You'll be charged based on your App Service plan SKU, the capacity you specify, and any instances you scale to based on your autoscale criteria. If you enable availability zones but specify a capacity less than three, the platform will enforce a minimum instance count of three and charge you for those three instances.



Discussion:

Resolving patch:
diff --git a/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py b/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py
new file mode 100644
--- /dev/null
+++ b/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py
@@ -0,0 +1,26 @@
+from __future__ import annotations
+
+from checkov.common.models.enums import CheckCategories
+from checkov.terraform.checks.resource.base_resource_value_check import BaseResourceValueCheck
+
+
+class AppServicePlanZoneRedundant(BaseResourceValueCheck):
+    def __init__(self) -> None:
+        """
+        To enhance the resiliency and reliability of business-critical workloads,
+        it's recommended to deploy new App Service Plans with zone-redundancy.
+
+        There's no additional cost associated with enabling availability zones.
+        Pricing for a zone redundant App Service is the same as a single zone App Service.
+        """
+        name = "Ensure the App Service Plan is zone redundant"
+        id = "CKV_AZURE_225"
+        supported_resources = ("azurerm_service_plan",)
+        categories = (CheckCategories.BACKUP_AND_RECOVERY,)
+        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
+
+    def get_inspected_key(self) -> str:
+        return "zone_balancing_enabled"
+
+
+check = AppServicePlanZoneRedundant()


Test patch:
diff --git a/tests/terraform/checks/resource/azure/example_AppServicePlanZoneRedundant/main.tf b/tests/terraform/checks/resource/azure/example_AppServicePlanZoneRedundant/main.tf
new file mode 100644
--- /dev/null
+++ b/tests/terraform/checks/resource/azure/example_AppServicePlanZoneRedundant/main.tf
@@ -0,0 +1,26 @@
+resource "azurerm_service_plan" "pass" {
+  name                   = "example"
+  resource_group_name    = azurerm_resource_group.example.name
+  location               = azurerm_resource_group.example.location
+  os_type                = "Linux"
+  sku_name               = "P1v2"
+  zone_balancing_enabled = true
+}
+
+resource "azurerm_service_plan" "fail1" {
+  name                   = "example"
+  resource_group_name    = azurerm_resource_group.example.name
+  location               = azurerm_resource_group.example.location
+  os_type                = "Linux"
+  sku_name               = "P1v2"
+  zone_balancing_enabled = false
+}
+
+
+resource "azurerm_service_plan" "fail2" {
+  name                   = "example"
+  resource_group_name    = azurerm_resource_group.example.name
+  location               = azurerm_resource_group.example.location
+  os_type                = "Linux"
+  sku_name              = "P1v2"
+}
diff --git a/tests/terraform/checks/resource/azure/test_AppServicePlanZoneRedundant.py b/tests/terraform/checks/resource/azure/test_AppServicePlanZoneRedundant.py
new file mode 100644
--- /dev/null
+++ b/tests/terraform/checks/resource/azure/test_AppServicePlanZoneRedundant.py
@@ -0,0 +1,42 @@
+import os
+import unittest
+
+from checkov.runner_filter import RunnerFilter
+from checkov.terraform.runner import Runner
+from checkov.terraform.checks.resource.azure.AppServicePlanZoneRedundant import check
+
+
+class AppServicePlanZoneRedundant(unittest.TestCase):
+
+    def test(self):
+        runner = Runner()
+        current_dir = os.path.dirname(os.path.realpath(__file__))
+
+        test_files_dir = os.path.join(current_dir, "example_AppServicePlanZoneRedundant")
+        report = runner.run(root_folder=test_files_dir,
+                            runner_filter=RunnerFilter(checks=[check.id]))
+        summary = report.get_summary()
+
+        passing_resources = {
+            'azurerm_service_plan.pass',
+        }
+        failing_resources = {
+            'azurerm_service_plan.fail1',
+            'azurerm_service_plan.fail2',
+        }
+        skipped_resources = {}
+
+        passed_check_resources = set([c.resource for c in report.passed_checks])
+        failed_check_resources = set([c.resource for c in report.failed_checks])
+
+        self.assertEqual(summary['passed'], len(passing_resources))
+        self.assertEqual(summary['failed'], len(failing_resources))
+        self.assertEqual(summary['skipped'], len(skipped_resources))
+        self.assertEqual(summary['parsing_errors'], 0)
+
+        self.assertEqual(passing_resources, passed_check_resources)
+        self.assertEqual(failing_resources, failed_check_resources)
+
+
+if __name__ == '__main__':
+    unittest.main()