From be5b9ea27bd6cb58125c6e8dde23dd7359887d62 Mon Sep 17 00:00:00 2001 From: Thomas Defise Date: Wed, 18 Oct 2023 14:57:10 +0200 Subject: [PATCH 1/4] Created check CKV_AZURE_228 --- .../AppServiceEnvironmentZoneRedundant.py | 17 ++++++++ .../main.tf | 34 +++++++++++++++ ...test_AppServiceEnvironmentZoneRedundant.py | 42 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 checkov/terraform/checks/resource/azure/AppServiceEnvironmentZoneRedundant.py create mode 100644 tests/terraform/checks/resource/azure/example_AppServiceEnvironmentZoneRedundant/main.tf create mode 100644 tests/terraform/checks/resource/azure/test_AppServiceEnvironmentZoneRedundant.py diff --git a/checkov/terraform/checks/resource/azure/AppServiceEnvironmentZoneRedundant.py b/checkov/terraform/checks/resource/azure/AppServiceEnvironmentZoneRedundant.py new file mode 100644 index 00000000000..7332559dced --- /dev/null +++ b/checkov/terraform/checks/resource/azure/AppServiceEnvironmentZoneRedundant.py @@ -0,0 +1,17 @@ +from checkov.common.models.enums import CheckCategories +from checkov.terraform.checks.resource.base_resource_value_check import BaseResourceValueCheck + + +class AppServiceEnvironmentZoneRedundant(BaseResourceValueCheck): + def __init__(self) -> None: + name = "Ensure App Service Environment is zone redundant." + id = "CKV_AZURE_228" + supported_resources = ("azurerm_app_service_environment_v3",) + 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 = AppServiceEnvironmentZoneRedundant() diff --git a/tests/terraform/checks/resource/azure/example_AppServiceEnvironmentZoneRedundant/main.tf b/tests/terraform/checks/resource/azure/example_AppServiceEnvironmentZoneRedundant/main.tf new file mode 100644 index 00000000000..1cddb1d86b6 --- /dev/null +++ b/tests/terraform/checks/resource/azure/example_AppServiceEnvironmentZoneRedundant/main.tf @@ -0,0 +1,34 @@ +resource "azurerm_app_service_environment_v3" "pass" { + name = "example-asev3" + resource_group_name = azurerm_resource_group.example.name + subnet_id = azurerm_subnet.example.id + zone_redundant = true + + tags = { + env = "production" + terraformed = "true" + } +} + +resource "azurerm_app_service_environment_v3" "fail1" { + name = "example-asev3" + resource_group_name = azurerm_resource_group.example.name + subnet_id = azurerm_subnet.example.id + zone_redundant = false + + tags = { + env = "production" + terraformed = "true" + } +} + +resource "azurerm_app_service_environment_v3" "fail2" { + name = "example-asev3" + resource_group_name = azurerm_resource_group.example.name + subnet_id = azurerm_subnet.example.id + + tags = { + env = "production" + terraformed = "true" + } +} \ No newline at end of file diff --git a/tests/terraform/checks/resource/azure/test_AppServiceEnvironmentZoneRedundant.py b/tests/terraform/checks/resource/azure/test_AppServiceEnvironmentZoneRedundant.py new file mode 100644 index 00000000000..66a7a10d50c --- /dev/null +++ b/tests/terraform/checks/resource/azure/test_AppServiceEnvironmentZoneRedundant.py @@ -0,0 +1,42 @@ +import unittest +from pathlib import Path + +from checkov.runner_filter import RunnerFilter +from checkov.terraform.checks.resource.azure.AppServiceEnvironmentZoneRedundant import check +from checkov.terraform.runner import Runner + + +class TestAppServiceEnvironmentZoneRedundant(unittest.TestCase): + def test(self): + # given + test_files_dir = Path(__file__).parent / "example_AppServiceEnvironmentZoneRedundant" + + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) + + # then + summary = report.get_summary() + + passing_resources = { + "azurerm_app_service_environment_v3.pass", + } + failing_resources = { + "azurerm_app_service_environment_v3.fail1", + "azurerm_app_service_environment_v3.fail2", + } + + 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"], 2) + self.assertEqual(summary["failed"], 1) + self.assertEqual(summary["skipped"], 0) + self.assertEqual(summary["parsing_errors"], 0) + self.assertEqual(summary["resource_count"], 6) # 3 unknown + + self.assertEqual(passing_resources, passed_check_resources) + self.assertEqual(failing_resources, failed_check_resources) + + +if __name__ == "__main__": + unittest.main() From e94f795e5bd65aafed8ae15538fa0e88c7bfb6cb Mon Sep 17 00:00:00 2001 From: Thomas Defise Date: Thu, 26 Oct 2023 10:40:59 +0200 Subject: [PATCH 2/4] Adjusted CKV_AZURE_154 --- .../resource/azure/AppServiceSlotMinTLS.py | 13 +- .../example_AppServiceSlotMinTLS/main.tf | 156 ++++++++++++++++++ .../azure/test_AppServiceSlotMinTLSVersion.py | 10 +- 3 files changed, 173 insertions(+), 6 deletions(-) diff --git a/checkov/terraform/checks/resource/azure/AppServiceSlotMinTLS.py b/checkov/terraform/checks/resource/azure/AppServiceSlotMinTLS.py index 6448c5318c2..b83dfbda114 100644 --- a/checkov/terraform/checks/resource/azure/AppServiceSlotMinTLS.py +++ b/checkov/terraform/checks/resource/azure/AppServiceSlotMinTLS.py @@ -6,16 +6,21 @@ class AppServiceSlotMinTLS(BaseResourceValueCheck): def __init__(self): name = "Ensure the App service slot is using the latest version of TLS encryption" id = "CKV_AZURE_154" - supported_resources = ['azurerm_app_service_slot'] + supported_resources = ["azurerm_app_service_slot", "azurerm_linux_web_app_slot", "azurerm_windows_web_app_slot"] categories = [CheckCategories.NETWORKING] - super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources, - missing_block_result=CheckResult.PASSED) + super().__init__( + name=name, + id=id, + categories=categories, + supported_resources=supported_resources, + missing_block_result=CheckResult.PASSED, + ) def get_inspected_key(self): return "site_config/[0]/min_tls_version/[0]" def get_expected_value(self): - return '1.2' + return "1.2" check = AppServiceSlotMinTLS() diff --git a/tests/terraform/checks/resource/azure/example_AppServiceSlotMinTLS/main.tf b/tests/terraform/checks/resource/azure/example_AppServiceSlotMinTLS/main.tf index 8e8530fb3eb..be287ca16c6 100644 --- a/tests/terraform/checks/resource/azure/example_AppServiceSlotMinTLS/main.tf +++ b/tests/terraform/checks/resource/azure/example_AppServiceSlotMinTLS/main.tf @@ -24,6 +24,58 @@ resource "azurerm_app_service_slot" "fail" { } } +resource "azurerm_linux_web_app_slot" "fail" { + name = "brian" + app_service_name = azurerm_app_service.example.name + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id + + https_only = false #thedefault + + site_config { + dotnet_framework_version = "v4.0" + min_tls_version = "1.1" + remote_debugging_enabled = true + } + + app_settings = { + "SOME_KEY" = "some-value" + } + + connection_string { + name = "Database" + type = "SQLServer" + value = "Server=some-server.mydomain.com;Integrated Security=SSPI" + } +} + +resource "azurerm_windows_web_app_slot" "fail" { + name = "brian" + app_service_name = azurerm_app_service.example.name + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id + + https_only = false #thedefault + + site_config { + dotnet_framework_version = "v4.0" + min_tls_version = "1.1" + remote_debugging_enabled = true + } + + app_settings = { + "SOME_KEY" = "some-value" + } + + connection_string { + name = "Database" + type = "SQLServer" + value = "Server=some-server.mydomain.com;Integrated Security=SSPI" + } +} + #default resource "azurerm_app_service_slot" "pass" { name = "fred" @@ -51,6 +103,110 @@ resource "azurerm_app_service_slot" "pass" { } } +resource "azurerm_linux_web_app_slot" "pass" { + name = "brian" + app_service_name = azurerm_app_service.example.name + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id + + https_only = false #thedefault + + site_config { + dotnet_framework_version = "v4.0" + min_tls_version = "1.2" + remote_debugging_enabled = true + } + + app_settings = { + "SOME_KEY" = "some-value" + } + + connection_string { + name = "Database" + type = "SQLServer" + value = "Server=some-server.mydomain.com;Integrated Security=SSPI" + } +} + +resource "azurerm_windows_web_app_slot" "pass" { + name = "brian" + app_service_name = azurerm_app_service.example.name + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id + + https_only = false #thedefault + + site_config { + dotnet_framework_version = "v4.0" + min_tls_version = "1.2" + remote_debugging_enabled = true + } + + app_settings = { + "SOME_KEY" = "some-value" + } + + connection_string { + name = "Database" + type = "SQLServer" + value = "Server=some-server.mydomain.com;Integrated Security=SSPI" + } +} + +resource "azurerm_linux_web_app_slot" "pass2" { + name = "brian" + app_service_name = azurerm_app_service.example.name + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id + + https_only = false #thedefault + + site_config { + dotnet_framework_version = "v4.0" + min_tls_version = "1.2" + remote_debugging_enabled = true + } + + app_settings = { + "SOME_KEY" = "some-value" + } + + connection_string { + name = "Database" + type = "SQLServer" + value = "Server=some-server.mydomain.com;Integrated Security=SSPI" + } +} + +resource "azurerm_windows_web_app_slot" "pass2" { + name = "brian" + app_service_name = azurerm_app_service.example.name + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id + + https_only = false #thedefault + + site_config { + dotnet_framework_version = "v4.0" + min_tls_version = "1.2" + remote_debugging_enabled = true + } + + app_settings = { + "SOME_KEY" = "some-value" + } + + connection_string { + name = "Database" + type = "SQLServer" + value = "Server=some-server.mydomain.com;Integrated Security=SSPI" + } +} + resource "azurerm_app_service_slot" "pass2" { name = "ted" app_service_name = azurerm_app_service.example.name diff --git a/tests/terraform/checks/resource/azure/test_AppServiceSlotMinTLSVersion.py b/tests/terraform/checks/resource/azure/test_AppServiceSlotMinTLSVersion.py index a945910af9f..2e3eeea6ef9 100644 --- a/tests/terraform/checks/resource/azure/test_AppServiceSlotMinTLSVersion.py +++ b/tests/terraform/checks/resource/azure/test_AppServiceSlotMinTLSVersion.py @@ -19,17 +19,23 @@ def test(self): passing_resources = { "azurerm_app_service_slot.pass", + "azurerm_linux_web_app_slot.pass", + "azurerm_windows_web_app_slot.pass", "azurerm_app_service_slot.pass2", + "azurerm_linux_web_app_slot.pass2", + "azurerm_windows_web_app_slot.pass2", } failing_resources = { "azurerm_app_service_slot.fail", + "azurerm_linux_web_app_slot.fail", + "azurerm_windows_web_app_slot.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"], 2) - self.assertEqual(summary["failed"], 1) + self.assertEqual(summary["passed"], passed_check_resources) + self.assertEqual(summary["failed"], failed_check_resources) self.assertEqual(summary["skipped"], 0) self.assertEqual(summary["parsing_errors"], 0) self.assertEqual(summary["resource_count"], 6) # 3 unknown From eb650317c633a8bc0c1138d4bb8f4c0df41d8acd Mon Sep 17 00:00:00 2001 From: Thomas Defise Date: Thu, 26 Oct 2023 11:00:34 +0200 Subject: [PATCH 3/4] Not for this PR --- .../azure/AppServicePlanZoneRedundant.py | 26 ------------ .../main.tf | 26 ------------ ...test_AppServiceEnvironmentZoneRedundant.py | 42 ------------------- 3 files changed, 94 deletions(-) delete mode 100644 checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py delete mode 100644 tests/terraform/checks/resource/azure/example_AppServicePlanZoneRedundant/main.tf delete mode 100644 tests/terraform/checks/resource/azure/test_AppServiceEnvironmentZoneRedundant.py diff --git a/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py b/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py deleted file mode 100644 index 6f04fef7ec7..00000000000 --- a/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py +++ /dev/null @@ -1,26 +0,0 @@ -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() diff --git a/tests/terraform/checks/resource/azure/example_AppServicePlanZoneRedundant/main.tf b/tests/terraform/checks/resource/azure/example_AppServicePlanZoneRedundant/main.tf deleted file mode 100644 index b04e48e0326..00000000000 --- a/tests/terraform/checks/resource/azure/example_AppServicePlanZoneRedundant/main.tf +++ /dev/null @@ -1,26 +0,0 @@ -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_AppServiceEnvironmentZoneRedundant.py b/tests/terraform/checks/resource/azure/test_AppServiceEnvironmentZoneRedundant.py deleted file mode 100644 index 66a7a10d50c..00000000000 --- a/tests/terraform/checks/resource/azure/test_AppServiceEnvironmentZoneRedundant.py +++ /dev/null @@ -1,42 +0,0 @@ -import unittest -from pathlib import Path - -from checkov.runner_filter import RunnerFilter -from checkov.terraform.checks.resource.azure.AppServiceEnvironmentZoneRedundant import check -from checkov.terraform.runner import Runner - - -class TestAppServiceEnvironmentZoneRedundant(unittest.TestCase): - def test(self): - # given - test_files_dir = Path(__file__).parent / "example_AppServiceEnvironmentZoneRedundant" - - # when - report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) - - # then - summary = report.get_summary() - - passing_resources = { - "azurerm_app_service_environment_v3.pass", - } - failing_resources = { - "azurerm_app_service_environment_v3.fail1", - "azurerm_app_service_environment_v3.fail2", - } - - 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"], 2) - self.assertEqual(summary["failed"], 1) - self.assertEqual(summary["skipped"], 0) - self.assertEqual(summary["parsing_errors"], 0) - self.assertEqual(summary["resource_count"], 6) # 3 unknown - - self.assertEqual(passing_resources, passed_check_resources) - self.assertEqual(failing_resources, failed_check_resources) - - -if __name__ == "__main__": - unittest.main() From 6404eb95fa54ea98652403bfb4e70e9bcc2b0a73 Mon Sep 17 00:00:00 2001 From: Thomas Defise Date: Thu, 26 Oct 2023 15:10:24 +0200 Subject: [PATCH 4/4] Fix PR issue --- .../AppServiceEnvironmentZoneRedundant.py | 17 ---------- .../azure/AppServicePlanZoneRedundant.py | 25 ++++++++++++++ .../main.tf | 34 ------------------- .../main.tf | 26 ++++++++++++++ 4 files changed, 51 insertions(+), 51 deletions(-) delete mode 100644 checkov/terraform/checks/resource/azure/AppServiceEnvironmentZoneRedundant.py create mode 100644 checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py delete mode 100644 tests/terraform/checks/resource/azure/example_AppServiceEnvironmentZoneRedundant/main.tf create mode 100644 tests/terraform/checks/resource/azure/example_AppServicePlanZoneRedundant/main.tf diff --git a/checkov/terraform/checks/resource/azure/AppServiceEnvironmentZoneRedundant.py b/checkov/terraform/checks/resource/azure/AppServiceEnvironmentZoneRedundant.py deleted file mode 100644 index 7332559dced..00000000000 --- a/checkov/terraform/checks/resource/azure/AppServiceEnvironmentZoneRedundant.py +++ /dev/null @@ -1,17 +0,0 @@ -from checkov.common.models.enums import CheckCategories -from checkov.terraform.checks.resource.base_resource_value_check import BaseResourceValueCheck - - -class AppServiceEnvironmentZoneRedundant(BaseResourceValueCheck): - def __init__(self) -> None: - name = "Ensure App Service Environment is zone redundant." - id = "CKV_AZURE_228" - supported_resources = ("azurerm_app_service_environment_v3",) - 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 = AppServiceEnvironmentZoneRedundant() diff --git a/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py b/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py new file mode 100644 index 00000000000..8d32cf1e147 --- /dev/null +++ b/checkov/terraform/checks/resource/azure/AppServicePlanZoneRedundant.py @@ -0,0 +1,25 @@ +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() diff --git a/tests/terraform/checks/resource/azure/example_AppServiceEnvironmentZoneRedundant/main.tf b/tests/terraform/checks/resource/azure/example_AppServiceEnvironmentZoneRedundant/main.tf deleted file mode 100644 index 1cddb1d86b6..00000000000 --- a/tests/terraform/checks/resource/azure/example_AppServiceEnvironmentZoneRedundant/main.tf +++ /dev/null @@ -1,34 +0,0 @@ -resource "azurerm_app_service_environment_v3" "pass" { - name = "example-asev3" - resource_group_name = azurerm_resource_group.example.name - subnet_id = azurerm_subnet.example.id - zone_redundant = true - - tags = { - env = "production" - terraformed = "true" - } -} - -resource "azurerm_app_service_environment_v3" "fail1" { - name = "example-asev3" - resource_group_name = azurerm_resource_group.example.name - subnet_id = azurerm_subnet.example.id - zone_redundant = false - - tags = { - env = "production" - terraformed = "true" - } -} - -resource "azurerm_app_service_environment_v3" "fail2" { - name = "example-asev3" - resource_group_name = azurerm_resource_group.example.name - subnet_id = azurerm_subnet.example.id - - tags = { - env = "production" - terraformed = "true" - } -} \ No newline at end of file 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 index 00000000000..b04e48e0326 --- /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" +}