From 908032977340f1b8f44d36f3149962d01331ef27 Mon Sep 17 00:00:00 2001 From: James Woolfenden Date: Wed, 23 Aug 2023 14:29:41 +0100 Subject: [PATCH] feat(arm): migrate check CKV_AZURE_50 to arm (#5453) migrate check to arem --- checkov/arm/base_resource_value_check.py | 2 +- .../resource/AzureInstanceExtensions.py | 20 ++++ .../example_AzureInstanceExtensions/fail.json | 95 +++++++++++++++++++ .../fail2.json | 94 ++++++++++++++++++ .../example_AzureInstanceExtensions/pass.json | 95 +++++++++++++++++++ .../resource/test_AzureInstanceExtensions.py | 42 ++++++++ .../example_AzureInstanceExtensions/main.tf | 67 +++++++++---- 7 files changed, 394 insertions(+), 21 deletions(-) create mode 100644 checkov/arm/checks/resource/AzureInstanceExtensions.py create mode 100644 tests/arm/checks/resource/example_AzureInstanceExtensions/fail.json create mode 100644 tests/arm/checks/resource/example_AzureInstanceExtensions/fail2.json create mode 100644 tests/arm/checks/resource/example_AzureInstanceExtensions/pass.json create mode 100644 tests/arm/checks/resource/test_AzureInstanceExtensions.py diff --git a/checkov/arm/base_resource_value_check.py b/checkov/arm/base_resource_value_check.py index 0d3f870bb75..15c752aaf88 100644 --- a/checkov/arm/base_resource_value_check.py +++ b/checkov/arm/base_resource_value_check.py @@ -38,7 +38,7 @@ def scan_resource_conf(self, conf: Dict[str, Any]) -> CheckResult: # type:ignor inspected_key = self.get_inspected_key() expected_values = self.get_expected_values() value = find_in_dict(conf, inspected_key) - if value: + if value is not None: if ANY_VALUE in expected_values: # Key is found in the configuration - if it accepts any value, the check is PASSED return CheckResult.PASSED diff --git a/checkov/arm/checks/resource/AzureInstanceExtensions.py b/checkov/arm/checks/resource/AzureInstanceExtensions.py new file mode 100644 index 00000000000..67221bda7ae --- /dev/null +++ b/checkov/arm/checks/resource/AzureInstanceExtensions.py @@ -0,0 +1,20 @@ +from checkov.common.models.enums import CheckCategories +from checkov.arm.base_resource_value_check import BaseResourceValueCheck + + +class AzureInstanceExtensions(BaseResourceValueCheck): + def __init__(self) -> None: + name = "Ensure Virtual Machine Extensions are not Installed" + id = "CKV_AZURE_50" + supported_resources = ["Microsoft.Compute/virtualMachines"] + categories = [CheckCategories.GENERAL_SECURITY] + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources) + + def get_inspected_key(self) -> str: + return "properties/osProfile/allowExtensionOperations" + + def get_expected_value(self) -> bool: + return False + + +check = AzureInstanceExtensions() diff --git a/tests/arm/checks/resource/example_AzureInstanceExtensions/fail.json b/tests/arm/checks/resource/example_AzureInstanceExtensions/fail.json new file mode 100644 index 00000000000..53bfb050460 --- /dev/null +++ b/tests/arm/checks/resource/example_AzureInstanceExtensions/fail.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "virtualMachines_pike_name": { + "defaultValue": "fail", + "type": "String" + }, + "disks_pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050_externalid": { + "defaultValue": "/subscriptions/037ce662-dfc1-4b8b-a8a7-6c414b540ed6/resourceGroups/example-resources/providers/Microsoft.Compute/disks/pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050", + "type": "String" + }, + "networkInterfaces_pike_nic_externalid": { + "defaultValue": "/subscriptions/037ce662-dfc1-4b8b-a8a7-6c414b540ed6/resourceGroups/example-resources/providers/Microsoft.Network/networkInterfaces/pike_nic", + "type": "String" + } + }, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-03-01", + "name": "[parameters('virtualMachines_pike_name')]", + "location": "westeurope", + "properties": { + "hardwareProfile": { + "vmSize": "Standard_F2" + }, + "storageProfile": { + "imageReference": { + "publisher": "Canonical", + "offer": "0001-com-ubuntu-server-focal", + "sku": "20_04-lts", + "version": "latest" + }, + "osDisk": { + "osType": "Linux", + "name": "[concat(parameters('virtualMachines_pike_name'), '_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050')]", + "createOption": "FromImage", + "caching": "ReadWrite", + "writeAcceleratorEnabled": false, + "managedDisk": { + "storageAccountType": "Standard_LRS", + "id": "[parameters('disks_pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050_externalid')]" + }, + "deleteOption": "Detach", + "diskSizeGB": 30 + }, + "dataDisks": [] + }, + "osProfile": { + "computerName": "[parameters('virtualMachines_pike_name')]", + "adminUsername": "adminuser", + "linuxConfiguration": { + "disablePasswordAuthentication": true, + "ssh": { + "publicKeys": [ + { + "path": "/home/adminuser/.ssh/authorized_keys", + "keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5M1Z6i9r0/5ld5oWUhWIDI8j1DPc1sDrRqfPc4GMuotkpg2Iza7mX+JkieB36RmzRmhOjNZDh8FdtnoW3gtJ/dTkY8t2cnttAAD49BWmg9C9scfVXj5zNYdaDX9eYFY+a4UyYNkDZtmTnaK+i4r32lIAahcCd8L4vD8ltpw/LIZmI4FpShy019pXadYMVhPA3X6Tav8+BUW76enj1BKD2e5WqUOSvdxuiKcLIiJeyveq2Yl30kbmB0o3hVp7fQYrIwtEjz/11X29NcIgyb9wNuEGPq751Vfgwk6vh0tBUasrOGrh5wo3gHezBEtfOWXYadIxMzGW/a7QYRbXhcUfz\n" + } + ] + }, + "provisionVMAgent": true, + "patchSettings": { + "patchMode": "ImageDefault", + "assessmentMode": "ImageDefault" + }, + "enableVMAgentPlatformUpdates": false + }, + "secrets": [], + "allowExtensionOperations": true, + "requireGuestProvisionSignal": true + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[parameters('networkInterfaces_pike_nic_externalid')]", + "properties": { + "primary": true + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "priority": "Regular", + "extensionsTimeBudget": "PT1H30M" + } + } + ] +} \ No newline at end of file diff --git a/tests/arm/checks/resource/example_AzureInstanceExtensions/fail2.json b/tests/arm/checks/resource/example_AzureInstanceExtensions/fail2.json new file mode 100644 index 00000000000..50f0cdc13f5 --- /dev/null +++ b/tests/arm/checks/resource/example_AzureInstanceExtensions/fail2.json @@ -0,0 +1,94 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "virtualMachines_pike_name": { + "defaultValue": "fail2", + "type": "String" + }, + "disks_pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050_externalid": { + "defaultValue": "/subscriptions/037ce662-dfc1-4b8b-a8a7-6c414b540ed6/resourceGroups/example-resources/providers/Microsoft.Compute/disks/pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050", + "type": "String" + }, + "networkInterfaces_pike_nic_externalid": { + "defaultValue": "/subscriptions/037ce662-dfc1-4b8b-a8a7-6c414b540ed6/resourceGroups/example-resources/providers/Microsoft.Network/networkInterfaces/pike_nic", + "type": "String" + } + }, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-03-01", + "name": "[parameters('virtualMachines_pike_name')]", + "location": "westeurope", + "properties": { + "hardwareProfile": { + "vmSize": "Standard_F2" + }, + "storageProfile": { + "imageReference": { + "publisher": "Canonical", + "offer": "0001-com-ubuntu-server-focal", + "sku": "20_04-lts", + "version": "latest" + }, + "osDisk": { + "osType": "Linux", + "name": "[concat(parameters('virtualMachines_pike_name'), '_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050')]", + "createOption": "FromImage", + "caching": "ReadWrite", + "writeAcceleratorEnabled": false, + "managedDisk": { + "storageAccountType": "Standard_LRS", + "id": "[parameters('disks_pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050_externalid')]" + }, + "deleteOption": "Detach", + "diskSizeGB": 30 + }, + "dataDisks": [] + }, + "osProfile": { + "computerName": "[parameters('virtualMachines_pike_name')]", + "adminUsername": "adminuser", + "linuxConfiguration": { + "disablePasswordAuthentication": true, + "ssh": { + "publicKeys": [ + { + "path": "/home/adminuser/.ssh/authorized_keys", + "keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5M1Z6i9r0/5ld5oWUhWIDI8j1DPc1sDrRqfPc4GMuotkpg2Iza7mX+JkieB36RmzRmhOjNZDh8FdtnoW3gtJ/dTkY8t2cnttAAD49BWmg9C9scfVXj5zNYdaDX9eYFY+a4UyYNkDZtmTnaK+i4r32lIAahcCd8L4vD8ltpw/LIZmI4FpShy019pXadYMVhPA3X6Tav8+BUW76enj1BKD2e5WqUOSvdxuiKcLIiJeyveq2Yl30kbmB0o3hVp7fQYrIwtEjz/11X29NcIgyb9wNuEGPq751Vfgwk6vh0tBUasrOGrh5wo3gHezBEtfOWXYadIxMzGW/a7QYRbXhcUfz\n" + } + ] + }, + "provisionVMAgent": true, + "patchSettings": { + "patchMode": "ImageDefault", + "assessmentMode": "ImageDefault" + }, + "enableVMAgentPlatformUpdates": false + }, + "secrets": [], + "requireGuestProvisionSignal": true + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[parameters('networkInterfaces_pike_nic_externalid')]", + "properties": { + "primary": true + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "priority": "Regular", + "extensionsTimeBudget": "PT1H30M" + } + } + ] +} \ No newline at end of file diff --git a/tests/arm/checks/resource/example_AzureInstanceExtensions/pass.json b/tests/arm/checks/resource/example_AzureInstanceExtensions/pass.json new file mode 100644 index 00000000000..389a0180447 --- /dev/null +++ b/tests/arm/checks/resource/example_AzureInstanceExtensions/pass.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "virtualMachines_pike_name": { + "defaultValue": "pike", + "type": "String" + }, + "disks_pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050_externalid": { + "defaultValue": "/subscriptions/037ce662-dfc1-4b8b-a8a7-6c414b540ed6/resourceGroups/example-resources/providers/Microsoft.Compute/disks/pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050", + "type": "String" + }, + "networkInterfaces_pike_nic_externalid": { + "defaultValue": "/subscriptions/037ce662-dfc1-4b8b-a8a7-6c414b540ed6/resourceGroups/example-resources/providers/Microsoft.Network/networkInterfaces/pike_nic", + "type": "String" + } + }, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-03-01", + "name": "[parameters('virtualMachines_pike_name')]", + "location": "westeurope", + "properties": { + "hardwareProfile": { + "vmSize": "Standard_F2" + }, + "storageProfile": { + "imageReference": { + "publisher": "Canonical", + "offer": "0001-com-ubuntu-server-focal", + "sku": "20_04-lts", + "version": "latest" + }, + "osDisk": { + "osType": "Linux", + "name": "[concat(parameters('virtualMachines_pike_name'), '_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050')]", + "createOption": "FromImage", + "caching": "ReadWrite", + "writeAcceleratorEnabled": false, + "managedDisk": { + "storageAccountType": "Standard_LRS", + "id": "[parameters('disks_pike_OsDisk_1_8456bd2e1ebc4b3e9ece2b8770126050_externalid')]" + }, + "deleteOption": "Detach", + "diskSizeGB": 30 + }, + "dataDisks": [] + }, + "osProfile": { + "computerName": "[parameters('virtualMachines_pike_name')]", + "adminUsername": "adminuser", + "linuxConfiguration": { + "disablePasswordAuthentication": true, + "ssh": { + "publicKeys": [ + { + "path": "/home/adminuser/.ssh/authorized_keys", + "keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5M1Z6i9r0/5ld5oWUhWIDI8j1DPc1sDrRqfPc4GMuotkpg2Iza7mX+JkieB36RmzRmhOjNZDh8FdtnoW3gtJ/dTkY8t2cnttAAD49BWmg9C9scfVXj5zNYdaDX9eYFY+a4UyYNkDZtmTnaK+i4r32lIAahcCd8L4vD8ltpw/LIZmI4FpShy019pXadYMVhPA3X6Tav8+BUW76enj1BKD2e5WqUOSvdxuiKcLIiJeyveq2Yl30kbmB0o3hVp7fQYrIwtEjz/11X29NcIgyb9wNuEGPq751Vfgwk6vh0tBUasrOGrh5wo3gHezBEtfOWXYadIxMzGW/a7QYRbXhcUfz\n" + } + ] + }, + "provisionVMAgent": true, + "patchSettings": { + "patchMode": "ImageDefault", + "assessmentMode": "ImageDefault" + }, + "enableVMAgentPlatformUpdates": false + }, + "secrets": [], + "allowExtensionOperations": false, + "requireGuestProvisionSignal": true + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[parameters('networkInterfaces_pike_nic_externalid')]", + "properties": { + "primary": true + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "priority": "Regular", + "extensionsTimeBudget": "PT1H30M" + } + } + ] +} \ No newline at end of file diff --git a/tests/arm/checks/resource/test_AzureInstanceExtensions.py b/tests/arm/checks/resource/test_AzureInstanceExtensions.py new file mode 100644 index 00000000000..e2b5119be6a --- /dev/null +++ b/tests/arm/checks/resource/test_AzureInstanceExtensions.py @@ -0,0 +1,42 @@ +import unittest +from pathlib import Path + +from checkov.arm.checks.resource.AzureInstanceExtensions import check +from checkov.arm.runner import Runner +from checkov.runner_filter import RunnerFilter + + +class TestAzureInstanceExtensions(unittest.TestCase): + def test_summary(self): + # given + test_files_dir = Path(__file__).parent / "example_AzureInstanceExtensions" + + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) + + # then + summary = report.get_summary() + + passing_resources = { + "Microsoft.Compute/virtualMachines.pike", + } + failing_resources = { + "Microsoft.Compute/virtualMachines.fail", + "Microsoft.Compute/virtualMachines.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"], len(passing_resources)) + self.assertEqual(summary["failed"], len(failing_resources)) + self.assertEqual(summary["skipped"], 0) + self.assertEqual(summary["parsing_errors"], 0) + self.assertEqual(summary["resource_count"], 3) # includes 2 unknown + + self.assertEqual(passing_resources, passed_check_resources) + self.assertEqual(failing_resources, failed_check_resources) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/terraform/checks/resource/azure/example_AzureInstanceExtensions/main.tf b/tests/terraform/checks/resource/azure/example_AzureInstanceExtensions/main.tf index d9b6193cf5e..3e93d561df7 100644 --- a/tests/terraform/checks/resource/azure/example_AzureInstanceExtensions/main.tf +++ b/tests/terraform/checks/resource/azure/example_AzureInstanceExtensions/main.tf @@ -1,15 +1,22 @@ # pass resource "azurerm_linux_virtual_machine" "disabled" { - admin_password = "admin" + admin_password = "@Admin123" admin_username = "admin123" - location = "azurerm_resource_group.test.location" + location = azurerm_resource_group.test.location name = "linux-vm" - resource_group_name = "azurerm_resource_group.test.name" - size = "Standard_F2" + resource_group_name = azurerm_resource_group.test.name + size = "balls" + + source_image_reference { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-focal" + sku = "20_04-lts" + version = "latest" + } network_interface_ids = [ - "azurerm_network_interface.test.id" + azurerm_network_interface.test.id ] os_disk { @@ -23,9 +30,9 @@ resource "azurerm_linux_virtual_machine" "disabled" { resource "azurerm_windows_virtual_machine" "disabled" { admin_password = "admin" admin_username = "admin123" - location = "azurerm_resource_group.test.location" + location = azurerm_resource_group.test.location name = "win-vm" - resource_group_name = "azurerm_resource_group.test.name" + resource_group_name = azurerm_resource_group.test.name size = "Standard_F2" network_interface_ids = [ @@ -40,18 +47,18 @@ resource "azurerm_windows_virtual_machine" "disabled" { allow_extension_operations = false } -# fail +## fail resource "azurerm_linux_virtual_machine" "default" { admin_password = "admin" admin_username = "admin123" - location = "azurerm_resource_group.test.location" + location = azurerm_resource_group.test.location name = "linux-vm" - resource_group_name = "azurerm_resource_group.test.name" + resource_group_name = azurerm_resource_group.test.name size = "Standard_F2" network_interface_ids = [ - "azurerm_network_interface.test.id" + azurerm_network_interface.test.id ] os_disk { @@ -63,13 +70,13 @@ resource "azurerm_linux_virtual_machine" "default" { resource "azurerm_linux_virtual_machine" "enabled" { admin_password = "admin" admin_username = "admin123" - location = "azurerm_resource_group.test.location" + location = azurerm_resource_group.test.location name = "linux-vm" - resource_group_name = "azurerm_resource_group.test.name" + resource_group_name = azurerm_resource_group.test.name size = "Standard_F2" network_interface_ids = [ - "azurerm_network_interface.test.id" + azurerm_network_interface.test.id ] os_disk { @@ -83,13 +90,13 @@ resource "azurerm_linux_virtual_machine" "enabled" { resource "azurerm_windows_virtual_machine" "default" { admin_password = "admin" admin_username = "admin123" - location = "azurerm_resource_group.test.location" + location = azurerm_resource_group.test.location name = "win-vm" - resource_group_name = "azurerm_resource_group.test.name" + resource_group_name = azurerm_resource_group.test.name size = "Standard_F2" network_interface_ids = [ - "azurerm_network_interface.test.id" + azurerm_network_interface.test.id ] os_disk { @@ -101,13 +108,13 @@ resource "azurerm_windows_virtual_machine" "default" { resource "azurerm_windows_virtual_machine" "enabled" { admin_password = "admin" admin_username = "admin123" - location = "azurerm_resource_group.test.location" + location = azurerm_resource_group.test.location name = "win-vm" - resource_group_name = "azurerm_resource_group.test.name" + resource_group_name = azurerm_resource_group.test.name size = "Standard_F2" network_interface_ids = [ - "azurerm_network_interface.test.id" + azurerm_network_interface.test.id ] os_disk { @@ -117,3 +124,23 @@ resource "azurerm_windows_virtual_machine" "enabled" { allow_extension_operations = true } + + +resource "azurerm_resource_group" "test" { + name="test" + location="uk south" +} + +resource "azurerm_network_interface" "test" { + location = azurerm_resource_group.test.location + name = "test" + resource_group_name = azurerm_resource_group.test.name + ip_configuration { + name = "internal" + private_ip_address_allocation = "Dynamic" + } +} + +provider "azurerm" { + features{} +} \ No newline at end of file