diff --git a/checkov/arm/checks/resource/KeyBackedByHSM.py b/checkov/arm/checks/resource/KeyBackedByHSM.py new file mode 100644 index 00000000000..5fe2a02290f --- /dev/null +++ b/checkov/arm/checks/resource/KeyBackedByHSM.py @@ -0,0 +1,23 @@ +from checkov.common.models.enums import CheckCategories +from checkov.arm.base_resource_value_check import BaseResourceValueCheck + + +class KeyBackedByHSM(BaseResourceValueCheck): + def __init__(self): + name = "Ensure that key vault key is backed by HSM" + id = "CKV_AZURE_112" + supported_resources = ['Microsoft.KeyVault/vaults/keys'] + categories = [CheckCategories.BACKUP_AND_RECOVERY] + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources) + + def get_inspected_key(self): + return 'properties/kty' + + def get_expected_value(self): + return 'RSA-HSM' + + def get_expected_values(self): + return [self.get_expected_value(), 'EC-HSM'] + + +check = KeyBackedByHSM() diff --git a/tests/arm/checks/resource/example_KeyBackedByHSM/fail.json b/tests/arm/checks/resource/example_KeyBackedByHSM/fail.json new file mode 100644 index 00000000000..09e311beb23 --- /dev/null +++ b/tests/arm/checks/resource/example_KeyBackedByHSM/fail.json @@ -0,0 +1,123 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault to be created." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "The name of the key to be created." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location of the resources" + } + }, + "skuName": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "standard", + "premium" + ], + "metadata": { + "description": "The SKU of the vault to be created." + } + }, + "keyType": { + "type": "string", + "defaultValue": "RSA", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "The JsonWebKeyType of the key to be created." + } + }, + "keyOps": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The permitted JSON web key operations of the key to be created." + } + }, + "keySize": { + "type": "int", + "defaultValue": 2048, + "metadata": { + "description": "The size in bits of the key to be created." + } + }, + "curveName": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "The JsonWebKeyCurveName of the key to be created." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-11-01-preview", + "name": "[parameters('vaultName')]", + "location": "[parameters('location')]", + "properties": { + "accessPolicies": [], + "enableRbacAuthorization": true, + "enableSoftDelete": true, + "softDeleteRetentionInDays": "90", + "enabledForDeployment": false, + "enabledForDiskEncryption": false, + "enabledForTemplateDeployment": false, + "tenantId": "[subscription().tenantId]", + "sku": { + "name": "[parameters('skuName')]", + "family": "A" + }, + "networkAcls": { + "defaultAction": "Allow", + "bypass": "AzureServices" + } + } + }, + { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2021-11-01-preview", + "name": "fail", + "properties": { + "kty": "RSA", + "keyOps": "[parameters('keyOps')]", + "keySize": "[parameters('keySize')]", + "curveName": "[parameters('curveName')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('vaultName'))]" + ] + } + ], + "outputs": { + "proxyKey": { + "type": "object", + "value": "[reference(resourceId('Microsoft.KeyVault/vaults/keys', parameters('vaultName'), parameters('keyName')))]" + } + } +} \ No newline at end of file diff --git a/tests/arm/checks/resource/example_KeyBackedByHSM/pass.json b/tests/arm/checks/resource/example_KeyBackedByHSM/pass.json new file mode 100644 index 00000000000..df39e8c64ba --- /dev/null +++ b/tests/arm/checks/resource/example_KeyBackedByHSM/pass.json @@ -0,0 +1,123 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault to be created." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "The name of the key to be created." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location of the resources" + } + }, + "skuName": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "standard", + "premium" + ], + "metadata": { + "description": "The SKU of the vault to be created." + } + }, + "keyType": { + "type": "string", + "defaultValue": "RSA", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "The JsonWebKeyType of the key to be created." + } + }, + "keyOps": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The permitted JSON web key operations of the key to be created." + } + }, + "keySize": { + "type": "int", + "defaultValue": 2048, + "metadata": { + "description": "The size in bits of the key to be created." + } + }, + "curveName": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "The JsonWebKeyCurveName of the key to be created." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-11-01-preview", + "name": "[parameters('vaultName')]", + "location": "[parameters('location')]", + "properties": { + "accessPolicies": [], + "enableRbacAuthorization": true, + "enableSoftDelete": true, + "softDeleteRetentionInDays": "90", + "enabledForDeployment": false, + "enabledForDiskEncryption": false, + "enabledForTemplateDeployment": false, + "tenantId": "[subscription().tenantId]", + "sku": { + "name": "[parameters('skuName')]", + "family": "A" + }, + "networkAcls": { + "defaultAction": "Allow", + "bypass": "AzureServices" + } + } + }, + { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2021-11-01-preview", + "name": "pass", + "properties": { + "kty": "RSA-HSM", + "keyOps": "[parameters('keyOps')]", + "keySize": "[parameters('keySize')]", + "curveName": "[parameters('curveName')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('vaultName'))]" + ] + } + ], + "outputs": { + "proxyKey": { + "type": "object", + "value": "[reference(resourceId('Microsoft.KeyVault/vaults/keys', parameters('vaultName'), parameters('keyName')))]" + } + } +} \ No newline at end of file diff --git a/tests/arm/checks/resource/test_KeyBackedByHSM.py b/tests/arm/checks/resource/test_KeyBackedByHSM.py new file mode 100644 index 00000000000..e336e5f6d41 --- /dev/null +++ b/tests/arm/checks/resource/test_KeyBackedByHSM.py @@ -0,0 +1,40 @@ +import unittest +from pathlib import Path + +from checkov.arm.checks.resource.KeyBackedByHSM import check +from checkov.arm.runner import Runner +from checkov.runner_filter import RunnerFilter + + +class TestKeyBackedByHSM(unittest.TestCase): + def test_summary(self): + # given + test_files_dir = Path(__file__).parent / "example_KeyBackedByHSM" + + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) + + # then + summary = report.get_summary() + + passing_resources = { + "Microsoft.KeyVault/vaults/keys.pass", + } + failing_resources = { + "Microsoft.KeyVault/vaults/keys.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()