diff --git a/checkov/arm/checks/resource/PubsubSKUSLA.py b/checkov/arm/checks/resource/PubsubSKUSLA.py new file mode 100644 index 00000000000..3c2c9f8180d --- /dev/null +++ b/checkov/arm/checks/resource/PubsubSKUSLA.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any + +from checkov.common.models.enums import CheckCategories +from checkov.arm.base_resource_negative_value_check import BaseResourceNegativeValueCheck + + +class PubsubSKUSLA(BaseResourceNegativeValueCheck): + def __init__(self) -> None: + name = "Ensure Web PubSub uses a SKU with an SLA" + id = "CKV_AZURE_175" + supported_resources = ("Microsoft.SignalRService/webPubSub",) + categories = (CheckCategories.GENERAL_SECURITY,) + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources,) + + def get_inspected_key(self) -> str: + return "sku/name" + + def get_forbidden_values(self) -> Any: + return "Free_F1" + + +check = PubsubSKUSLA() diff --git a/tests/arm/checks/resource/example_PubsubSKUSLA/fail.json b/tests/arm/checks/resource/example_PubsubSKUSLA/fail.json new file mode 100644 index 00000000000..7ddcc188e35 --- /dev/null +++ b/tests/arm/checks/resource/example_PubsubSKUSLA/fail.json @@ -0,0 +1,127 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.13.1.58284", + "templateHash": "18262070107935981048" + } + }, + "parameters": { + "wpsName": { + "type": "string", + "defaultValue": "[uniqueString(resourceGroup().id)]", + "minLength": 3, + "maxLength": 63, + "metadata": { + "description": "The name for your new Web PubSub instance." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The region in which to create the new instance, defaults to the same location as the resource group." + } + }, + "unitCount": { + "type": "int", + "defaultValue": 1, + "allowedValues": [ + 1, + 2, + 5, + 10, + 20, + 50, + 100 + ], + "metadata": { + "description": "Unit count" + } + }, + "sku": { + "type": "string", + "defaultValue": "Free_F1", + "allowedValues": [ + "Standard_S1", + "Free_F1" + ], + "metadata": { + "description": "SKU name" + } + }, + "pricingTier": { + "type": "string", + "defaultValue": "Free", + "allowedValues": [ + "Free", + "Standard" + ], + "metadata": { + "description": "Pricing tier" + } + } + }, + "resources": [ + { + "type": "Microsoft.SignalRService/webPubSub", + "apiVersion": "2021-10-01", + "name": "fail", + "location": "[parameters('location')]", + "sku": { + "capacity": "[parameters('unitCount')]", + "name": "Free_F1", + "tier": "[parameters('pricingTier')]" + }, + "identity": { + "type": "None" + }, + "properties": { + "disableAadAuth": false, + "disableLocalAuth": false, + "liveTraceConfiguration": { + "categories": [ + { + "enabled": "false", + "name": "ConnectivityLogs" + }, + { + "enabled": "false", + "name": "MessagingLogs" + } + ], + "enabled": "false" + }, + "networkACLs": { + "defaultAction": "Deny", + "publicNetwork": { + "allow": [ + "ServerConnection", + "ClientConnection", + "RESTAPI", + "Trace" + ] + } + }, + "publicNetworkAccess": "Enabled", + "resourceLogConfiguration": { + "categories": [ + { + "enabled": "true", + "name": "ConnectivityLogs" + }, + { + "enabled": "true", + "name": "MessagingLogs" + } + ] + }, + "tls": { + "clientCertEnabled": false + } + } + } + ] +} diff --git a/tests/arm/checks/resource/example_PubsubSKUSLA/pass.json b/tests/arm/checks/resource/example_PubsubSKUSLA/pass.json new file mode 100644 index 00000000000..2c46bc3a699 --- /dev/null +++ b/tests/arm/checks/resource/example_PubsubSKUSLA/pass.json @@ -0,0 +1,127 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.13.1.58284", + "templateHash": "18262070107935981048" + } + }, + "parameters": { + "wpsName": { + "type": "string", + "defaultValue": "[uniqueString(resourceGroup().id)]", + "minLength": 3, + "maxLength": 63, + "metadata": { + "description": "The name for your new Web PubSub instance." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The region in which to create the new instance, defaults to the same location as the resource group." + } + }, + "unitCount": { + "type": "int", + "defaultValue": 1, + "allowedValues": [ + 1, + 2, + 5, + 10, + 20, + 50, + 100 + ], + "metadata": { + "description": "Unit count" + } + }, + "sku": { + "type": "string", + "defaultValue": "Free_F1", + "allowedValues": [ + "Standard_S1", + "Free_F1" + ], + "metadata": { + "description": "SKU name" + } + }, + "pricingTier": { + "type": "string", + "defaultValue": "Free", + "allowedValues": [ + "Free", + "Standard" + ], + "metadata": { + "description": "Pricing tier" + } + } + }, + "resources": [ + { + "type": "Microsoft.SignalRService/webPubSub", + "apiVersion": "2021-10-01", + "name": "pass", + "location": "[parameters('location')]", + "sku": { + "capacity": "[parameters('unitCount')]", + "name": "Standard_S1", + "tier": "[parameters('pricingTier')]" + }, + "identity": { + "type": "None" + }, + "properties": { + "disableAadAuth": false, + "disableLocalAuth": false, + "liveTraceConfiguration": { + "categories": [ + { + "enabled": "false", + "name": "ConnectivityLogs" + }, + { + "enabled": "false", + "name": "MessagingLogs" + } + ], + "enabled": "false" + }, + "networkACLs": { + "defaultAction": "Deny", + "publicNetwork": { + "allow": [ + "ServerConnection", + "ClientConnection", + "RESTAPI", + "Trace" + ] + } + }, + "publicNetworkAccess": "Enabled", + "resourceLogConfiguration": { + "categories": [ + { + "enabled": "true", + "name": "ConnectivityLogs" + }, + { + "enabled": "true", + "name": "MessagingLogs" + } + ] + }, + "tls": { + "clientCertEnabled": false + } + } + } + ] +} diff --git a/tests/arm/checks/resource/test_PubsubSKUSLA.py b/tests/arm/checks/resource/test_PubsubSKUSLA.py new file mode 100644 index 00000000000..2557783e5b7 --- /dev/null +++ b/tests/arm/checks/resource/test_PubsubSKUSLA.py @@ -0,0 +1,41 @@ +import unittest +from pathlib import Path + +from checkov.runner_filter import RunnerFilter +from checkov.arm.checks.resource.PubsubSKUSLA import check +from checkov.arm.runner import Runner + + +class TestPubsubSKUSLA(unittest.TestCase): + + def test(self): + # given + test_files_dir = Path(__file__).parent / "example_PubsubSKUSLA" + + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) + + # then + summary = report.get_summary() + + passing_resources = { + "Microsoft.SignalRService/webPubSub.pass", + } + failing_resources = { + "Microsoft.SignalRService/webPubSub.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()