diff --git a/checkov/terraform/checks/resource/azure/EventHubNamespaceZoneRedundant.py b/checkov/terraform/checks/resource/azure/EventHubNamespaceZoneRedundant.py new file mode 100644 index 00000000000..796ee4745be --- /dev/null +++ b/checkov/terraform/checks/resource/azure/EventHubNamespaceZoneRedundant.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +from checkov.common.models.enums import CheckCategories +from checkov.terraform.checks.resource.base_resource_value_check import BaseResourceValueCheck + + +class EventHubNamespaceZoneRedundant(BaseResourceValueCheck): + def __init__(self) -> None: + """ + This is a best practice as the all-active Azure Event Hubs cluster model with availability zone support provides + resiliency against grave hardware failures and even catastrophic loss of entire datacenter facilities. + If an Event Hubs namespace is created in a region with availability zones, + the outage risk is further spread across three physically separated facilities, and the service has enough + capacity reserves to instantly cope up with the complete, catastrophic loss of the entire facility. + + When a client application sends events to an Event Hubs without specifying a partition, events are automatically + distributed among partitions in the event hub. If a partition isn't available for some reason, events are + distributed among the remaining partitions. This behavior allows for the greatest amount of up time. + """ + name = "Ensure the Azure Event Hub Namespace is zone redundant" + id = "CKV_AZURE_228" + supported_resources = ("azurerm_eventhub_namespace",) + 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_redundant" + + +check = EventHubNamespaceZoneRedundant() diff --git a/tests/terraform/checks/resource/azure/example_EventHubNamespaceZoneRedundant/main.tf b/tests/terraform/checks/resource/azure/example_EventHubNamespaceZoneRedundant/main.tf new file mode 100644 index 00000000000..aa462936573 --- /dev/null +++ b/tests/terraform/checks/resource/azure/example_EventHubNamespaceZoneRedundant/main.tf @@ -0,0 +1,29 @@ +resource "azurerm_eventhub_namespace" "pass" { + name = "example-namespace" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku = "Standard" + capacity = 2 + minimum_tls_version = 1.2 + zone_redundant = true + + tags = { + environment = "Production" + } +} + +resource "azurerm_eventhub_namespace" "fail2" { + name = "eventhub-primary" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku = "Standard" +} + +resource "azurerm_eventhub_namespace" "fail" { + name = "eventhub-primary" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku = "Standard" + minimum_tls_version = "1.1" + zone_redundant = false +} \ No newline at end of file diff --git a/tests/terraform/checks/resource/azure/test_EventHubNamespaceZoneRedundant.py b/tests/terraform/checks/resource/azure/test_EventHubNamespaceZoneRedundant.py new file mode 100644 index 00000000000..0cf3805ea7b --- /dev/null +++ b/tests/terraform/checks/resource/azure/test_EventHubNamespaceZoneRedundant.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.EventHubNamespaceZoneRedundant import check + + +class TestEventHubNamespaceZoneRedundant(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_EventHubNamespaceZoneRedundant") + report = runner.run(root_folder=test_files_dir, + runner_filter=RunnerFilter(checks=[check.id])) + summary = report.get_summary() + + passing_resources = { + 'azurerm_eventhub_namespace.pass', + } + failing_resources = { + 'azurerm_eventhub_namespace.fail', + 'azurerm_eventhub_namespace.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() \ No newline at end of file