mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-09 21:14:22 +00:00
feat(openstack): Add 7 New Compute Security Checks (#9944)
This commit is contained in:
+229
@@ -0,0 +1,229 @@
|
||||
"""Tests for compute_instance_config_drive_enabled check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.compute.compute_service import ComputeInstance
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_compute_instance_config_drive_enabled:
|
||||
"""Test suite for compute_instance_config_drive_enabled check."""
|
||||
|
||||
def test_no_instances(self):
|
||||
"""Test when no instances exist."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_config_drive_enabled.compute_instance_config_drive_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_config_drive_enabled.compute_instance_config_drive_enabled import (
|
||||
compute_instance_config_drive_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_config_drive_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_with_config_drive(self):
|
||||
"""Test instance with config drive enabled (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-1",
|
||||
name="ConfigDrive Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=True,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_config_drive_enabled.compute_instance_config_drive_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_config_drive_enabled.compute_instance_config_drive_enabled import (
|
||||
compute_instance_config_drive_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_config_drive_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance ConfigDrive Instance (instance-1) has config drive enabled for secure metadata injection."
|
||||
)
|
||||
assert result[0].resource_id == "instance-1"
|
||||
assert result[0].resource_name == "ConfigDrive Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_without_config_drive(self):
|
||||
"""Test instance without config drive (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-2",
|
||||
name="No ConfigDrive",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_config_drive_enabled.compute_instance_config_drive_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_config_drive_enabled.compute_instance_config_drive_enabled import (
|
||||
compute_instance_config_drive_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_config_drive_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance No ConfigDrive (instance-2) does not have config drive enabled (relies on metadata service)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-2"
|
||||
assert result[0].resource_name == "No ConfigDrive"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_multiple_instances_mixed(self):
|
||||
"""Test multiple instances with mixed config drive status."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-pass",
|
||||
name="Pass",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=True,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
ComputeInstance(
|
||||
id="instance-fail",
|
||||
name="Fail",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_config_drive_enabled.compute_instance_config_drive_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_config_drive_enabled.compute_instance_config_drive_enabled import (
|
||||
compute_instance_config_drive_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_config_drive_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert len([r for r in result if r.status == "PASS"]) == 1
|
||||
assert len([r for r in result if r.status == "FAIL"]) == 1
|
||||
+601
@@ -0,0 +1,601 @@
|
||||
"""Tests for compute_instance_isolated_private_network check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.compute.compute_service import ComputeInstance
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_compute_instance_isolated_private_network:
|
||||
"""Test suite for compute_instance_isolated_private_network check."""
|
||||
|
||||
def test_no_instances(self):
|
||||
"""Test when no instances exist."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_private_only(self):
|
||||
"""Test instance with private IP only (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-1",
|
||||
name="Isolated Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.5",
|
||||
private_v6="",
|
||||
networks={"private": ["10.0.0.5"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Isolated Instance (instance-1) is properly isolated in private network with private IPs (10.0.0.5) and no public exposure."
|
||||
)
|
||||
assert result[0].resource_id == "instance-1"
|
||||
assert result[0].resource_name == "Isolated Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_mixed_public_private(self):
|
||||
"""Test instance with both public and private IPs (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-2",
|
||||
name="Mixed Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="8.8.4.4",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.10",
|
||||
private_v6="",
|
||||
networks={"public": ["8.8.4.4"], "private": ["10.0.0.10"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Mixed Instance (instance-2) has mixed public and private network exposure (not properly isolated)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-2"
|
||||
assert result[0].resource_name == "Mixed Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_public_only(self):
|
||||
"""Test instance with only public IP (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-3",
|
||||
name="Public Only",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="1.1.1.1",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={"public": ["1.1.1.1"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Public Only (instance-3) has only public IP addresses (no private network isolation)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-3"
|
||||
assert result[0].resource_name == "Public Only"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_no_ips(self):
|
||||
"""Test instance with no IPs (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-4",
|
||||
name="No IPs",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance No IPs (instance-4) has no network configuration (no IPs assigned)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-4"
|
||||
assert result[0].resource_name == "No IPs"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_private_ipv6_only(self):
|
||||
"""Test instance with private IPv6 only (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-5",
|
||||
name="IPv6 Private",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="fd00::1",
|
||||
networks={"private": ["fd00::1"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance IPv6 Private (instance-5) is properly isolated in private network with private IPs (fd00::1) and no public exposure."
|
||||
)
|
||||
assert result[0].resource_id == "instance-5"
|
||||
assert result[0].resource_name == "IPv6 Private"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_fallback_private_only_networks_dict(self):
|
||||
"""Test fallback logic: instance with private IP populated by service from networks dict."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-fallback-1",
|
||||
name="Private Fallback",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="", # Empty
|
||||
access_ipv6="", # Empty
|
||||
public_v4="", # Empty
|
||||
public_v6="", # Empty
|
||||
private_v4="10.99.1.207", # Populated by service fallback
|
||||
private_v6="", # Empty
|
||||
networks={"test-private-net": ["10.99.1.207"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert "10.99.1.207" in result[0].status_extended
|
||||
assert "properly isolated in private network" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-fallback-1"
|
||||
|
||||
def test_instance_fallback_public_only_networks_dict(self):
|
||||
"""Test fallback logic: instance with public IP populated by service from networks dict."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-fallback-2",
|
||||
name="Public Fallback",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="8.8.8.8", # Populated by service fallback
|
||||
public_v6="", # Empty
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={"ext-net": ["8.8.8.8"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
"only public IP addresses" in result[0].status_extended
|
||||
or "no private network isolation" in result[0].status_extended
|
||||
)
|
||||
assert result[0].resource_id == "instance-fallback-2"
|
||||
|
||||
def test_instance_fallback_mixed_networks_dict(self):
|
||||
"""Test fallback logic: instance with mixed IPs populated by service from networks dict."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-fallback-3",
|
||||
name="Mixed Fallback",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="8.8.8.8", # Populated by service fallback
|
||||
public_v6="", # Empty
|
||||
private_v4="10.0.0.100", # Populated by service fallback
|
||||
private_v6="", # Empty
|
||||
networks={
|
||||
"private-net": ["10.0.0.100"],
|
||||
"ext-net": ["8.8.8.8"],
|
||||
},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
"mixed public and private network exposure" in result[0].status_extended
|
||||
)
|
||||
assert result[0].resource_id == "instance-fallback-3"
|
||||
|
||||
def test_instance_access_ipv4_private_treated_as_private(self):
|
||||
"""Test that access_ipv4 set to a private IP is not treated as public exposure."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-access-priv",
|
||||
name="Access Private",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="10.0.0.50",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.50",
|
||||
private_v6="",
|
||||
networks={"private-net": ["10.0.0.50"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert "properly isolated in private network" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-access-priv"
|
||||
|
||||
def test_instance_network_ips_validated_as_public(self):
|
||||
"""Test that IPs from networks dict are validated as truly public."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-net-pub",
|
||||
name="Network Public",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={
|
||||
"my-net": ["10.0.0.5", "8.8.8.8"],
|
||||
},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_isolated_private_network.compute_instance_isolated_private_network import (
|
||||
compute_instance_isolated_private_network,
|
||||
)
|
||||
|
||||
check = compute_instance_isolated_private_network()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
"mixed public and private network exposure" in result[0].status_extended
|
||||
)
|
||||
assert result[0].resource_id == "instance-net-pub"
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
"""Tests for compute_instance_key_based_authentication check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.compute.compute_service import ComputeInstance
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_compute_instance_key_based_authentication:
|
||||
"""Test suite for compute_instance_key_based_authentication check."""
|
||||
|
||||
def test_no_instances(self):
|
||||
"""Test when no instances exist."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_key_based_authentication.compute_instance_key_based_authentication.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_key_based_authentication.compute_instance_key_based_authentication import (
|
||||
compute_instance_key_based_authentication,
|
||||
)
|
||||
|
||||
check = compute_instance_key_based_authentication()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_with_keypair(self):
|
||||
"""Test instance with SSH keypair configured (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-1",
|
||||
name="Secure Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="my-production-keypair",
|
||||
user_id="user-123",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.5",
|
||||
private_v6="",
|
||||
networks={"private": ["10.0.0.5"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_key_based_authentication.compute_instance_key_based_authentication.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_key_based_authentication.compute_instance_key_based_authentication import (
|
||||
compute_instance_key_based_authentication,
|
||||
)
|
||||
|
||||
check = compute_instance_key_based_authentication()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Secure Instance (instance-1) is configured with SSH key-based authentication (keypair: my-production-keypair)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-1"
|
||||
assert result[0].resource_name == "Secure Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_without_keypair(self):
|
||||
"""Test instance without SSH keypair (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-2",
|
||||
name="Insecure Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="user-456",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.10",
|
||||
private_v6="",
|
||||
networks={"private": ["10.0.0.10"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_key_based_authentication.compute_instance_key_based_authentication.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_key_based_authentication.compute_instance_key_based_authentication import (
|
||||
compute_instance_key_based_authentication,
|
||||
)
|
||||
|
||||
check = compute_instance_key_based_authentication()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Insecure Instance (instance-2) does not have SSH key-based authentication configured (no keypair assigned)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-2"
|
||||
assert result[0].resource_name == "Insecure Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_multiple_instances_mixed(self):
|
||||
"""Test multiple instances with mixed keypair configuration."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-secure",
|
||||
name="With Key",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="prod-keypair",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
ComputeInstance(
|
||||
id="instance-insecure",
|
||||
name="Without Key",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_key_based_authentication.compute_instance_key_based_authentication.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_key_based_authentication.compute_instance_key_based_authentication import (
|
||||
compute_instance_key_based_authentication,
|
||||
)
|
||||
|
||||
check = compute_instance_key_based_authentication()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert len([r for r in result if r.status == "PASS"]) == 1
|
||||
assert len([r for r in result if r.status == "FAIL"]) == 1
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
"""Tests for compute_instance_locked_status_enabled check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.compute.compute_service import ComputeInstance
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_compute_instance_locked_status_enabled:
|
||||
"""Test suite for compute_instance_locked_status_enabled check."""
|
||||
|
||||
def test_no_instances(self):
|
||||
"""Test when no instances exist."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled import (
|
||||
compute_instance_locked_status_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_locked_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_locked_with_reason(self):
|
||||
"""Test instance with locked status enabled and reason (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-1",
|
||||
name="Locked Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=True,
|
||||
locked_reason="Production instance - do not modify",
|
||||
key_name="my-keypair",
|
||||
user_id="user-123",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.5",
|
||||
private_v6="",
|
||||
networks={"private": ["10.0.0.5"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled import (
|
||||
compute_instance_locked_status_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_locked_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Locked Instance (instance-1) has locked status enabled (reason: Production instance - do not modify)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-1"
|
||||
assert result[0].resource_name == "Locked Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_locked_without_reason(self):
|
||||
"""Test instance with locked status enabled but no reason (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-2",
|
||||
name="Locked No Reason",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=True,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled import (
|
||||
compute_instance_locked_status_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_locked_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Locked No Reason (instance-2) has locked status enabled."
|
||||
)
|
||||
assert result[0].resource_id == "instance-2"
|
||||
assert result[0].resource_name == "Locked No Reason"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_not_locked(self):
|
||||
"""Test instance without locked status (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-3",
|
||||
name="Unlocked Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled import (
|
||||
compute_instance_locked_status_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_locked_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Unlocked Instance (instance-3) does not have locked status enabled."
|
||||
)
|
||||
assert result[0].resource_id == "instance-3"
|
||||
assert result[0].resource_name == "Unlocked Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_multiple_instances_mixed(self):
|
||||
"""Test multiple instances with mixed locked status."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-locked",
|
||||
name="Locked",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=True,
|
||||
locked_reason="Protected",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
ComputeInstance(
|
||||
id="instance-unlocked",
|
||||
name="Unlocked",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_locked_status_enabled.compute_instance_locked_status_enabled import (
|
||||
compute_instance_locked_status_enabled,
|
||||
)
|
||||
|
||||
check = compute_instance_locked_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert len([r for r in result if r.status == "PASS"]) == 1
|
||||
assert len([r for r in result if r.status == "FAIL"]) == 1
|
||||
+576
@@ -0,0 +1,576 @@
|
||||
"""Tests for compute_instance_metadata_sensitive_data check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.compute.compute_service import ComputeInstance
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_compute_instance_metadata_sensitive_data:
|
||||
"""Test suite for compute_instance_metadata_sensitive_data check."""
|
||||
|
||||
def test_no_instances(self):
|
||||
"""Test when no instances exist."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = []
|
||||
compute_client.audit_config = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_no_metadata(self):
|
||||
"""Test instance with no metadata (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-1",
|
||||
name="No Metadata",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance No Metadata (instance-1) has no metadata (no sensitive data exposure risk)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-1"
|
||||
assert result[0].resource_name == "No Metadata"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_safe_metadata(self):
|
||||
"""Test instance with safe metadata (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-2",
|
||||
name="Safe Metadata",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={"environment": "production", "application": "web-app"},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Safe Metadata (instance-2) metadata does not contain sensitive data."
|
||||
)
|
||||
assert result[0].resource_id == "instance-2"
|
||||
assert result[0].resource_name == "Safe Metadata"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_password_in_metadata(self):
|
||||
"""Test instance with password in metadata (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-3",
|
||||
name="Password Metadata",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={"db_password": "supersecret123"},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "contains potential secrets" in result[0].status_extended
|
||||
|
||||
def test_instance_api_key_in_metadata(self):
|
||||
"""Test instance with API key in metadata (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-4",
|
||||
name="API Key Metadata",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={"api_key": "sk-1234567890"},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status_extended.startswith(
|
||||
"Instance API Key Metadata (instance-4) metadata contains potential secrets ->"
|
||||
)
|
||||
assert result[0].resource_id == "instance-4"
|
||||
assert result[0].resource_name == "API Key Metadata"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_connection_string_in_metadata(self):
|
||||
"""Test instance with database connection string in metadata (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-5",
|
||||
name="Connection String",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={"db_url": "mysql://admin:s3cret@dbhost:3306/appdb"},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status_extended.startswith(
|
||||
"Instance Connection String (instance-5) metadata contains potential secrets ->"
|
||||
)
|
||||
assert result[0].resource_id == "instance-5"
|
||||
assert result[0].resource_name == "Connection String"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_private_key_in_metadata(self):
|
||||
"""Test instance with private key in metadata (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-6",
|
||||
name="Private Key",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={"ssh_key": "-----BEGIN RSA PRIVATE KEY-----"},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status_extended.startswith(
|
||||
"Instance Private Key (instance-6) metadata contains potential secrets ->"
|
||||
)
|
||||
assert result[0].resource_id == "instance-6"
|
||||
assert result[0].resource_name == "Private Key"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_multiple_instances_mixed(self):
|
||||
"""Test multiple instances with mixed metadata."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-pass",
|
||||
name="Safe",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={"tier": "web"},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
ComputeInstance(
|
||||
id="instance-fail",
|
||||
name="Unsafe",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={"admin_password": "secret123"},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert len([r for r in result if r.status == "PASS"]) == 1
|
||||
assert len([r for r in result if r.status == "FAIL"]) == 1
|
||||
|
||||
def test_instance_multiple_metadata_keys_correct_identification(self):
|
||||
"""Test that secrets are correctly attributed to the right metadata keys."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-7",
|
||||
name="Multiple Keys",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={
|
||||
"environment": "production",
|
||||
"application": "web-app",
|
||||
"db_password": "supersecret123",
|
||||
"region": "us-east",
|
||||
},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
# Verify the secret is correctly attributed to 'db_password' key
|
||||
assert "in metadata key 'db_password'" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-7"
|
||||
|
||||
def test_instance_metadata_key_ordering(self):
|
||||
"""Test that secret detection works with different key orderings."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.audit_config = {}
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-8",
|
||||
name="Ordered Keys",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={
|
||||
"first_key": "safe_value",
|
||||
"api_key": "sk-1234567890abcdef",
|
||||
"third_key": "also_safe",
|
||||
},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_metadata_sensitive_data.compute_instance_metadata_sensitive_data import (
|
||||
compute_instance_metadata_sensitive_data,
|
||||
)
|
||||
|
||||
check = compute_instance_metadata_sensitive_data()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
# Verify the secret is correctly attributed to 'api_key' key (second in order)
|
||||
assert "in metadata key 'api_key'" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-8"
|
||||
+708
@@ -0,0 +1,708 @@
|
||||
"""Tests for compute_instance_public_ip_exposed check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.compute.compute_service import ComputeInstance
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_compute_instance_public_ip_exposed:
|
||||
"""Test suite for compute_instance_public_ip_exposed check."""
|
||||
|
||||
def test_no_instances(self):
|
||||
"""Test when no instances exist."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_without_public_ip(self):
|
||||
"""Test instance without public IP (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-1",
|
||||
name="Private Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.5",
|
||||
private_v6="",
|
||||
networks={"private": ["10.0.0.5"]}, # Processed from addresses
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Private Instance (instance-1) is not exposed to the internet (no public IP addresses or external network attachments detected)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-1"
|
||||
assert result[0].resource_name == "Private Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_with_public_ipv4(self):
|
||||
"""Test instance with public IPv4 (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-2",
|
||||
name="Public Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="203.0.113.10",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.10",
|
||||
private_v6="",
|
||||
networks={"public": ["203.0.113.10"], "private": ["10.0.0.10"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status_extended.startswith(
|
||||
"Instance Public Instance (instance-2) is exposed to the internet with public IP addresses:"
|
||||
)
|
||||
assert "203.0.113.10" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-2"
|
||||
assert result[0].resource_name == "Public Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_with_access_ipv4(self):
|
||||
"""Test instance with access IPv4 (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-3",
|
||||
name="Access IP Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="198.51.100.5",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.15",
|
||||
private_v6="",
|
||||
networks={"private": ["10.0.0.15"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status_extended.startswith(
|
||||
"Instance Access IP Instance (instance-3) is exposed to the internet with public IP addresses:"
|
||||
)
|
||||
assert "198.51.100.5" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-3"
|
||||
assert result[0].resource_name == "Access IP Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_with_ipv6(self):
|
||||
"""Test instance with public IPv6 (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-4",
|
||||
name="IPv6 Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="2001:db8::1",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="fd00::1",
|
||||
networks={"private": ["fd00::1"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status_extended.startswith(
|
||||
"Instance IPv6 Instance (instance-4) is exposed to the internet with public IP addresses:"
|
||||
)
|
||||
assert "2001:db8::1" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-4"
|
||||
assert result[0].resource_name == "IPv6 Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_multiple_instances_mixed(self):
|
||||
"""Test multiple instances with mixed public IP configuration."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-pass",
|
||||
name="Private",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.20",
|
||||
private_v6="",
|
||||
networks={"private": ["10.0.0.20"]},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
ComputeInstance(
|
||||
id="instance-fail",
|
||||
name="Public",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="203.0.113.20",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert len([r for r in result if r.status == "PASS"]) == 1
|
||||
assert len([r for r in result if r.status == "FAIL"]) == 1
|
||||
|
||||
def test_instance_on_external_network(self):
|
||||
"""Test instance directly attached to external network (OVH-style)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-extnet",
|
||||
name="ExtNet Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="", # SDK might not populate this
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={
|
||||
"Ext-Net": ["57.128.163.151", "2001:41d0:801:1000::164b"]
|
||||
}, # OVH external network
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "57.128.163.151" in result[0].status_extended
|
||||
assert "Ext-Net" in result[0].status_extended
|
||||
assert result[0].resource_id
|
||||
assert result[0].resource_name
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_mixed_networks_private_and_external(self):
|
||||
"""Test instance with both private and external network attachments."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-mixed",
|
||||
name="Mixed Networks",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.5",
|
||||
private_v6="",
|
||||
networks={
|
||||
"private-net": ["10.0.0.5"],
|
||||
"public-network": ["8.8.8.8"], # Real public IP (Google DNS)
|
||||
},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "8.8.8.8" in result[0].status_extended
|
||||
assert "public-network" in result[0].status_extended
|
||||
assert result[0].resource_id
|
||||
assert result[0].resource_name
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_false_positive_network_names(self):
|
||||
"""Test that network names containing 'ext' as substring don't cause false positives."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-context",
|
||||
name="Context Network Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.100",
|
||||
private_v6="",
|
||||
networks={
|
||||
"context-internal": [
|
||||
"10.0.0.100"
|
||||
], # Contains "ext" but should not match
|
||||
"next-hop": ["10.0.0.101"], # Contains "ext" but should not match
|
||||
"text-processing": [
|
||||
"10.0.0.102"
|
||||
], # Contains "ext" but should not match
|
||||
},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Context Network Instance (instance-context) is not exposed to the internet (no public IP addresses or external network attachments detected)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-context"
|
||||
assert result[0].resource_name == "Context Network Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_word_boundary_ext_network(self):
|
||||
"""Test that 'ext' as a complete word is properly detected."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-ext-word",
|
||||
name="Ext Word Boundary Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={
|
||||
"ext": ["8.8.8.8"], # Word boundary: "ext" alone
|
||||
"ext-network": ["1.1.1.1"], # Word boundary: "ext" at start
|
||||
"network-ext": ["9.9.9.9"], # Word boundary: "ext" at end
|
||||
},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
# Should detect at least one external network with public IP
|
||||
assert "ext" in result[0].status_extended.lower()
|
||||
assert result[0].resource_id == "instance-ext-word"
|
||||
assert result[0].resource_name == "Ext Word Boundary Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_public_ip_generic_network_name(self):
|
||||
"""Test that public IPs are detected regardless of network name (e.g., 'hello')."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-hello",
|
||||
name="Generic Network Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="8.8.8.8", # Service populates this via fallback
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={"hello": ["8.8.8.8"]}, # Generic name, but public IP
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "8.8.8.8" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-hello"
|
||||
assert result[0].resource_name == "Generic Network Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_multiple_public_ips_on_different_networks(self):
|
||||
"""Test that multiple public IPs on different networks are all detected."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-multi-ip",
|
||||
name="Multiple Public IPs",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="8.8.8.8", # First public IP captured by service
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={
|
||||
"network1": ["8.8.8.8"], # First public IP
|
||||
"network2": ["1.1.1.1"], # Second public IP
|
||||
"network3": ["9.9.9.9"], # Third public IP
|
||||
},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_public_ip_exposed.compute_instance_public_ip_exposed import (
|
||||
compute_instance_public_ip_exposed,
|
||||
)
|
||||
|
||||
check = compute_instance_public_ip_exposed()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
# Should detect all three public IPs
|
||||
assert "8.8.8.8" in result[0].status_extended
|
||||
assert "1.1.1.1" in result[0].status_extended
|
||||
assert "9.9.9.9" in result[0].status_extended
|
||||
# Should show network names for additional IPs
|
||||
assert "network2" in result[0].status_extended
|
||||
assert "network3" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-multi-ip"
|
||||
assert result[0].resource_name == "Multiple Public IPs"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
+90
-6
@@ -49,6 +49,21 @@ class Test_compute_instance_security_groups_attached:
|
||||
security_groups=["default", "web"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
@@ -71,11 +86,14 @@ class Test_compute_instance_security_groups_attached:
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Instance One (instance-1) has security groups attached: default, web."
|
||||
)
|
||||
assert result[0].resource_id == "instance-1"
|
||||
assert result[0].resource_name == "Instance One"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
assert "has security groups attached" in result[0].status_extended
|
||||
|
||||
def test_instance_without_security_groups(self):
|
||||
"""Test instance without security groups attached (FAIL)."""
|
||||
@@ -89,6 +107,21 @@ class Test_compute_instance_security_groups_attached:
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
@@ -111,14 +144,14 @@ class Test_compute_instance_security_groups_attached:
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Instance Two (instance-2) does not have any security groups attached."
|
||||
)
|
||||
assert result[0].resource_id == "instance-2"
|
||||
assert result[0].resource_name == "Instance Two"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
assert (
|
||||
"does not have any security groups attached"
|
||||
in result[0].status_extended
|
||||
)
|
||||
|
||||
def test_multiple_instances_mixed(self):
|
||||
"""Test multiple instances with mixed results."""
|
||||
@@ -132,6 +165,21 @@ class Test_compute_instance_security_groups_attached:
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
ComputeInstance(
|
||||
id="instance-fail",
|
||||
@@ -141,6 +189,21 @@ class Test_compute_instance_security_groups_attached:
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -177,6 +240,21 @@ class Test_compute_instance_security_groups_attached:
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
@@ -198,6 +276,12 @@ class Test_compute_instance_security_groups_attached:
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance (instance-3) has security groups attached: default."
|
||||
)
|
||||
assert result[0].resource_id == "instance-3"
|
||||
assert result[0].resource_name == ""
|
||||
assert "instance-3" in result[0].status_extended
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
"""Tests for compute_instance_trusted_image_certificates check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.compute.compute_service import ComputeInstance
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_compute_instance_trusted_image_certificates:
|
||||
"""Test suite for compute_instance_trusted_image_certificates check."""
|
||||
|
||||
def test_no_instances(self):
|
||||
"""Test when no instances exist."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_trusted_image_certificates.compute_instance_trusted_image_certificates.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_trusted_image_certificates.compute_instance_trusted_image_certificates import (
|
||||
compute_instance_trusted_image_certificates,
|
||||
)
|
||||
|
||||
check = compute_instance_trusted_image_certificates()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_with_trusted_certificates(self):
|
||||
"""Test instance with trusted image certificates (PASS)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-1",
|
||||
name="Trusted Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=["cert-123", "cert-456"],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_trusted_image_certificates.compute_instance_trusted_image_certificates.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_trusted_image_certificates.compute_instance_trusted_image_certificates import (
|
||||
compute_instance_trusted_image_certificates,
|
||||
)
|
||||
|
||||
check = compute_instance_trusted_image_certificates()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].status_extended.startswith(
|
||||
"Instance Trusted Instance (instance-1) uses trusted image certificates:"
|
||||
)
|
||||
assert "cert-123" in result[0].status_extended
|
||||
assert result[0].resource_id == "instance-1"
|
||||
assert result[0].resource_name == "Trusted Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_instance_without_trusted_certificates(self):
|
||||
"""Test instance without trusted image certificates (FAIL)."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-2",
|
||||
name="Untrusted Instance",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=["default"],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_trusted_image_certificates.compute_instance_trusted_image_certificates.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_trusted_image_certificates.compute_instance_trusted_image_certificates import (
|
||||
compute_instance_trusted_image_certificates,
|
||||
)
|
||||
|
||||
check = compute_instance_trusted_image_certificates()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Instance Untrusted Instance (instance-2) does not use trusted image certificates (image signature validation not enforced)."
|
||||
)
|
||||
assert result[0].resource_id == "instance-2"
|
||||
assert result[0].resource_name == "Untrusted Instance"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
assert result[0].project_id == OPENSTACK_PROJECT_ID
|
||||
|
||||
def test_multiple_instances_mixed(self):
|
||||
"""Test multiple instances with mixed certificate configuration."""
|
||||
compute_client = mock.MagicMock()
|
||||
compute_client.instances = [
|
||||
ComputeInstance(
|
||||
id="instance-pass",
|
||||
name="Pass",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=["cert-789"],
|
||||
),
|
||||
ComputeInstance(
|
||||
id="instance-fail",
|
||||
name="Fail",
|
||||
status="ACTIVE",
|
||||
flavor_id="flavor-1",
|
||||
security_groups=[],
|
||||
region=OPENSTACK_REGION,
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
is_locked=False,
|
||||
locked_reason="",
|
||||
key_name="",
|
||||
user_id="",
|
||||
access_ipv4="",
|
||||
access_ipv6="",
|
||||
public_v4="",
|
||||
public_v6="",
|
||||
private_v4="",
|
||||
private_v6="",
|
||||
networks={},
|
||||
has_config_drive=False,
|
||||
metadata={},
|
||||
user_data="",
|
||||
trusted_image_certificates=[],
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.compute.compute_instance_trusted_image_certificates.compute_instance_trusted_image_certificates.compute_client",
|
||||
new=compute_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.compute.compute_instance_trusted_image_certificates.compute_instance_trusted_image_certificates import (
|
||||
compute_instance_trusted_image_certificates,
|
||||
)
|
||||
|
||||
check = compute_instance_trusted_image_certificates()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert len([r for r in result if r.status == "PASS"]) == 1
|
||||
assert len([r for r in result if r.status == "FAIL"]) == 1
|
||||
@@ -0,0 +1,53 @@
|
||||
"""Tests for the shared is_public_ip utility."""
|
||||
|
||||
from prowler.providers.openstack.services.compute.lib.ip import is_public_ip
|
||||
|
||||
|
||||
class Test_is_public_ip:
|
||||
def test_public_ipv4(self):
|
||||
assert is_public_ip("8.8.8.8")
|
||||
|
||||
def test_public_ipv4_other(self):
|
||||
assert is_public_ip("1.1.1.1")
|
||||
|
||||
def test_private_ipv4_10(self):
|
||||
assert not is_public_ip("10.0.0.5")
|
||||
|
||||
def test_private_ipv4_172(self):
|
||||
assert not is_public_ip("172.16.0.1")
|
||||
|
||||
def test_private_ipv4_192(self):
|
||||
assert not is_public_ip("192.168.1.1")
|
||||
|
||||
def test_loopback_ipv4(self):
|
||||
assert not is_public_ip("127.0.0.1")
|
||||
|
||||
def test_link_local_ipv4(self):
|
||||
assert not is_public_ip("169.254.0.1")
|
||||
|
||||
def test_multicast_ipv4(self):
|
||||
assert not is_public_ip("224.0.0.1")
|
||||
|
||||
def test_documentation_ipv4_not_global(self):
|
||||
assert not is_public_ip("203.0.113.10")
|
||||
|
||||
def test_public_ipv6(self):
|
||||
assert is_public_ip("2001:41d0:801:1000::164b")
|
||||
|
||||
def test_private_ipv6(self):
|
||||
assert not is_public_ip("fd00::1")
|
||||
|
||||
def test_loopback_ipv6(self):
|
||||
assert not is_public_ip("::1")
|
||||
|
||||
def test_link_local_ipv6(self):
|
||||
assert not is_public_ip("fe80::1")
|
||||
|
||||
def test_documentation_ipv6_not_global(self):
|
||||
assert not is_public_ip("2001:db8::1")
|
||||
|
||||
def test_invalid_ip(self):
|
||||
assert not is_public_ip("not-an-ip")
|
||||
|
||||
def test_empty_string(self):
|
||||
assert not is_public_ip("")
|
||||
@@ -44,6 +44,24 @@ class TestComputeService:
|
||||
mock_server1.status = "ACTIVE"
|
||||
mock_server1.flavor = {"id": "flavor-1"}
|
||||
mock_server1.security_groups = [{"name": "default"}]
|
||||
mock_server1.is_locked = True
|
||||
mock_server1.locked_reason = "maintenance"
|
||||
mock_server1.key_name = "my-keypair"
|
||||
mock_server1.user_id = "user-123"
|
||||
mock_server1.access_ipv4 = "203.0.113.10"
|
||||
mock_server1.access_ipv6 = "2001:db8::1"
|
||||
mock_server1.public_v4 = "203.0.113.10"
|
||||
mock_server1.public_v6 = ""
|
||||
mock_server1.private_v4 = "10.0.0.5"
|
||||
mock_server1.private_v6 = ""
|
||||
mock_server1.addresses = {
|
||||
"private": [{"version": 4, "addr": "10.0.0.5"}],
|
||||
"public": [{"version": 4, "addr": "203.0.113.10"}],
|
||||
}
|
||||
mock_server1.has_config_drive = True
|
||||
mock_server1.metadata = {"environment": "production"}
|
||||
mock_server1.user_data = "#!/bin/bash\necho hello"
|
||||
mock_server1.trusted_image_certificates = ["cert-123"]
|
||||
|
||||
mock_server2 = MagicMock()
|
||||
mock_server2.id = "instance-2"
|
||||
@@ -51,6 +69,21 @@ class TestComputeService:
|
||||
mock_server2.status = "SHUTOFF"
|
||||
mock_server2.flavor = {"id": "flavor-2"}
|
||||
mock_server2.security_groups = [{"name": "web"}, {"name": "db"}]
|
||||
mock_server2.is_locked = False
|
||||
mock_server2.locked_reason = ""
|
||||
mock_server2.key_name = ""
|
||||
mock_server2.user_id = "user-456"
|
||||
mock_server2.access_ipv4 = ""
|
||||
mock_server2.access_ipv6 = ""
|
||||
mock_server2.public_v4 = ""
|
||||
mock_server2.public_v6 = ""
|
||||
mock_server2.private_v4 = "10.0.0.10"
|
||||
mock_server2.private_v6 = ""
|
||||
mock_server2.addresses = {"private": [{"version": 4, "addr": "10.0.0.10"}]}
|
||||
mock_server2.has_config_drive = False
|
||||
mock_server2.metadata = {}
|
||||
mock_server2.user_data = ""
|
||||
mock_server2.trusted_image_certificates = []
|
||||
|
||||
provider.connection.compute.servers.return_value = [
|
||||
mock_server1,
|
||||
@@ -68,8 +101,27 @@ class TestComputeService:
|
||||
assert compute.instances[0].security_groups == ["default"]
|
||||
assert compute.instances[0].region == OPENSTACK_REGION
|
||||
assert compute.instances[0].project_id == OPENSTACK_PROJECT_ID
|
||||
assert compute.instances[0].is_locked is True
|
||||
assert compute.instances[0].locked_reason == "maintenance"
|
||||
assert compute.instances[0].key_name == "my-keypair"
|
||||
assert compute.instances[0].user_id == "user-123"
|
||||
assert compute.instances[0].access_ipv4 == "203.0.113.10"
|
||||
assert compute.instances[0].access_ipv6 == "2001:db8::1"
|
||||
assert compute.instances[0].public_v4 == "203.0.113.10"
|
||||
assert compute.instances[0].private_v4 == "10.0.0.5"
|
||||
assert compute.instances[0].networks == {
|
||||
"private": ["10.0.0.5"],
|
||||
"public": ["203.0.113.10"],
|
||||
}
|
||||
assert compute.instances[0].has_config_drive is True
|
||||
assert compute.instances[0].metadata == {"environment": "production"}
|
||||
assert compute.instances[0].user_data == "#!/bin/bash\necho hello"
|
||||
assert compute.instances[0].trusted_image_certificates == ["cert-123"]
|
||||
|
||||
assert compute.instances[1].security_groups == ["web", "db"]
|
||||
assert compute.instances[1].is_locked is False
|
||||
assert compute.instances[1].key_name == ""
|
||||
assert compute.instances[1].trusted_image_certificates == []
|
||||
|
||||
def test_compute_list_instances_empty(self):
|
||||
"""Test listing instances when none exist."""
|
||||
@@ -90,6 +142,21 @@ class TestComputeService:
|
||||
del mock_server.status
|
||||
del mock_server.flavor
|
||||
del mock_server.security_groups
|
||||
del mock_server.is_locked
|
||||
del mock_server.locked_reason
|
||||
del mock_server.key_name
|
||||
del mock_server.user_id
|
||||
del mock_server.access_ipv4
|
||||
del mock_server.access_ipv6
|
||||
del mock_server.public_v4
|
||||
del mock_server.public_v6
|
||||
del mock_server.private_v4
|
||||
del mock_server.private_v6
|
||||
del mock_server.addresses
|
||||
del mock_server.has_config_drive
|
||||
del mock_server.metadata
|
||||
del mock_server.user_data
|
||||
del mock_server.trusted_image_certificates
|
||||
|
||||
provider.connection.compute.servers.return_value = [mock_server]
|
||||
|
||||
@@ -101,6 +168,21 @@ class TestComputeService:
|
||||
assert compute.instances[0].status == ""
|
||||
assert compute.instances[0].flavor_id == ""
|
||||
assert compute.instances[0].security_groups == []
|
||||
assert compute.instances[0].is_locked is False
|
||||
assert compute.instances[0].locked_reason == ""
|
||||
assert compute.instances[0].key_name == ""
|
||||
assert compute.instances[0].user_id == ""
|
||||
assert compute.instances[0].access_ipv4 == ""
|
||||
assert compute.instances[0].access_ipv6 == ""
|
||||
assert compute.instances[0].public_v4 == ""
|
||||
assert compute.instances[0].public_v6 == ""
|
||||
assert compute.instances[0].private_v4 == ""
|
||||
assert compute.instances[0].private_v6 == ""
|
||||
assert compute.instances[0].networks == {}
|
||||
assert compute.instances[0].has_config_drive is False
|
||||
assert compute.instances[0].metadata == {}
|
||||
assert compute.instances[0].user_data == ""
|
||||
assert compute.instances[0].trusted_image_certificates == []
|
||||
|
||||
def test_compute_list_instances_sdk_exception(self):
|
||||
"""Test handling SDKException when listing instances."""
|
||||
@@ -133,6 +215,21 @@ class TestComputeService:
|
||||
mock_server.status = "ACTIVE"
|
||||
mock_server.flavor = {"id": "flavor-1"}
|
||||
mock_server.security_groups = [{"name": "default"}]
|
||||
mock_server.is_locked = False
|
||||
mock_server.locked_reason = ""
|
||||
mock_server.key_name = ""
|
||||
mock_server.user_id = ""
|
||||
mock_server.access_ipv4 = ""
|
||||
mock_server.access_ipv6 = ""
|
||||
mock_server.public_v4 = ""
|
||||
mock_server.public_v6 = ""
|
||||
mock_server.private_v4 = ""
|
||||
mock_server.private_v6 = ""
|
||||
mock_server.addresses = {}
|
||||
mock_server.has_config_drive = False
|
||||
mock_server.metadata = {}
|
||||
mock_server.user_data = ""
|
||||
mock_server.trusted_image_certificates = []
|
||||
yield mock_server
|
||||
raise Exception("Iterator failed")
|
||||
|
||||
@@ -154,6 +251,23 @@ class TestComputeService:
|
||||
security_groups=["default"],
|
||||
region="RegionOne",
|
||||
project_id="project-1",
|
||||
is_locked=True,
|
||||
locked_reason="maintenance",
|
||||
key_name="my-keypair",
|
||||
user_id="user-123",
|
||||
access_ipv4="203.0.113.10",
|
||||
access_ipv6="2001:db8::1",
|
||||
public_v4="203.0.113.10",
|
||||
public_v6="",
|
||||
private_v4="10.0.0.5",
|
||||
private_v6="",
|
||||
networks={
|
||||
"private": ["10.0.0.5"]
|
||||
}, # Note: This is the processed dict, not addresses
|
||||
has_config_drive=True,
|
||||
metadata={"environment": "production"},
|
||||
user_data="#!/bin/bash\necho hello",
|
||||
trusted_image_certificates=["cert-123"],
|
||||
)
|
||||
|
||||
assert instance.id == "instance-1"
|
||||
@@ -163,6 +277,21 @@ class TestComputeService:
|
||||
assert instance.security_groups == ["default"]
|
||||
assert instance.region == "RegionOne"
|
||||
assert instance.project_id == "project-1"
|
||||
assert instance.is_locked is True
|
||||
assert instance.locked_reason == "maintenance"
|
||||
assert instance.key_name == "my-keypair"
|
||||
assert instance.user_id == "user-123"
|
||||
assert instance.access_ipv4 == "203.0.113.10"
|
||||
assert instance.access_ipv6 == "2001:db8::1"
|
||||
assert instance.public_v4 == "203.0.113.10"
|
||||
assert instance.public_v6 == ""
|
||||
assert instance.private_v4 == "10.0.0.5"
|
||||
assert instance.private_v6 == ""
|
||||
assert instance.networks == {"private": ["10.0.0.5"]}
|
||||
assert instance.has_config_drive is True
|
||||
assert instance.metadata == {"environment": "production"}
|
||||
assert instance.user_data == "#!/bin/bash\necho hello"
|
||||
assert instance.trusted_image_certificates == ["cert-123"]
|
||||
|
||||
def test_compute_service_inherits_from_base(self):
|
||||
"""Test Compute service inherits from OpenStackService."""
|
||||
@@ -180,3 +309,37 @@ class TestComputeService:
|
||||
assert hasattr(compute, "identity")
|
||||
assert hasattr(compute, "audit_config")
|
||||
assert hasattr(compute, "fixer_config")
|
||||
|
||||
def test_compute_list_instances_with_none_addresses(self):
|
||||
"""Test listing instances when addresses attribute is None."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_server = MagicMock()
|
||||
mock_server.id = "instance-1"
|
||||
mock_server.name = "Instance With None Addresses"
|
||||
mock_server.status = "ACTIVE"
|
||||
mock_server.flavor = {"id": "flavor-1"}
|
||||
mock_server.security_groups = [{"name": "default"}]
|
||||
mock_server.is_locked = False
|
||||
mock_server.locked_reason = ""
|
||||
mock_server.key_name = "test-key"
|
||||
mock_server.user_id = "user-123"
|
||||
mock_server.access_ipv4 = ""
|
||||
mock_server.access_ipv6 = ""
|
||||
mock_server.public_v4 = ""
|
||||
mock_server.public_v6 = ""
|
||||
mock_server.private_v4 = ""
|
||||
mock_server.private_v6 = ""
|
||||
mock_server.addresses = None # This is the key test case
|
||||
mock_server.has_config_drive = False
|
||||
mock_server.metadata = {}
|
||||
mock_server.user_data = ""
|
||||
mock_server.trusted_image_certificates = []
|
||||
|
||||
provider.connection.compute.servers.return_value = [mock_server]
|
||||
|
||||
compute = Compute(provider)
|
||||
|
||||
assert len(compute.instances) == 1
|
||||
assert compute.instances[0].id == "instance-1"
|
||||
assert compute.instances[0].networks == {} # Should default to empty dict
|
||||
|
||||
Reference in New Issue
Block a user