mirror of
https://github.com/prowler-cloud/prowler.git
synced 2025-12-19 05:17:47 +00:00
feat(azure/vm): add new check vm_desired_sku_size (#8191)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
committed by
GitHub
parent
285aea3458
commit
d9a9236ab7
@@ -78,7 +78,8 @@ The following list includes all the Azure checks with configurable variables tha
|
||||
| `app_ensure_python_version_is_latest` | `python_latest_version` | String |
|
||||
| `app_ensure_java_version_is_latest` | `java_latest_version` | String |
|
||||
| `sqlserver_recommended_minimal_tls_version` | `recommended_minimal_tls_versions` | List of Strings |
|
||||
| `defender_attack_path_notifications_properly_configured` | `defender_attack_path_minimal_risk_level` | String |
|
||||
| `vm_desired_sku_size` | `desired_vm_sku_sizes` | List of Strings |
|
||||
| `defender_attack_path_notifications_properly_configured` | `defender_attack_path_minimal_risk_level` | String |
|
||||
|
||||
|
||||
## GCP
|
||||
@@ -481,6 +482,16 @@ azure:
|
||||
"1.3"
|
||||
]
|
||||
|
||||
# Azure Virtual Machines
|
||||
# azure.vm_desired_sku_size
|
||||
# List of desired VM SKU sizes that are allowed in the organization
|
||||
desired_vm_sku_sizes:
|
||||
[
|
||||
"Standard_A8_v2",
|
||||
"Standard_DS3_v2",
|
||||
"Standard_D4s_v3",
|
||||
]
|
||||
|
||||
# GCP Configuration
|
||||
gcp:
|
||||
# GCP Compute Configuration
|
||||
|
||||
@@ -8,6 +8,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `bedrock_api_key_no_administrative_privileges` check for AWS provider [(#8321)](https://github.com/prowler-cloud/prowler/pull/8321)
|
||||
- Support App Key Content in GitHub provider [(#8271)](https://github.com/prowler-cloud/prowler/pull/8271)
|
||||
- CIS 4.0 for the Azure provider [(#7782)](https://github.com/prowler-cloud/prowler/pull/7782)
|
||||
- `vm_desired_sku_size` check for Azure provider [(#8191)](https://github.com/prowler-cloud/prowler/pull/8191)
|
||||
|
||||
### Changed
|
||||
- Handle some AWS errors as warnings instead of errors [(#8347)](https://github.com/prowler-cloud/prowler/pull/8347)
|
||||
|
||||
@@ -450,6 +450,16 @@ azure:
|
||||
"1.3",
|
||||
]
|
||||
|
||||
# Azure Virtual Machines
|
||||
# azure.vm_desired_sku_size
|
||||
# List of desired VM SKU sizes that are allowed in the organization
|
||||
desired_vm_sku_sizes:
|
||||
[
|
||||
"Standard_A8_v2",
|
||||
"Standard_DS3_v2",
|
||||
"Standard_D4s_v3",
|
||||
]
|
||||
|
||||
# GCP Configuration
|
||||
gcp:
|
||||
# GCP Compute Configuration
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "vm_desired_sku_size",
|
||||
"CheckTitle": "Ensure that your virtual machine instances are using SKU sizes that are approved by your organization",
|
||||
"CheckType": [],
|
||||
"ServiceName": "vm",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Microsoft.Compute/virtualMachines",
|
||||
"Description": "Ensure that your virtual machine instances are using SKU sizes that are approved by your organization. This check requires configuration of the desired VM SKU sizes in the Prowler configuration file.",
|
||||
"Risk": "Setting limits for the SKU size(s) of the virtual machine instances provisioned in your Microsoft Azure account can help you to manage better your cloud compute power, address internal compliance requirements and prevent unexpected charges on your Azure monthly bill. Without proper SKU size controls, organizations may face cost overruns and compliance violations.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/virtual-machines/sizes/overview",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az policy assignment create --display-name 'Allowed VM SKU Sizes' --policy cccc23c7-8427-4f53-ad12-b6a63eb452b3 -p '{\"listOfAllowedSKUs\": {\"value\": [\"<desired-sku-1>\", \"<desired-sku-2>\"]}}' --scope /subscriptions/<subscription-id>",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "1. Define and document your organization's approved VM SKU sizes based on workload requirements, cost constraints, and compliance needs. 2. Implement Azure Policy to enforce VM size restrictions across your subscriptions. 3. Use the 'Allowed virtual machine size SKUs' built-in policy to restrict VM creation to approved sizes. 4. Regularly review and update your approved SKU list based on changing business requirements and cost optimization goals. 5. Monitor VM usage and costs to ensure compliance with your SKU size policies.",
|
||||
"Url": "https://learn.microsoft.com/en-us/azure/virtual-machines/sizes/resize-vm"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "This check requires configuration of the desired VM SKU sizes in the Prowler configuration file. Configure the azure.desired_vm_sku_sizes list in your Prowler configuration file (see https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/configuration_file/) with the SKU sizes approved by your organization."
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.vm.vm_client import vm_client
|
||||
|
||||
|
||||
class vm_desired_sku_size(Check):
|
||||
"""
|
||||
Ensure that Azure virtual machines are using SKU sizes that are approved by your organization.
|
||||
|
||||
This check evaluates whether each virtual machine's SKU size is included in the organization's approved list of VM sizes.
|
||||
The approved SKU sizes are configured in the Prowler configuration file under azure.desired_vm_sku_sizes.
|
||||
- PASS: The VM is using a SKU size that is approved by the organization.
|
||||
- FAIL: The VM is using a SKU size that is not approved by the organization.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[Check_Report_Azure]:
|
||||
"""
|
||||
Execute the check to verify that virtual machines are using desired SKU sizes.
|
||||
|
||||
Returns:
|
||||
A list of check reports for each virtual machine
|
||||
"""
|
||||
|
||||
findings = []
|
||||
|
||||
# Get the desired SKU sizes from configuration
|
||||
DESIRED_SKU_SIZES = vm_client.audit_config.get(
|
||||
"desired_vm_sku_sizes",
|
||||
[
|
||||
"Standard_A8_v2",
|
||||
"Standard_DS3_v2",
|
||||
"Standard_D4s_v3",
|
||||
],
|
||||
)
|
||||
|
||||
for subscription_name, vms in vm_client.virtual_machines.items():
|
||||
for vm in vms.values():
|
||||
report = Check_Report_Azure(metadata=self.metadata(), resource=vm)
|
||||
report.subscription = subscription_name
|
||||
|
||||
if vm.vm_size in DESIRED_SKU_SIZES:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"VM {vm.resource_name} is using desired SKU size {vm.vm_size} in subscription {subscription_name}."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"VM {vm.resource_name} is using {vm.vm_size} which is not a desired SKU size in subscription {subscription_name}."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -75,6 +75,30 @@ class VirtualMachines(AzureService):
|
||||
)
|
||||
)
|
||||
|
||||
# Convert Azure SDK SecurityProfile to custom SecurityProfile dataclass
|
||||
azure_security_profile = getattr(vm, "security_profile", None)
|
||||
security_profile = None
|
||||
if azure_security_profile:
|
||||
uefi_settings = None
|
||||
azure_uefi_settings = getattr(
|
||||
azure_security_profile, "uefi_settings", None
|
||||
)
|
||||
if azure_uefi_settings:
|
||||
uefi_settings = UefiSettings(
|
||||
secure_boot_enabled=getattr(
|
||||
azure_uefi_settings, "secure_boot_enabled", False
|
||||
),
|
||||
v_tpm_enabled=getattr(
|
||||
azure_uefi_settings, "v_tpm_enabled", False
|
||||
),
|
||||
)
|
||||
security_profile = SecurityProfile(
|
||||
security_type=getattr(
|
||||
azure_security_profile, "security_type", None
|
||||
),
|
||||
uefi_settings=uefi_settings,
|
||||
)
|
||||
|
||||
virtual_machines[subscription_name].update(
|
||||
{
|
||||
vm.id: VirtualMachine(
|
||||
@@ -103,8 +127,13 @@ class VirtualMachines(AzureService):
|
||||
else None
|
||||
),
|
||||
location=vm.location,
|
||||
security_profile=getattr(vm, "security_profile", None),
|
||||
security_profile=security_profile,
|
||||
extensions=extensions,
|
||||
vm_size=getattr(
|
||||
getattr(vm, "hardware_profile", None),
|
||||
"vm_size",
|
||||
None,
|
||||
),
|
||||
image_reference=getattr(
|
||||
getattr(storage_profile, "image_reference", None),
|
||||
"id",
|
||||
@@ -273,6 +302,7 @@ class VirtualMachine(BaseModel):
|
||||
security_profile: Optional[SecurityProfile]
|
||||
extensions: list[VirtualMachineExtension]
|
||||
storage_profile: Optional[StorageProfile] = None
|
||||
vm_size: Optional[str] = None
|
||||
image_reference: Optional[str] = None
|
||||
linux_configuration: Optional[LinuxConfiguration] = None
|
||||
|
||||
|
||||
@@ -321,6 +321,11 @@ config_azure = {
|
||||
"python_latest_version": "3.12",
|
||||
"java_latest_version": "17",
|
||||
"recommended_minimal_tls_versions": ["1.2", "1.3"],
|
||||
"desired_vm_sku_sizes": [
|
||||
"Standard_A8_v2",
|
||||
"Standard_DS3_v2",
|
||||
"Standard_D4s_v3",
|
||||
],
|
||||
"defender_attack_path_minimal_risk_level": "High",
|
||||
}
|
||||
|
||||
|
||||
@@ -395,6 +395,16 @@ azure:
|
||||
"1.3"
|
||||
]
|
||||
|
||||
# Azure Virtual Machines
|
||||
# azure.vm_desired_sku_size
|
||||
# List of desired VM SKU sizes that are allowed in the organization
|
||||
desired_vm_sku_sizes:
|
||||
[
|
||||
"Standard_A8_v2",
|
||||
"Standard_DS3_v2",
|
||||
"Standard_D4s_v3",
|
||||
]
|
||||
|
||||
# GCP Configuration
|
||||
gcp:
|
||||
# GCP Compute Configuration
|
||||
|
||||
@@ -85,6 +85,11 @@ class TestAzureProvider:
|
||||
"python_latest_version": "3.12",
|
||||
"java_latest_version": "17",
|
||||
"recommended_minimal_tls_versions": ["1.2", "1.3"],
|
||||
"desired_vm_sku_sizes": [
|
||||
"Standard_A8_v2",
|
||||
"Standard_DS3_v2",
|
||||
"Standard_D4s_v3",
|
||||
],
|
||||
"defender_attack_path_minimal_risk_level": "High",
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,660 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from prowler.providers.azure.services.vm.vm_service import (
|
||||
SecurityProfile,
|
||||
StorageProfile,
|
||||
UefiSettings,
|
||||
VirtualMachine,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_vm_desired_sku_size:
|
||||
def test_vm_no_subscriptions(self):
|
||||
"""Test when there are no subscriptions."""
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {}
|
||||
vm_client.audit_config = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_vm_subscriptions_empty(self):
|
||||
"""Test when subscriptions exist but have no VMs."""
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {AZURE_SUBSCRIPTION_ID: {}}
|
||||
vm_client.audit_config = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_vm_using_desired_sku_size_default_config(self):
|
||||
"""Test VM using a SKU size that is in the default configuration."""
|
||||
vm_id = str(uuid4())
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id: VirtualMachine(
|
||||
resource_id=vm_id,
|
||||
resource_name="VMTest",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_A8_v2",
|
||||
),
|
||||
}
|
||||
}
|
||||
vm_client.audit_config = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "VMTest"
|
||||
assert result[0].resource_id == vm_id
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"VM VMTest is using desired SKU size Standard_A8_v2 in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
def test_vm_using_desired_sku_size_custom_config(self):
|
||||
"""Test VM using a SKU size that is in the custom configuration."""
|
||||
vm_id = str(uuid4())
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id: VirtualMachine(
|
||||
resource_id=vm_id,
|
||||
resource_name="VMTest",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_B1s",
|
||||
),
|
||||
}
|
||||
}
|
||||
vm_client.audit_config = {
|
||||
"desired_vm_sku_sizes": ["Standard_B1s", "Standard_B2s"]
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "VMTest"
|
||||
assert result[0].resource_id == vm_id
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"VM VMTest is using desired SKU size Standard_B1s in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
def test_vm_using_non_desired_sku_size_default_config(self):
|
||||
"""Test VM using a SKU size that is not in the default configuration."""
|
||||
vm_id = str(uuid4())
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id: VirtualMachine(
|
||||
resource_id=vm_id,
|
||||
resource_name="VMTest",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_B1s",
|
||||
),
|
||||
}
|
||||
}
|
||||
vm_client.audit_config = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "VMTest"
|
||||
assert result[0].resource_id == vm_id
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"VM VMTest is using Standard_B1s which is not a desired SKU size in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
def test_vm_using_non_desired_sku_size_custom_config(self):
|
||||
"""Test VM using a SKU size that is not in the custom configuration."""
|
||||
vm_id = str(uuid4())
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id: VirtualMachine(
|
||||
resource_id=vm_id,
|
||||
resource_name="VMTest",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_A8_v2",
|
||||
),
|
||||
}
|
||||
}
|
||||
vm_client.audit_config = {
|
||||
"desired_vm_sku_sizes": ["Standard_B1s", "Standard_B2s"]
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "VMTest"
|
||||
assert result[0].resource_id == vm_id
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"VM VMTest is using Standard_A8_v2 which is not a desired SKU size in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
def test_vm_with_none_vm_size(self):
|
||||
"""Test VM with None vm_size."""
|
||||
vm_id = str(uuid4())
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id: VirtualMachine(
|
||||
resource_id=vm_id,
|
||||
resource_name="VMTest",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size=None,
|
||||
),
|
||||
}
|
||||
}
|
||||
vm_client.audit_config = {"desired_vm_sku_sizes": ["Standard_A8_v2"]}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "VMTest"
|
||||
assert result[0].resource_id == vm_id
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"VM VMTest is using None which is not a desired SKU size in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
def test_multiple_vms_different_statuses(self):
|
||||
"""Test multiple VMs with different statuses."""
|
||||
vm_id_1 = str(uuid4())
|
||||
vm_id_2 = str(uuid4())
|
||||
vm_id_3 = str(uuid4())
|
||||
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id_1: VirtualMachine(
|
||||
resource_id=vm_id_1,
|
||||
resource_name="VMApproved",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_A8_v2",
|
||||
),
|
||||
vm_id_2: VirtualMachine(
|
||||
resource_id=vm_id_2,
|
||||
resource_name="VMNotApproved",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_B1s",
|
||||
),
|
||||
vm_id_3: VirtualMachine(
|
||||
resource_id=vm_id_3,
|
||||
resource_name="VMAnotherApproved",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_DS3_v2",
|
||||
),
|
||||
}
|
||||
}
|
||||
vm_client.audit_config = {
|
||||
"desired_vm_sku_sizes": ["Standard_A8_v2", "Standard_DS3_v2"]
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 3
|
||||
|
||||
# Find the PASS result
|
||||
pass_result = next(
|
||||
r
|
||||
for r in result
|
||||
if r.status == "PASS" and r.resource_name == "VMApproved"
|
||||
)
|
||||
assert pass_result.subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert pass_result.resource_id == vm_id_1
|
||||
assert (
|
||||
pass_result.status_extended
|
||||
== f"VM VMApproved is using desired SKU size Standard_A8_v2 in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
# Find the FAIL result
|
||||
fail_result = next(
|
||||
r
|
||||
for r in result
|
||||
if r.status == "FAIL" and r.resource_name == "VMNotApproved"
|
||||
)
|
||||
assert fail_result.subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert fail_result.resource_id == vm_id_2
|
||||
assert (
|
||||
fail_result.status_extended
|
||||
== f"VM VMNotApproved is using Standard_B1s which is not a desired SKU size in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
# Find the second PASS result
|
||||
pass_result_2 = next(
|
||||
r
|
||||
for r in result
|
||||
if r.status == "PASS" and r.resource_name == "VMAnotherApproved"
|
||||
)
|
||||
assert pass_result_2.subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert pass_result_2.resource_id == vm_id_3
|
||||
assert (
|
||||
pass_result_2.status_extended
|
||||
== f"VM VMAnotherApproved is using desired SKU size Standard_DS3_v2 in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
def test_multiple_subscriptions(self):
|
||||
"""Test multiple subscriptions with different VMs."""
|
||||
vm_id_1 = str(uuid4())
|
||||
vm_id_2 = str(uuid4())
|
||||
subscription_2 = "subscription-2"
|
||||
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id_1: VirtualMachine(
|
||||
resource_id=vm_id_1,
|
||||
resource_name="VMSub1",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_A8_v2",
|
||||
),
|
||||
},
|
||||
subscription_2: {
|
||||
vm_id_2: VirtualMachine(
|
||||
resource_id=vm_id_2,
|
||||
resource_name="VMSub2",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_B1s",
|
||||
),
|
||||
},
|
||||
}
|
||||
vm_client.audit_config = {"desired_vm_sku_sizes": ["Standard_A8_v2"]}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
# Find the PASS result from subscription 1
|
||||
pass_result = next(
|
||||
r
|
||||
for r in result
|
||||
if r.status == "PASS" and r.subscription == AZURE_SUBSCRIPTION_ID
|
||||
)
|
||||
assert pass_result.resource_name == "VMSub1"
|
||||
assert pass_result.resource_id == vm_id_1
|
||||
|
||||
# Find the FAIL result from subscription 2
|
||||
fail_result = next(
|
||||
r
|
||||
for r in result
|
||||
if r.status == "FAIL" and r.subscription == subscription_2
|
||||
)
|
||||
assert fail_result.resource_name == "VMSub2"
|
||||
assert fail_result.resource_id == vm_id_2
|
||||
|
||||
def test_empty_desired_sku_sizes_config(self):
|
||||
"""Test when the desired SKU sizes configuration is empty."""
|
||||
vm_id = str(uuid4())
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id: VirtualMachine(
|
||||
resource_id=vm_id,
|
||||
resource_name="VMTest",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_A8_v2",
|
||||
),
|
||||
}
|
||||
}
|
||||
vm_client.audit_config = {"desired_vm_sku_sizes": []}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "VMTest"
|
||||
assert result[0].resource_id == vm_id
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"VM VMTest is using Standard_A8_v2 which is not a desired SKU size in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
|
||||
def test_case_sensitive_sku_size_matching(self):
|
||||
"""Test that SKU size matching is case sensitive."""
|
||||
vm_id = str(uuid4())
|
||||
vm_client = mock.MagicMock
|
||||
vm_client.virtual_machines = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
vm_id: VirtualMachine(
|
||||
resource_id=vm_id,
|
||||
resource_name="VMTest",
|
||||
location="location",
|
||||
security_profile=SecurityProfile(
|
||||
security_type="TrustedLaunch",
|
||||
uefi_settings=UefiSettings(
|
||||
secure_boot_enabled=True,
|
||||
v_tpm_enabled=True,
|
||||
),
|
||||
),
|
||||
extensions=[],
|
||||
storage_profile=StorageProfile(
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="standard_a8_v2", # lowercase
|
||||
),
|
||||
}
|
||||
}
|
||||
vm_client.audit_config = {
|
||||
"desired_vm_sku_sizes": ["Standard_A8_v2"]
|
||||
} # proper case
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size.vm_client",
|
||||
new=vm_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.vm.vm_desired_sku_size.vm_desired_sku_size import (
|
||||
vm_desired_sku_size,
|
||||
)
|
||||
|
||||
check = vm_desired_sku_size()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL" # Should fail due to case mismatch
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "VMTest"
|
||||
assert result[0].resource_id == vm_id
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"VM VMTest is using standard_a8_v2 which is not a desired SKU size in subscription {AZURE_SUBSCRIPTION_ID}."
|
||||
)
|
||||
@@ -41,6 +41,7 @@ def mock_vm_get_virtual_machines(_):
|
||||
),
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_A8_v2",
|
||||
linux_configuration=None,
|
||||
)
|
||||
}
|
||||
@@ -57,6 +58,7 @@ def mock_vm_get_virtual_machines_with_none(_):
|
||||
security_profile=None,
|
||||
extensions=[],
|
||||
storage_profile=None,
|
||||
vm_size=None,
|
||||
linux_configuration=None,
|
||||
),
|
||||
"vm_id-2": VirtualMachine(
|
||||
@@ -69,6 +71,7 @@ def mock_vm_get_virtual_machines_with_none(_):
|
||||
os_disk=None,
|
||||
data_disks=[],
|
||||
),
|
||||
vm_size="Standard_B1s",
|
||||
linux_configuration=None,
|
||||
),
|
||||
}
|
||||
@@ -177,6 +180,10 @@ class Test_VirtualMachines_Service:
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert (
|
||||
virtual_machines.virtual_machines[AZURE_SUBSCRIPTION_ID]["vm_id-1"].vm_size
|
||||
== "Standard_A8_v2"
|
||||
)
|
||||
|
||||
def test__get_disks(self):
|
||||
disks = VirtualMachines(set_mocked_azure_provider()).disks
|
||||
|
||||
Reference in New Issue
Block a user