diff --git a/checkov/arm/checks/resource/StorageAccountsUseReplication.py b/checkov/arm/checks/resource/StorageAccountsUseReplication.py new file mode 100644 index 00000000000..86b0de0d9bd --- /dev/null +++ b/checkov/arm/checks/resource/StorageAccountsUseReplication.py @@ -0,0 +1,24 @@ +from checkov.common.models.enums import CheckCategories +from checkov.arm.base_resource_value_check import BaseResourceValueCheck +from typing import Any, List + + +class StorageAccountsUseReplication(BaseResourceValueCheck): + def __init__(self) -> None: + name = "Ensure that Storage Accounts use replication" + id = "CKV_AZURE_206" + supported_resources = ("Microsoft.Storage/storageAccounts",) + categories = (CheckCategories.BACKUP_AND_RECOVERY,) + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources,) + + def get_inspected_key(self) -> str: + return "sku/name" + + def get_expected_value(self) -> Any: + return "Standard_GRS" + + def get_expected_values(self) -> List[Any]: + return ["Standard_GRS", "Standard_RAGRS", "Standard_GZRS", "Standard_RAGZRS"] + + +check = StorageAccountsUseReplication() diff --git a/tests/arm/checks/resource/example_StorageAccountsUseReplication/fail.json b/tests/arm/checks/resource/example_StorageAccountsUseReplication/fail.json new file mode 100644 index 00000000000..248e4d3be5a --- /dev/null +++ b/tests/arm/checks/resource/example_StorageAccountsUseReplication/fail.json @@ -0,0 +1,50 @@ +{ + "$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": "13120038605368246703" + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The storage account location." + } + }, + "storageAccountName": { + "type": "string", + "defaultValue": "[format('store{0}', uniqueString(resourceGroup().id))]", + "metadata": { + "description": "The name of the storage account" + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "fail", + "location": "[parameters('location')]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2", + "properties": {} + } + ], + "outputs": { + "storageAccountName": { + "type": "string", + "value": "[parameters('storageAccountName')]" + }, + "storageAccountId": { + "type": "string", + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + } + } +} diff --git a/tests/arm/checks/resource/example_StorageAccountsUseReplication/pass.json b/tests/arm/checks/resource/example_StorageAccountsUseReplication/pass.json new file mode 100644 index 00000000000..c3946a6630c --- /dev/null +++ b/tests/arm/checks/resource/example_StorageAccountsUseReplication/pass.json @@ -0,0 +1,61 @@ +{ + "$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": "13120038605368246703" + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The storage account location." + } + }, + "storageAccountName": { + "type": "string", + "defaultValue": "[format('store{0}', uniqueString(resourceGroup().id))]", + "metadata": { + "description": "The name of the storage account" + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "pass", + "location": "[parameters('location')]", + "sku": { + "name": "Standard_GRS" + }, + "kind": "StorageV2", + "properties": {} + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "pass2", + "location": "[parameters('location')]", + "sku": { + "name": "Standard_RAGRS" + }, + "kind": "StorageV2", + "properties": {} + } + ], + "outputs": { + "storageAccountName": { + "type": "string", + "value": "[parameters('storageAccountName')]" + }, + "storageAccountId": { + "type": "string", + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + } + } +} diff --git a/tests/arm/checks/resource/test_StorageAccountsUseReplication.py b/tests/arm/checks/resource/test_StorageAccountsUseReplication.py new file mode 100644 index 00000000000..ca4127965aa --- /dev/null +++ b/tests/arm/checks/resource/test_StorageAccountsUseReplication.py @@ -0,0 +1,41 @@ +import unittest +from pathlib import Path + +from checkov.runner_filter import RunnerFilter +from checkov.arm.checks.resource.StorageAccountsUseReplication import check +from checkov.arm.runner import Runner + + +class TestStorageAccountsUseReplication(unittest.TestCase): + def test(self): + # given + test_files_dir = Path(__file__).parent / "example_StorageAccountsUseReplication" + + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) + + # then + summary = report.get_summary() + + passing_resources = { + "Microsoft.Storage/storageAccounts.pass", + "Microsoft.Storage/storageAccounts.pass2", + } + failing_resources = { + "Microsoft.Storage/storageAccounts.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()