From f329694e3592d0814c1cabc1771da395eb235dac Mon Sep 17 00:00:00 2001 From: Roee Segev Date: Wed, 1 Jan 2025 17:51:42 +0200 Subject: [PATCH 1/5] add azure batch account network access validation - arm --- ...BatchAccountEndpointAccessDefaultAction.py | 46 ++++++++++++++++ .../fail.json | 19 +++++++ .../pass.json | 53 +++++++++++++++++++ ...chAccountEndpointAccessDefaultAction.py.py | 43 +++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py create mode 100644 tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/fail.json create mode 100644 tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/pass.json create mode 100644 tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py.py diff --git a/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py b/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py new file mode 100644 index 00000000000..e9ccf59bfb5 --- /dev/null +++ b/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py @@ -0,0 +1,46 @@ +from typing import Any + +from checkov.arm.base_resource_check import BaseResourceCheck +from checkov.common.models.enums import CheckCategories, CheckResult + + +class AzureBatchAccountEndpointAccessDefaultAction(BaseResourceCheck): + + FORBIDDEN_PUBLIC_NETWORK_ACCESS = "enabled" + FORBIDDEN_NETWORK_ACCESS_DEFAULT_ACTION = "allow" + + def __init__(self) -> None: + name = "Ensure that Azure Batch account public network access is 'enabled' account access default action is 'ignore'" + id = "CKV_AZURE_244" + supported_resources = ("Microsoft.Batch/batchAccounts",) + categories = [CheckCategories.ENCRYPTION] + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources,) + + @staticmethod + def _exists_and_lower_equal(actual_value: Any, expected_lowercase_value: str) -> bool: + return actual_value and str(actual_value).lower() == expected_lowercase_value + + def scan_resource_conf(self, conf: dict[str, Any]) -> CheckResult: + properties = conf.get('properties') + if not properties or not isinstance(properties, dict): + return CheckResult.FAILED + + # public network access is disabled, no need to check for account access default action + public_network_access = properties.get('publicNetworkAccess') + if not self._exists_and_lower_equal(public_network_access, self.FORBIDDEN_PUBLIC_NETWORK_ACCESS): + return CheckResult.PASSED + + network_profile = properties.get('networkProfile') + if not network_profile: + return CheckResult.PASSED + account_access = network_profile.get('accountAccess') + if not account_access: + return CheckResult.PASSED + default_action = account_access.get('defaultAction') + if not self._exists_and_lower_equal(default_action, self.FORBIDDEN_NETWORK_ACCESS_DEFAULT_ACTION): + return CheckResult.PASSED + + return CheckResult.FAILED + + +check = AzureBatchAccountEndpointAccessDefaultAction() diff --git a/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/fail.json b/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/fail.json new file mode 100644 index 00000000000..814781a5e74 --- /dev/null +++ b/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/fail.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Batch/batchAccounts", + "apiVersion": "2024-02-01", + "name": "fail", + "properties": { + "publicNetworkAccess": "Enabled", + "networkProfile": { + "accountAccess": { + "defaultAction": "Allow" + } + } + } + } + ] +} \ No newline at end of file diff --git a/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/pass.json b/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/pass.json new file mode 100644 index 00000000000..500eaed86b9 --- /dev/null +++ b/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/pass.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Batch/batchAccounts", + "apiVersion": "2024-02-01", + "name": "pass_no_publicNetworkAccess", + "properties": { + } + }, + { + "type": "Microsoft.Batch/batchAccounts", + "apiVersion": "2024-02-01", + "name": "pass_publicNetworkAccess_disabled", + "properties": { + "publicNetworkAccess": "Disabled" + } + }, + { + "type": "Microsoft.Batch/batchAccounts", + "apiVersion": "2024-02-01", + "name": "pass_publicNetworkAccess_enabled_no_network_profile", + "properties": { + "publicNetworkAccess": "Enabled" + } + }, + { + "type": "Microsoft.Batch/batchAccounts", + "apiVersion": "2024-02-01", + "name": "pass_publicNetworkAccess_enabled_no_account_access", + "properties": { + "publicNetworkAccess": "Enabled", + "networkProfile": { + + } + } + }, + { + "type": "Microsoft.Batch/batchAccounts", + "apiVersion": "2024-02-01", + "name": "pass_publicNetworkAccess_enabled_default_action_deny", + "properties": { + "publicNetworkAccess": "Enabled", + "networkProfile": { + "accountAccess": { + "defaultAction": "Deny" + } + } + } + } + ] +} \ No newline at end of file diff --git a/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py.py b/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py.py new file mode 100644 index 00000000000..b6236bfacd5 --- /dev/null +++ b/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py.py @@ -0,0 +1,43 @@ +import unittest +from pathlib import Path +from checkov.arm.checks.resource.AzureBatchAccountEndpointAccessDefaultAction import check +from checkov.arm.runner import Runner +from checkov.runner_filter import RunnerFilter + + +class TestAzureBatchAccountEndpointAccessDefaultAction(unittest.TestCase): + def test_summary(self): + # given + test_files_dir = Path(__file__).parent / "example_AzureBatchAccountEndpointAccessDefaultAction.py" + + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) + + # then + summary = report.get_summary() + + passing_resources = { + "Microsoft.Batch/batchAccounts.pass_no_publicNetworkAccess", + "Microsoft.Batch/batchAccounts.pass_publicNetworkAccess_disabled", + "Microsoft.Batch/batchAccounts.pass_publicNetworkAccess_enabled_no_network_profile", + "Microsoft.Batch/batchAccounts.pass_publicNetworkAccess_enabled_no_account_access", + "Microsoft.Batch/batchAccounts.pass_publicNetworkAccess_enabled_default_action_deny", + } + failing_resources = { + "Microsoft.Batch/batchAccounts.fail", + } + + passed_check_resources = {c.resource for c in report.passed_checks} + failed_check_resources = {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"], 0) + 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() From a96743b3506a15360ced2ccfa01164bb2d31c67f Mon Sep 17 00:00:00 2001 From: Roee Segev Date: Thu, 2 Jan 2025 11:50:19 +0200 Subject: [PATCH 2/5] add azure batch account network access validation - terraform --- ...BatchAccountEndpointAccessDefaultAction.py | 2 +- ...BatchAccountEndpointAccessDefaultAction.py | 36 +++++++++++ ...atchAccountEndpointAccessDefaultAction.py} | 0 .../main.tf | 60 +++++++++++++++++++ ...BatchAccountEndpointAccessDefaultAction.py | 46 ++++++++++++++ 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py rename tests/arm/checks/resource/{test_AzureBatchAccountEndpointAccessDefaultAction.py.py => test_AzureBatchAccountEndpointAccessDefaultAction.py} (100%) create mode 100644 tests/terraform/checks/resource/azure/example_AzureBatchAccountEndpointAccessDefaultAction/main.tf create mode 100644 tests/terraform/checks/resource/azure/test_AzureBatchAccountEndpointAccessDefaultAction.py diff --git a/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py b/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py index e9ccf59bfb5..920b3a3a206 100644 --- a/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py +++ b/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py @@ -13,7 +13,7 @@ def __init__(self) -> None: name = "Ensure that Azure Batch account public network access is 'enabled' account access default action is 'ignore'" id = "CKV_AZURE_244" supported_resources = ("Microsoft.Batch/batchAccounts",) - categories = [CheckCategories.ENCRYPTION] + categories = [CheckCategories.NETWORKING] super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources,) @staticmethod diff --git a/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py b/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py new file mode 100644 index 00000000000..22a09111e76 --- /dev/null +++ b/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py @@ -0,0 +1,36 @@ +from typing import Any + +from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck +from checkov.common.models.enums import CheckCategories, CheckResult + + +class AzureBatchAccountEndpointAccessDefaultAction(BaseResourceCheck): + + def __init__(self) -> None: + name = "Ensure that Azure Batch account public network access is 'enabled' account access default action is 'ignore'" + id = "CKV_AZURE_244" + supported_resources = ("azurerm_batch_account",) + categories = [CheckCategories.NETWORKING] + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources,) + + def scan_resource_conf(self, conf: dict[str, Any]) -> CheckResult: + + # public network access is disabled, no need to check for account access default action + public_network_access = conf.get('public_network_access_enabled', [None])[0] + if not public_network_access: + return CheckResult.PASSED + + network_profile: dict[str, Any] | None = conf.get('network_profile', [None])[0] + if not network_profile: + return CheckResult.PASSED + account_access: dict[str, Any] | None = network_profile.get('account_access', [None])[0] + if not account_access: + return CheckResult.PASSED + default_action: str | None = account_access.get('default_action', [None])[0] + if not default_action or str(default_action).lower() != "allow": + return CheckResult.PASSED + + return CheckResult.FAILED + + +check = AzureBatchAccountEndpointAccessDefaultAction() diff --git a/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py.py b/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py similarity index 100% rename from tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py.py rename to tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py diff --git a/tests/terraform/checks/resource/azure/example_AzureBatchAccountEndpointAccessDefaultAction/main.tf b/tests/terraform/checks/resource/azure/example_AzureBatchAccountEndpointAccessDefaultAction/main.tf new file mode 100644 index 00000000000..288343f090e --- /dev/null +++ b/tests/terraform/checks/resource/azure/example_AzureBatchAccountEndpointAccessDefaultAction/main.tf @@ -0,0 +1,60 @@ +#pass +resource "azurerm_batch_account" "pass_no_publicNetworkAccess" { + name = "testbatchaccount" + resource_group_name = "group" + location = "azurerm_resource_group.example.location" + pool_allocation_mode = "BatchService" +} + +resource "azurerm_batch_account" "pass_publicNetworkAccess_disabled" { + name = "testbatchaccount" + resource_group_name = "group" + location = "azurerm_resource_group.example.location" + pool_allocation_mode = "BatchService" + public_network_access_enabled = false +} + +resource "azurerm_batch_account" "pass_publicNetworkAccess_enabled_no_network_profile" { + name = "testbatchaccount" + resource_group_name = "group" + location = "azurerm_resource_group.example.location" + pool_allocation_mode = "BatchService" + public_network_access_enabled = true +} + +resource "azurerm_batch_account" "pass_publicNetworkAccess_enabled_no_account_access" { + name = "testbatchaccount" + resource_group_name = "group" + location = "azurerm_resource_group.example.location" + pool_allocation_mode = "BatchService" + public_network_access_enabled = true + network_profile { + + } +} + +resource "azurerm_batch_account" "pass_publicNetworkAccess_enabled_default_action_deny" { + name = "testbatchaccount" + resource_group_name = "group" + location = "azurerm_resource_group.example.location" + pool_allocation_mode = "BatchService" + public_network_access_enabled = true + network_profile { + account_access { + default_action = "deny" + } + } +} + +resource "azurerm_batch_account" "fail_publicNetworkAccess_enabled_default_action_allow" { + name = "testbatchaccount" + resource_group_name = "group" + location = "azurerm_resource_group.example.location" + pool_allocation_mode = "BatchService" + public_network_access_enabled = true + network_profile { + account_access { + default_action = "allow" + } + } +} \ No newline at end of file diff --git a/tests/terraform/checks/resource/azure/test_AzureBatchAccountEndpointAccessDefaultAction.py b/tests/terraform/checks/resource/azure/test_AzureBatchAccountEndpointAccessDefaultAction.py new file mode 100644 index 00000000000..261d9b3611b --- /dev/null +++ b/tests/terraform/checks/resource/azure/test_AzureBatchAccountEndpointAccessDefaultAction.py @@ -0,0 +1,46 @@ +import os +import unittest +from pathlib import Path + +from checkov.runner_filter import RunnerFilter +from checkov.terraform.runner import Runner +from checkov.terraform.checks.resource.azure.AzureBatchAccountEndpointAccessDefaultAction import check + + +class TestAzureBatchAccountEndpointAccessDefaultAction(unittest.TestCase): + + def test(self): + runner = Runner() + + test_files_dir = Path(__file__).parent / "example_AzureBatchAccountEndpointAccessDefaultAction" + report = runner.run(root_folder=str(test_files_dir), + runner_filter=RunnerFilter(checks=[check.id])) + summary = report.get_summary() + + passing_resources = { + 'azurerm_batch_account.pass_no_publicNetworkAccess', + 'azurerm_batch_account.pass_publicNetworkAccess_disabled', + 'azurerm_batch_account.pass_publicNetworkAccess_enabled_no_network_profile', + 'azurerm_batch_account.pass_publicNetworkAccess_enabled_no_account_access', + 'azurerm_batch_account.pass_publicNetworkAccess_enabled_default_action_deny', + + } + failing_resources = { + 'azurerm_batch_account.fail_publicNetworkAccess_enabled_default_action_allow', + } + 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 From 6e38b52ff5ed9ffd1d1fd88b8c1701e234c21205 Mon Sep 17 00:00:00 2001 From: Roee Segev Date: Thu, 2 Jan 2025 12:40:54 +0200 Subject: [PATCH 3/5] add future annotation import --- .../azure/AzureBatchAccountEndpointAccessDefaultAction.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py b/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py index 22a09111e76..918f58846df 100644 --- a/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py +++ b/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Any from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck From 46c0fe004fbfd1893e257a6d23f49ba4b8a82a28 Mon Sep 17 00:00:00 2001 From: Roee Segev Date: Thu, 2 Jan 2025 12:50:12 +0200 Subject: [PATCH 4/5] change check id --- .../resource/AzureBatchAccountEndpointAccessDefaultAction.py | 4 +++- .../azure/AzureBatchAccountEndpointAccessDefaultAction.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py b/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py index 920b3a3a206..92ac4b9157c 100644 --- a/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py +++ b/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Any from checkov.arm.base_resource_check import BaseResourceCheck @@ -11,7 +13,7 @@ class AzureBatchAccountEndpointAccessDefaultAction(BaseResourceCheck): def __init__(self) -> None: name = "Ensure that Azure Batch account public network access is 'enabled' account access default action is 'ignore'" - id = "CKV_AZURE_244" + id = "CKV_AZURE_248" supported_resources = ("Microsoft.Batch/batchAccounts",) categories = [CheckCategories.NETWORKING] super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources,) diff --git a/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py b/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py index 918f58846df..60d255956dc 100644 --- a/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py +++ b/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py @@ -10,7 +10,7 @@ class AzureBatchAccountEndpointAccessDefaultAction(BaseResourceCheck): def __init__(self) -> None: name = "Ensure that Azure Batch account public network access is 'enabled' account access default action is 'ignore'" - id = "CKV_AZURE_244" + id = "CKV_AZURE_248" supported_resources = ("azurerm_batch_account",) categories = [CheckCategories.NETWORKING] super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources,) From 96aa3a95df173dfdf68d6c7c03925973e433ae05 Mon Sep 17 00:00:00 2001 From: Roee Segev Date: Sat, 4 Jan 2025 11:47:23 +0200 Subject: [PATCH 5/5] handle publicNetworkAccess default as true | add evaluated_keys | common checks assertions function --- ...BatchAccountEndpointAccessDefaultAction.py | 9 +++-- ...BatchAccountEndpointAccessDefaultAction.py | 7 ++-- .../fail.json | 14 ++++++- .../pass.json | 2 +- ...BatchAccountEndpointAccessDefaultAction.py | 31 ++++++--------- tests/common/check_assertion_utils.py | 39 +++++++++++++++++++ .../main.tf | 12 ++++++ ...BatchAccountEndpointAccessDefaultAction.py | 16 ++------ 8 files changed, 90 insertions(+), 40 deletions(-) create mode 100644 tests/common/check_assertion_utils.py diff --git a/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py b/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py index 92ac4b9157c..628be0362e5 100644 --- a/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py +++ b/checkov/arm/checks/resource/AzureBatchAccountEndpointAccessDefaultAction.py @@ -8,11 +8,11 @@ class AzureBatchAccountEndpointAccessDefaultAction(BaseResourceCheck): - FORBIDDEN_PUBLIC_NETWORK_ACCESS = "enabled" + DISABLED_PUBLIC_NETWORK_ACCESS = "disabled" FORBIDDEN_NETWORK_ACCESS_DEFAULT_ACTION = "allow" def __init__(self) -> None: - name = "Ensure that Azure Batch account public network access is 'enabled' account access default action is 'ignore'" + name = "Ensure that if Azure Batch account public network access in case 'enabled' then its account access must be 'deny'" id = "CKV_AZURE_248" supported_resources = ("Microsoft.Batch/batchAccounts",) categories = [CheckCategories.NETWORKING] @@ -27,9 +27,9 @@ def scan_resource_conf(self, conf: dict[str, Any]) -> CheckResult: if not properties or not isinstance(properties, dict): return CheckResult.FAILED - # public network access is disabled, no need to check for account access default action public_network_access = properties.get('publicNetworkAccess') - if not self._exists_and_lower_equal(public_network_access, self.FORBIDDEN_PUBLIC_NETWORK_ACCESS): + # public network access is disabled, no need to check for account access default action + if self._exists_and_lower_equal(public_network_access, self.DISABLED_PUBLIC_NETWORK_ACCESS): return CheckResult.PASSED network_profile = properties.get('networkProfile') @@ -42,6 +42,7 @@ def scan_resource_conf(self, conf: dict[str, Any]) -> CheckResult: if not self._exists_and_lower_equal(default_action, self.FORBIDDEN_NETWORK_ACCESS_DEFAULT_ACTION): return CheckResult.PASSED + self.evaluated_keys = ["properties/networkProfile/accountAccess/defaultAction"] return CheckResult.FAILED diff --git a/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py b/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py index 60d255956dc..b036207eb1f 100644 --- a/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py +++ b/checkov/terraform/checks/resource/azure/AzureBatchAccountEndpointAccessDefaultAction.py @@ -9,7 +9,7 @@ class AzureBatchAccountEndpointAccessDefaultAction(BaseResourceCheck): def __init__(self) -> None: - name = "Ensure that Azure Batch account public network access is 'enabled' account access default action is 'ignore'" + name = "Ensure that if Azure Batch account public network access in case 'enabled' then its account access must be 'deny'" id = "CKV_AZURE_248" supported_resources = ("azurerm_batch_account",) categories = [CheckCategories.NETWORKING] @@ -17,9 +17,9 @@ def __init__(self) -> None: def scan_resource_conf(self, conf: dict[str, Any]) -> CheckResult: - # public network access is disabled, no need to check for account access default action public_network_access = conf.get('public_network_access_enabled', [None])[0] - if not public_network_access: + # public network access is disabled, no need to check for account access default action + if public_network_access is False: return CheckResult.PASSED network_profile: dict[str, Any] | None = conf.get('network_profile', [None])[0] @@ -32,6 +32,7 @@ def scan_resource_conf(self, conf: dict[str, Any]) -> CheckResult: if not default_action or str(default_action).lower() != "allow": return CheckResult.PASSED + self.evaluated_keys = ["network_profile/[0]/account_access/[0]/default_action"] return CheckResult.FAILED diff --git a/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/fail.json b/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/fail.json index 814781a5e74..57e3a36b4db 100644 --- a/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/fail.json +++ b/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/fail.json @@ -5,7 +5,7 @@ { "type": "Microsoft.Batch/batchAccounts", "apiVersion": "2024-02-01", - "name": "fail", + "name": "fail_explicit_publicNetworkAccess", "properties": { "publicNetworkAccess": "Enabled", "networkProfile": { @@ -14,6 +14,18 @@ } } } + }, + { + "type": "Microsoft.Batch/batchAccounts", + "apiVersion": "2024-02-01", + "name": "fail_default_publicNetworkAccess", + "properties": { + "networkProfile": { + "accountAccess": { + "defaultAction": "Allow" + } + } + } } ] } \ No newline at end of file diff --git a/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/pass.json b/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/pass.json index 500eaed86b9..e09bc81d125 100644 --- a/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/pass.json +++ b/tests/arm/checks/resource/example_AzureBatchAccountEndpointAccessDefaultAction.py/pass.json @@ -5,7 +5,7 @@ { "type": "Microsoft.Batch/batchAccounts", "apiVersion": "2024-02-01", - "name": "pass_no_publicNetworkAccess", + "name": "pass_empty", "properties": { } }, diff --git a/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py b/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py index b6236bfacd5..ac743223e6d 100644 --- a/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py +++ b/tests/arm/checks/resource/test_AzureBatchAccountEndpointAccessDefaultAction.py @@ -3,40 +3,33 @@ from checkov.arm.checks.resource.AzureBatchAccountEndpointAccessDefaultAction import check from checkov.arm.runner import Runner from checkov.runner_filter import RunnerFilter +from tests.common.check_assertion_utils import checks_report_assertions class TestAzureBatchAccountEndpointAccessDefaultAction(unittest.TestCase): def test_summary(self): - # given - test_files_dir = Path(__file__).parent / "example_AzureBatchAccountEndpointAccessDefaultAction.py" - - # when - report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) - - # then - summary = report.get_summary() - passing_resources = { - "Microsoft.Batch/batchAccounts.pass_no_publicNetworkAccess", + "Microsoft.Batch/batchAccounts.pass_empty", "Microsoft.Batch/batchAccounts.pass_publicNetworkAccess_disabled", "Microsoft.Batch/batchAccounts.pass_publicNetworkAccess_enabled_no_network_profile", "Microsoft.Batch/batchAccounts.pass_publicNetworkAccess_enabled_no_account_access", "Microsoft.Batch/batchAccounts.pass_publicNetworkAccess_enabled_default_action_deny", } failing_resources = { - "Microsoft.Batch/batchAccounts.fail", + "Microsoft.Batch/batchAccounts.fail_explicit_publicNetworkAccess": + ["properties/networkProfile/accountAccess/defaultAction"], + "Microsoft.Batch/batchAccounts.fail_default_publicNetworkAccess": + ["properties/networkProfile/accountAccess/defaultAction"], } - passed_check_resources = {c.resource for c in report.passed_checks} - failed_check_resources = {c.resource for c in report.failed_checks} + # given + test_files_dir = Path(__file__).parent / "example_AzureBatchAccountEndpointAccessDefaultAction.py" - self.assertEqual(summary["passed"], len(passing_resources)) - self.assertEqual(summary["failed"], len(failing_resources)) - self.assertEqual(summary["skipped"], 0) - self.assertEqual(summary["parsing_errors"], 0) + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) - self.assertEqual(passing_resources, passed_check_resources) - self.assertEqual(failing_resources, failed_check_resources) + # then + checks_report_assertions(self, report, passing_resources, failing_resources) if __name__ == "__main__": diff --git a/tests/common/check_assertion_utils.py b/tests/common/check_assertion_utils.py new file mode 100644 index 00000000000..28a25cfccec --- /dev/null +++ b/tests/common/check_assertion_utils.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import unittest +from typing import Union + +from checkov.common.output.report import Report + + +def checks_report_assertions(test_case: unittest.TestCase, report: Report, + expected_passing_resources: set[str], + expected_failing_resources: Union[set[str], dict[str, list[str]]], + expected_skipped_resources: set[str] = None) -> None: + """ + validates: + 1. summary field includes correct count of passing / failing / skipped resources + 2. the resource themselves match the expected resources + 3. for failing resources, there's an option to send expected as dict, in which case both the resource and the evaluated keys of that check will be validated + """ + if expected_skipped_resources is None: + expected_skipped_resources = set() + + summary = report.get_summary() + + passed_check_resources = {c.resource for c in report.passed_checks} + skipped_check_resources = {c.resource for c in report.skipped_checks} + + if isinstance(expected_failing_resources, dict): + failed_check_resources = {c.resource: c.check_result.get("evaluated_keys") for c in report.failed_checks} + else: + failed_check_resources = {c.resource for c in report.failed_checks} + + test_case.assertEqual(summary["passed"], len(expected_passing_resources)) + test_case.assertEqual(summary["failed"], len(expected_failing_resources)) + test_case.assertEqual(summary["skipped"], len(expected_skipped_resources)) + test_case.assertEqual(summary["parsing_errors"], 0) + + test_case.assertEqual(expected_passing_resources, passed_check_resources) + test_case.assertEqual(expected_failing_resources, failed_check_resources) + test_case.assertEqual(expected_skipped_resources, skipped_check_resources) \ No newline at end of file diff --git a/tests/terraform/checks/resource/azure/example_AzureBatchAccountEndpointAccessDefaultAction/main.tf b/tests/terraform/checks/resource/azure/example_AzureBatchAccountEndpointAccessDefaultAction/main.tf index 288343f090e..edccbf78e49 100644 --- a/tests/terraform/checks/resource/azure/example_AzureBatchAccountEndpointAccessDefaultAction/main.tf +++ b/tests/terraform/checks/resource/azure/example_AzureBatchAccountEndpointAccessDefaultAction/main.tf @@ -57,4 +57,16 @@ resource "azurerm_batch_account" "fail_publicNetworkAccess_enabled_default_actio default_action = "allow" } } +} + +resource "azurerm_batch_account" "fail_bad_default_action_no_public_network" { + name = "testbatchaccount" + resource_group_name = "group" + location = "azurerm_resource_group.example.location" + pool_allocation_mode = "BatchService" + network_profile { + account_access { + default_action = "allow" + } + } } \ No newline at end of file diff --git a/tests/terraform/checks/resource/azure/test_AzureBatchAccountEndpointAccessDefaultAction.py b/tests/terraform/checks/resource/azure/test_AzureBatchAccountEndpointAccessDefaultAction.py index 261d9b3611b..c60f6c4afb1 100644 --- a/tests/terraform/checks/resource/azure/test_AzureBatchAccountEndpointAccessDefaultAction.py +++ b/tests/terraform/checks/resource/azure/test_AzureBatchAccountEndpointAccessDefaultAction.py @@ -5,6 +5,7 @@ from checkov.runner_filter import RunnerFilter from checkov.terraform.runner import Runner from checkov.terraform.checks.resource.azure.AzureBatchAccountEndpointAccessDefaultAction import check +from tests.common.check_assertion_utils import checks_report_assertions class TestAzureBatchAccountEndpointAccessDefaultAction(unittest.TestCase): @@ -15,7 +16,6 @@ def test(self): test_files_dir = Path(__file__).parent / "example_AzureBatchAccountEndpointAccessDefaultAction" report = runner.run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) - summary = report.get_summary() passing_resources = { 'azurerm_batch_account.pass_no_publicNetworkAccess', @@ -27,19 +27,11 @@ def test(self): } failing_resources = { 'azurerm_batch_account.fail_publicNetworkAccess_enabled_default_action_allow', + 'azurerm_batch_account.fail_bad_default_action_no_public_network', } - 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) + # then + checks_report_assertions(self, report, passing_resources, failing_resources) if __name__ == '__main__':