feat(azure): New check related with trusted launch in vm (#3616)

This commit is contained in:
Hugo966
2024-03-27 12:32:42 +01:00
committed by GitHub
parent e2bb4d885c
commit 20abfc87e8
7 changed files with 251 additions and 1 deletions
@@ -31,6 +31,7 @@ class VirtualMachines(AzureService):
resource_id=vm.id,
resource_name=vm.name,
storage_profile=getattr(vm, "storage_profile", None),
security_profile=vm.security_profile,
)
}
)
@@ -76,11 +77,24 @@ class VirtualMachines(AzureService):
return disks
@dataclass
class UefiSettings:
secure_boot_enabled: bool
v_tpm_enabled: bool
@dataclass
class SecurityProfile:
security_type: str
uefi_settings: UefiSettings
@dataclass
class VirtualMachine:
resource_id: str
resource_name: str
storage_profile: StorageProfile
security_profile: SecurityProfile
@dataclass
@@ -0,0 +1,30 @@
{
"Provider": "azure",
"CheckID": "vm_trusted_launch_enabled",
"CheckTitle": "Ensure Trusted Launch is enabled on Virtual Machines",
"CheckType": [],
"ServiceName": "vm",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "Microsoft.Compute/virtualMachines",
"Description": "When Secure Boot and vTPM are enabled together, they provide a strong foundation for protecting your VM from boot attacks. For example, if an attacker attempts to replace the bootloader with a malicious version, Secure Boot will prevent the VM from booting. If the attacker is able to bypass Secure Boot and install a malicious bootloader, vTPM can be used to detect the intrusion and alert you.",
"Risk": "Secure Boot and vTPM work together to protect your VM from a variety of boot attacks, including bootkits, rootkits, and firmware rootkits. Not enabling Trusted Launch in Azure VM can lead to increased vulnerability to rootkits and boot-level malware, reduced ability to detect and prevent unauthorized changes to the boot process, and a potential compromise of system integrity and data security.",
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/virtual-machines/trusted-launch-existing-vm?tabs=portal",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "1. Go to Virtual Machines 2. For each VM, under Settings, click on Configuration on the left blade 3. Under Security Type, select 'Trusted Launch Virtual Machines' 4. Make sure Enable Secure Boot & Enable vTPM are checked 5. Click on Apply.",
"Url": "https://learn.microsoft.com/en-us/azure/virtual-machines/trusted-launch-existing-vm?tabs=portal#enable-trusted-launch-on-existing-vm"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Secure Boot and vTPM are not currently supported for Azure Generation 1 VMs. IMPORTANT: Before enabling Secure Boot and vTPM on a Generation 2 VM which does not already have both enabled, it is highly recommended to create a restore point of the VM prior to remediation."
}
@@ -0,0 +1,28 @@
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.vm.vm_client import vm_client
class vm_trusted_launch_enabled(Check):
def execute(self) -> Check_Report_Azure:
findings = []
for subscription_name, vms in vm_client.virtual_machines.items():
for vm_id, vm in vms.items():
report = Check_Report_Azure(self.metadata())
report.status = "FAIL"
report.subscription = subscription_name
report.resource_name = vm.resource_name
report.resource_id = vm_id
report.status_extended = f"VM {vm.resource_name} has trusted launch disabled in subscription {subscription_name}"
if (
vm.security_profile.security_type == "TrustedLaunch"
and vm.security_profile.uefi_settings.secure_boot_enabled
and vm.security_profile.uefi_settings.v_tpm_enabled
):
report.status = "PASS"
report.status_extended = f"VM {vm.resource_name} has trusted launch enabled in subscription {subscription_name}"
findings.append(report)
return findings
@@ -46,6 +46,13 @@ class Test_vm_ensure_using_managed_disks:
vm_id: VirtualMachine(
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
security_profile=mock.MagicMock(
security_type="TrustedLaunch",
uefi_settings=mock.MagicMock(
secure_boot_enabled=True,
v_tpm_enabled=True,
),
),
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
@@ -53,7 +60,7 @@ class Test_vm_ensure_using_managed_disks:
),
data_disks=[],
),
)
),
}
}
@@ -85,6 +92,13 @@ class Test_vm_ensure_using_managed_disks:
vm_id: VirtualMachine(
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
security_profile=mock.MagicMock(
security_type="TrustedLaunch",
uefi_settings=mock.MagicMock(
secure_boot_enabled=True,
v_tpm_enabled=True,
),
),
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
@@ -124,6 +138,13 @@ class Test_vm_ensure_using_managed_disks:
vm_id: VirtualMachine(
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
security_profile=mock.MagicMock(
security_type="TrustedLaunch",
uefi_settings=mock.MagicMock(
secure_boot_enabled=True,
v_tpm_enabled=True,
),
),
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
@@ -1,3 +1,4 @@
from unittest import mock
from unittest.mock import patch
from azure.mgmt.compute.models import ManagedDiskParameters, OSDisk, StorageProfile
@@ -19,6 +20,13 @@ def mock_vm_get_virtual_machines(_):
"vm_id-1": VirtualMachine(
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
security_profile=mock.MagicMock(
security_type="TrustedLaunch",
uefi_settings=mock.MagicMock(
secure_boot_enabled=True,
v_tpm_enabled=True,
),
),
storage_profile=StorageProfile(
os_disk=OSDisk(
create_option="FromImage",
@@ -77,6 +85,24 @@ class Test_AppInsights_Service:
].resource_name
== "VMTest"
)
assert (
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION][
"vm_id-1"
].security_profile.security_type
== "TrustedLaunch"
)
assert (
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION][
"vm_id-1"
].security_profile.uefi_settings.secure_boot_enabled
is True
)
assert (
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION][
"vm_id-1"
].security_profile.uefi_settings.v_tpm_enabled
is True
)
assert (
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION][
"vm_id-1"
@@ -0,0 +1,131 @@
from unittest import mock
from uuid import uuid4
from prowler.providers.azure.services.vm.vm_service import VirtualMachine
from tests.providers.azure.azure_fixtures import AZURE_SUBSCRIPTION
class Test_vm_trusted_launch_enabled:
def test_vm_no_subscriptions(self):
vm_client = mock.MagicMock
vm_client.virtual_machines = {}
with mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
):
from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import (
vm_trusted_launch_enabled,
)
check = vm_trusted_launch_enabled()
result = check.execute()
assert len(result) == 0
def test_vm_no_vm(self):
vm_client = mock.MagicMock
vm_client.virtual_machines = {AZURE_SUBSCRIPTION: {}}
with mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
):
from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import (
vm_trusted_launch_enabled,
)
check = vm_trusted_launch_enabled()
result = check.execute()
assert len(result) == 0
def test_vm_trusted_launch_enabled(self):
vm_id = str(uuid4())
vm_client = mock.MagicMock
vm_client.virtual_machines = {
AZURE_SUBSCRIPTION: {
vm_id: VirtualMachine(
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
security_profile=mock.MagicMock(
security_type="TrustedLaunch",
uefi_settings=mock.MagicMock(
secure_boot_enabled=True,
v_tpm_enabled=True,
),
),
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
managed_disk=mock.MagicMock(id="managed_disk_id"),
),
data_disks=[],
),
)
}
}
with mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
):
from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import (
vm_trusted_launch_enabled,
)
check = vm_trusted_launch_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].subscription == AZURE_SUBSCRIPTION
assert result[0].resource_name == "VMTest"
assert result[0].resource_id == vm_id
assert (
result[0].status_extended
== f"VM VMTest has trusted launch enabled in subscription {AZURE_SUBSCRIPTION}"
)
def test_vm_trusted_launch_disabled(self):
vm_id = str(uuid4())
vm_client = mock.MagicMock
vm_client.virtual_machines = {
AZURE_SUBSCRIPTION: {
vm_id: VirtualMachine(
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
security_profile=mock.MagicMock(
security_type="TrustedLaunch",
uefi_settings=mock.MagicMock(
secure_boot_enabled=False,
v_tpm_enabled=False,
),
),
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
managed_disk=mock.MagicMock(id="managed_disk_id"),
),
data_disks=[],
),
)
}
}
with mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
):
from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import (
vm_trusted_launch_enabled,
)
check = vm_trusted_launch_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert result[0].subscription == AZURE_SUBSCRIPTION
assert result[0].resource_name == "VMTest"
assert result[0].resource_id == vm_id
assert (
result[0].status_extended
== f"VM VMTest has trusted launch disabled in subscription {AZURE_SUBSCRIPTION}"
)