From 9b6feb1ac73d783c90c92247a91c3cffca56a235 Mon Sep 17 00:00:00 2001 From: unu87 <151782629+unu87@users.noreply.github.com> Date: Sun, 19 May 2024 09:03:26 +0300 Subject: [PATCH] feat(arm): add FunctionAppDisallowCORS - password correctness check (#6248) * add policy FunctionAppDisallowCORS * Update FunctionAppDisallowCORS.py * add policy FunctionAppDisallowCORS * add policy FunctionAppDisallowCORS * add policy FunctionAppDisallowCORS * fix the lines of the code * add commit RedisCacheEnableNonSSLPort * fix RedisCacheEnableNonSSLPort --------- Co-authored-by: ChanochShayner <57212002+ChanochShayner@users.noreply.github.com> --- .../resource/FunctionAppDisallowCORS.py | 24 ++++++ .../example_FunctionAppDisallowCORS/fail.json | 81 +++++++++++++++++++ .../example_FunctionAppDisallowCORS/pass.json | 56 +++++++++++++ .../pass_with_cors.json | 81 +++++++++++++++++++ .../resource/test_FunctionAppDisallowCORS.py | 42 ++++++++++ 5 files changed, 284 insertions(+) create mode 100644 checkov/arm/checks/resource/FunctionAppDisallowCORS.py create mode 100644 tests/arm/checks/resource/example_FunctionAppDisallowCORS/fail.json create mode 100644 tests/arm/checks/resource/example_FunctionAppDisallowCORS/pass.json create mode 100644 tests/arm/checks/resource/example_FunctionAppDisallowCORS/pass_with_cors.json create mode 100644 tests/arm/checks/resource/test_FunctionAppDisallowCORS.py diff --git a/checkov/arm/checks/resource/FunctionAppDisallowCORS.py b/checkov/arm/checks/resource/FunctionAppDisallowCORS.py new file mode 100644 index 00000000000..e8b98b464d5 --- /dev/null +++ b/checkov/arm/checks/resource/FunctionAppDisallowCORS.py @@ -0,0 +1,24 @@ +from typing import List, Any +from checkov.common.models.enums import CheckCategories, CheckResult +from checkov.arm.base_resource_negative_value_check import BaseResourceNegativeValueCheck + + +class FunctionAppDisallowCORS(BaseResourceNegativeValueCheck): + + def __init__(self) -> None: + name = "Ensure function apps are not accessible from all regions" + id = "CKV_AZURE_62" + supported_resources = ("Microsoft.Web/sites",) + categories = (CheckCategories.GENERAL_SECURITY,) + super().__init__(name=name, id=id, categories=categories, + supported_resources=supported_resources, + missing_block_result=CheckResult.PASSED) + + def get_inspected_key(self) -> str: + return "properties/siteConfig/cors/allowedOrigins" + + def get_forbidden_values(self) -> List[Any]: + return ["*"] + + +check = FunctionAppDisallowCORS() diff --git a/tests/arm/checks/resource/example_FunctionAppDisallowCORS/fail.json b/tests/arm/checks/resource/example_FunctionAppDisallowCORS/fail.json new file mode 100644 index 00000000000..a1c52a80fe6 --- /dev/null +++ b/tests/arm/checks/resource/example_FunctionAppDisallowCORS/fail.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "siteName": { + "type": "string", + "metadata": { + "description": "The name of the Azure Web App." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The Azure region where the resource should be deployed." + } + }, + "sku": { + "type": "string", + "defaultValue": "Free", + "allowedValues": [ + "Free", + "Shared", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "The pricing tier of the Azure Web App." + } + }, + "appServicePlanName": { + "type": "string", + "metadata": { + "description": "The name of the App Service Plan to use." + } + } + }, + "resources": [ + { + "type": "Microsoft.Web/sites", + "apiVersion": "2019-08-01", + "name": "fail", + "location": "[parameters('location')]", + "properties": { + "name": "[parameters('siteName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]", + "siteConfig": { + "appSettings": [ + { + "name": "Setting1", + "value": "Value1" + }, + { + "name": "Setting2", + "value": "Value2" + } + ], + "metadata": [ + { + "name": "Key1", + "value": "Value1" + }, + { + "name": "Key2", + "value": "Value2" + } + ], + "cors": { + "allowedOrigins": ["*"] + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]" + ], + "sku": { + "name": "[parameters('sku')]" + } + } + ] +} \ No newline at end of file diff --git a/tests/arm/checks/resource/example_FunctionAppDisallowCORS/pass.json b/tests/arm/checks/resource/example_FunctionAppDisallowCORS/pass.json new file mode 100644 index 00000000000..d4db5386dc0 --- /dev/null +++ b/tests/arm/checks/resource/example_FunctionAppDisallowCORS/pass.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "siteName": { + "type": "string", + "metadata": { + "description": "The name of the Azure Web App." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The Azure region where the resource should be deployed." + } + }, + "sku": { + "type": "string", + "defaultValue": "Free", + "allowedValues": [ + "Free", + "Shared", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "The pricing tier of the Azure Web App." + } + }, + "appServicePlanName": { + "type": "string", + "metadata": { + "description": "The name of the App Service Plan to use." + } + } + }, + "resources": [ + { + "type": "Microsoft.Web/sites", + "apiVersion": "2019-08-01", + "name": "pass", + "location": "[parameters('location')]", + "properties": { + "name": "[parameters('siteName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]" + ], + "sku": { + "name": "[parameters('sku')]" + } + } + ] +} diff --git a/tests/arm/checks/resource/example_FunctionAppDisallowCORS/pass_with_cors.json b/tests/arm/checks/resource/example_FunctionAppDisallowCORS/pass_with_cors.json new file mode 100644 index 00000000000..89588498bbb --- /dev/null +++ b/tests/arm/checks/resource/example_FunctionAppDisallowCORS/pass_with_cors.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "siteName": { + "type": "string", + "metadata": { + "description": "The name of the Azure Web App." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The Azure region where the resource should be deployed." + } + }, + "sku": { + "type": "string", + "defaultValue": "Free", + "allowedValues": [ + "Free", + "Shared", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "The pricing tier of the Azure Web App." + } + }, + "appServicePlanName": { + "type": "string", + "metadata": { + "description": "The name of the App Service Plan to use." + } + } + }, + "resources": [ + { + "type": "Microsoft.Web/sites", + "apiVersion": "2019-08-01", + "name": "pass_with_cors", + "location": "[parameters('location')]", + "properties": { + "name": "[parameters('siteName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]", + "siteConfig": { + "appSettings": [ + { + "name": "Setting1", + "value": "Value1" + }, + { + "name": "Setting2", + "value": "Value2" + } + ], + "metadata": [ + { + "name": "Key1", + "value": "Value1" + }, + { + "name": "Key2", + "value": "Value2" + } + ], + "cors": { + "allowedOrigins": ["192.0.0.1"] + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]" + ], + "sku": { + "name": "[parameters('sku')]" + } + } + ] +} diff --git a/tests/arm/checks/resource/test_FunctionAppDisallowCORS.py b/tests/arm/checks/resource/test_FunctionAppDisallowCORS.py new file mode 100644 index 00000000000..93127cb1f91 --- /dev/null +++ b/tests/arm/checks/resource/test_FunctionAppDisallowCORS.py @@ -0,0 +1,42 @@ +import unittest +from pathlib import Path + +from checkov.arm.checks.resource.FunctionAppDisallowCORS import check +from checkov.arm.runner import Runner +from checkov.runner_filter import RunnerFilter + + +class TestFunctionAppDisallowCORS(unittest.TestCase): + + def test_summery(self): + # given + test_files_dir = Path(__file__).parent / "example_FunctionAppDisallowCORS" + + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) + + # then + summary = report.get_summary() + + passing_resources = { + "Microsoft.Web/sites.pass_with_cors", + "Microsoft.Web/sites.pass", + } + + failing_resources = { + "Microsoft.Web/sites.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() \ No newline at end of file