Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(arm): CKV_AZURE_92 to Ensure that Virtual Machines use managed disks #6455

Merged
merged 7 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions checkov/arm/checks/resource/VMStorageOsDisk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import Any, Dict

from checkov.common.models.enums import CheckResult, CheckCategories
from checkov.arm.base_resource_value_check import BaseResourceCheck


class VMStorageOsDisk(BaseResourceCheck):
def __init__(self) -> None:
name = "Ensure that Virtual Machines use managed disks"
id = "CKV_AZURE_92"
supported_resources = ("Microsoft.Compute/virtualMachines",)
categories = (CheckCategories.GENERAL_SECURITY,)
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def scan_resource_conf(self, conf: Dict[str, Any]) -> CheckResult:
properties = conf.get('properties')
if not properties or not isinstance(properties, dict):
return CheckResult.PASSED
storage_profile = properties.get('storageProfile')
if not storage_profile or not isinstance(storage_profile, dict):
return CheckResult.PASSED
os_disk = storage_profile.get('osDisk')
ChanochShayner marked this conversation as resolved.
Show resolved Hide resolved
data_disks = list(storage_profile.get('dataDisks', []))
if os_disk and isinstance(os_disk, dict) and "vhd" in os_disk:
self.evaluated_keys = ['os_disk']
return CheckResult.FAILED
if data_disks and any(isinstance(data_disk, dict) and "vhd" in data_disk for data_disk in data_disks):
ChanochShayner marked this conversation as resolved.
Show resolved Hide resolved
self.evaluated_keys = ['data_disks']
return CheckResult.FAILED
self.evaluated_keys = ['os_disk'] if os_disk else []
if data_disks:
self.evaluated_keys.append('data_disks')
return CheckResult.PASSED


check = VMStorageOsDisk()
57 changes: 57 additions & 0 deletions tests/arm/checks/resource/example_VMStorageOsDisk/fail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2021-07-01",
"name": "fail-linux",
"location": "[resourceGroup().location]",
"properties": {
"hardwareProfile": {
"vmSize": "Standard_DS1_v2"
},
"storageProfile": {
"imageReference": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "16.04-LTS",
"version": "latest"
},
"osDisk": {
"name": "myosdisk3",
"caching": "ReadWrite",
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"vhd": {
"uri": "someURI"
}
}
},
"osProfile": {
"computerName": "hostname",
"adminUsername": "testadmin",
"adminPassword": "Password1234!"
ChanochShayner marked this conversation as resolved.
Show resolved Hide resolved
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', 'main')]"
}
]
}
},
"tags": {
"environment": "staging"
}
}
],
"parameters": {
"prefix": {
"type": "string",
"defaultValue": "myprefix"
}
}
}
59 changes: 59 additions & 0 deletions tests/arm/checks/resource/example_VMStorageOsDisk/fail2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2021-07-01",
"name": "fail-windows",
"location": "[resourceGroup().location]",
"properties": {
"hardwareProfile": {
"vmSize": "Standard_DS1_v2"
},
"storageProfile": {
"imageReference": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2019-Datacenter",
"version": "latest"
},
"dataDisks": [
{
"name": "mydatadisk1",
"caching": "ReadWrite",
"createOption": "Empty",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"vhd": {
"uri": "someURI"
}
}
]
},
"osProfile": {
"computerName": "hostname",
"adminUsername": "testadmin",
"adminPassword": "Password1234!"
ChanochShayner marked this conversation as resolved.
Show resolved Hide resolved
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', 'main')]"
}
]
}
},
"tags": {
"environment": "staging"
}
}
],
"parameters": {
"prefix": {
"type": "string",
"defaultValue": "myprefix"
}
}
}
54 changes: 54 additions & 0 deletions tests/arm/checks/resource/example_VMStorageOsDisk/pass.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2021-07-01",
"name": "pass-linux",
"location": "[resourceGroup().location]",
"properties": {
"hardwareProfile": {
"vmSize": "Standard_DS1_v2"
},
"storageProfile": {
"imageReference": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "16.04-LTS",
"version": "latest"
},
"osDisk": {
"name": "myosdisk1",
"caching": "ReadWrite",
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
}
}
},
"osProfile": {
"computerName": "hostname",
"adminUsername": "testadmin",
"adminPassword": "Password1234!"
ChanochShayner marked this conversation as resolved.
Show resolved Hide resolved
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', 'main')]"
}
]
}
},
"tags": {
"environment": "staging"
}
}
],
"parameters": {
"prefix": {
"type": "string",
"defaultValue": "myprefix"
}
}
}
54 changes: 54 additions & 0 deletions tests/arm/checks/resource/example_VMStorageOsDisk/pass2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2021-07-01",
"name": "pass-windows",
"location": "[resourceGroup().location]",
"properties": {
"hardwareProfile": {
"vmSize": "Standard_DS1_v2"
},
"storageProfile": {
"imageReference": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2019-Datacenter",
"version": "latest"
},
"osDisk": {
"name": "myosdisk2",
"caching": "ReadWrite",
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
}
}
},
"osProfile": {
"computerName": "hostname",
"adminUsername": "testadmin",
"adminPassword": "Password1234!"
ChanochShayner marked this conversation as resolved.
Show resolved Hide resolved
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', 'main')]"
}
]
}
},
"tags": {
"environment": "staging"
}
}
],
"parameters": {
"prefix": {
"type": "string",
"defaultValue": "myprefix"
}
}
}
44 changes: 44 additions & 0 deletions tests/arm/checks/resource/test_VMStorageOsDisk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import unittest
from pathlib import Path

from checkov.runner_filter import RunnerFilter
from checkov.arm.checks.resource.VMStorageOsDisk import check
from checkov.arm.runner import Runner


class TestVMStorageOsDisk(unittest.TestCase):

def test(self):
# given
test_files_dir = Path(__file__).parent / "example_VMStorageOsDisk"

# 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.pass-linux",
"Microsoft.Compute/virtualMachines.pass-windows",
}
failing_resources = {
"Microsoft.Compute/virtualMachines.fail-linux",
"Microsoft.Compute/virtualMachines.fail-windows",
}

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"], 2)
self.assertEqual(summary["failed"], 2)
self.assertEqual(summary["skipped"], 0)
self.assertEqual(summary["parsing_errors"], 0)
self.assertEqual(summary["resource_count"], 4) # 3 unknown

self.assertEqual(passing_resources, passed_check_resources)
self.assertEqual(failing_resources, failed_check_resources)


if __name__ == '__main__':
unittest.main()
Loading