Skip to content

Commit

Permalink
feat(azure): New check related with trusted launch in vm (#3616)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo966 authored and sergargar committed Apr 1, 2024
1 parent 364baac commit 0529a3f
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 1 deletion.
14 changes: 14 additions & 0 deletions prowler/providers/azure/services/vm/vm_service.py
Expand Up @@ -32,6 +32,7 @@ def __get_virtual_machines__(self):
resource_name=vm.name,
storage_profile=getattr(vm, "storage_profile", None),
location=vm.location,
security_profile=vm.security_profile,
)
}
)
Expand Down Expand Up @@ -78,12 +79,25 @@ def __get_disks__(self):
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
location: str
security_profile: SecurityProfile


@dataclass
Expand Down
Empty file.
@@ -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
Expand Up @@ -56,14 +56,21 @@ def test_vm_ensure_using_managed_disks(self):
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
location="location",
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=[],
),
)
),
}
}

Expand Down Expand Up @@ -100,6 +107,13 @@ def test_vm_using_not_managed_os_disk(self):
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
location="location",
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",
Expand Down Expand Up @@ -144,6 +158,13 @@ def test_vm_using_not_managed_data_disks(self):
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
location="location",
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",
Expand Down
26 changes: 26 additions & 0 deletions tests/providers/azure/services/vm/vm_service_test.py
@@ -1,3 +1,4 @@
from unittest import mock
from unittest.mock import patch

from azure.mgmt.compute.models import ManagedDiskParameters, OSDisk, StorageProfile
Expand All @@ -20,6 +21,13 @@ def mock_vm_get_virtual_machines(_):
resource_id="/subscriptions/resource_id",
resource_name="VMTest",
location="location",
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",
Expand Down Expand Up @@ -84,6 +92,24 @@ def test__get_virtual_machines(self):
].resource_name
== "VMTest"
)
assert (
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION_ID][
"vm_id-1"
].security_profile.security_type
== "TrustedLaunch"
)
assert (
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION_ID][
"vm_id-1"
].security_profile.uefi_settings.secure_boot_enabled
is True
)
assert (
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION_ID][
"vm_id-1"
].security_profile.uefi_settings.v_tpm_enabled
is True
)
assert (
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION_ID][
"vm_id-1"
Expand Down
@@ -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}"
)

0 comments on commit 0529a3f

Please sign in to comment.