feat(dms): add tags to DMS checks (#5209)

This commit is contained in:
Rubén De la Torre Vico
2024-09-26 19:33:28 +02:00
committed by GitHub
parent 19acb873af
commit 05f7170add
10 changed files with 169 additions and 20 deletions
@@ -9,16 +9,15 @@ class dms_endpoint_ssl_enabled(Check):
report = Check_Report_AWS(self.metadata())
report.resource_id = endpoint.id
report.resource_arn = endpoint_arn
report.region = dms_client.audited_region
report.region = endpoint.region
report.resource_tags = endpoint.tags
if endpoint.ssl_mode == "none":
report.status = "FAIL"
report.status_extended = (
f"DMS Endpoint {endpoint_arn} is not using SSL."
)
report.status_extended = f"DMS Endpoint {endpoint.id} is not using SSL."
else:
report.status = "PASS"
report.status_extended = f"DMS Endpoint {endpoint_arn} is using SSL with mode: {endpoint.ssl_mode}."
report.status_extended = f"DMS Endpoint {endpoint.id} is using SSL with mode: {endpoint.ssl_mode}."
findings.append(report)
@@ -10,6 +10,7 @@ class dms_instance_minor_version_upgrade_enabled(Check):
report.region = instance.region
report.resource_id = instance.id
report.resource_arn = instance.arn
report.resource_tags = instance.tags
report.status = "FAIL"
report.status_extended = f"DMS Replication Instance {instance.id} does not have auto minor version upgrade enabled."
if instance.auto_minor_version_upgrade:
@@ -10,6 +10,7 @@ class dms_instance_multi_az_enabled(Check):
report.region = instance.region
report.resource_id = instance.id
report.resource_arn = instance.arn
report.resource_tags = instance.tags
report.status = "FAIL"
report.status_extended = f"DMS Replication Instance {instance.id} does not have multi az enabled."
if instance.multi_az:
@@ -12,6 +12,7 @@ class dms_instance_no_public_access(Check):
report.region = instance.region
report.resource_id = instance.id
report.resource_arn = instance.arn
report.resource_tags = instance.tags
report.status = "PASS"
report.status_extended = (
f"DMS Replication Instance {instance.id} is not publicly accessible."
@@ -1,3 +1,5 @@
from typing import Optional
from pydantic import BaseModel
from prowler.lib.logger import logger
@@ -5,7 +7,6 @@ from prowler.lib.scan_filters.scan_filters import is_resource_filtered
from prowler.providers.aws.lib.service.service import AWSService
################## Database Migration Service
class DMS(AWSService):
def __init__(self, provider):
# Call AWSService's __init__
@@ -13,7 +14,9 @@ class DMS(AWSService):
self.instances = []
self.endpoints = {}
self.__threading_call__(self._describe_replication_instances)
self.__threading_call__(self._list_tags, self.instances)
self.__threading_call__(self._describe_endpoints)
self.__threading_call__(self._list_tags, self.endpoints.values())
def _describe_replication_instances(self, regional_client):
logger.info("DMS - Describing DMS Replication Instances...")
@@ -64,7 +67,9 @@ class DMS(AWSService):
is_resource_filtered(arn, self.audit_resources)
):
self.endpoints[arn] = Endpoint(
arn=arn,
id=endpoint["EndpointIdentifier"],
region=regional_client.region,
ssl_mode=endpoint.get("SslMode", False),
)
except Exception as error:
@@ -72,10 +77,23 @@ class DMS(AWSService):
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
def _list_tags(self, resource: any):
try:
resource.tags = self.regional_clients[
resource.region
].list_tags_for_resource(ResourceArn=resource.arn)["TagList"]
except Exception as error:
logger.error(
f"{resource.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
class Endpoint(BaseModel):
arn: str
id: str
region: str
ssl_mode: str
tags: Optional[list]
class RepInstance(BaseModel):
@@ -88,3 +106,4 @@ class RepInstance(BaseModel):
security_groups: list[str] = []
multi_az: bool
region: str
tags: Optional[list]
@@ -5,7 +5,6 @@ from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_US_EAST_1
class Test_dms_endpoint_ssl_enabled:
def test_dms_no_endpoints(self):
dms_client = mock.MagicMock
dms_client.endpoints = {}
@@ -24,8 +23,15 @@ class Test_dms_endpoint_ssl_enabled:
def test_dms_endpoint_ssl_none(self):
dms_client = mock.MagicMock
endpoint_arn = f"arn:aws:dms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:endpoint:test-endpoint-no-ssl"
dms_client.endpoints = {
"test-endpoint-no-ssl": Endpoint(id="test-endpoint-no-ssl", ssl_mode="none")
endpoint_arn: Endpoint(
arn=endpoint_arn,
id="test-endpoint-no-ssl",
region=AWS_REGION_US_EAST_1,
ssl_mode="none",
tags=[{"Key": "Name", "Value": "test-endpoint-no-ssl"}],
)
}
dms_client.audited_account = AWS_ACCOUNT_NUMBER
dms_client.audited_partition = "aws"
@@ -45,18 +51,29 @@ class Test_dms_endpoint_ssl_enabled:
assert len(result) == 1
assert result[0].status == "FAIL"
assert result[0].resource_id == "test-endpoint-no-ssl"
assert result[0].resource_arn == "test-endpoint-no-ssl"
assert (
result[0].resource_arn
== f"arn:aws:dms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:endpoint:test-endpoint-no-ssl"
)
assert result[0].region == AWS_REGION_US_EAST_1
assert (
result[0].status_extended
== "DMS Endpoint test-endpoint-no-ssl is not using SSL."
)
assert result[0].resource_tags == [
{"Key": "Name", "Value": "test-endpoint-no-ssl"}
]
def test_dms_endpoint_ssl_require(self):
dms_client = mock.MagicMock
endpoint_arn = f"arn:aws:dms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:endpoint:test-endpoint-ssl-require"
dms_client.endpoints = {
"test-endpoint-ssl-require": Endpoint(
id="test-endpoint-ssl-require", ssl_mode="require"
endpoint_arn: Endpoint(
arn=endpoint_arn,
id="test-endpoint-ssl-require",
region=AWS_REGION_US_EAST_1,
ssl_mode="require",
tags=[{"Key": "Name", "Value": "test-endpoint-ssl-require"}],
)
}
dms_client.audited_account = AWS_ACCOUNT_NUMBER
@@ -77,18 +94,26 @@ class Test_dms_endpoint_ssl_enabled:
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].resource_id == "test-endpoint-ssl-require"
assert result[0].resource_arn == "test-endpoint-ssl-require"
assert result[0].resource_arn == endpoint_arn
assert result[0].region == AWS_REGION_US_EAST_1
assert (
result[0].status_extended
== "DMS Endpoint test-endpoint-ssl-require is using SSL with mode: require."
)
assert result[0].resource_tags == [
{"Key": "Name", "Value": "test-endpoint-ssl-require"}
]
def test_dms_endpoint_ssl_verify_ca(self):
dms_client = mock.MagicMock
endpoint_arn = f"arn:aws:dms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:endpoint:test-endpoint-ssl-verify-ca"
dms_client.endpoints = {
"test-endpoint-ssl-verify-ca": Endpoint(
id="test-endpoint-ssl-verify-ca", ssl_mode="verify-ca"
endpoint_arn: Endpoint(
arn=endpoint_arn,
id="test-endpoint-ssl-verify-ca",
region=AWS_REGION_US_EAST_1,
ssl_mode="verify-ca",
tags=[{"Key": "Name", "Value": "test-endpoint-ssl-verify-ca"}],
)
}
dms_client.audited_account = AWS_ACCOUNT_NUMBER
@@ -109,18 +134,26 @@ class Test_dms_endpoint_ssl_enabled:
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].resource_id == "test-endpoint-ssl-verify-ca"
assert result[0].resource_arn == "test-endpoint-ssl-verify-ca"
assert result[0].resource_arn == endpoint_arn
assert result[0].region == AWS_REGION_US_EAST_1
assert (
result[0].status_extended
== "DMS Endpoint test-endpoint-ssl-verify-ca is using SSL with mode: verify-ca."
)
assert result[0].resource_tags == [
{"Key": "Name", "Value": "test-endpoint-ssl-verify-ca"}
]
def test_dms_endpoint_ssl_verify_full(self):
dms_client = mock.MagicMock
endpoint_arn = f"arn:aws:dms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:endpoint:test-endpoint-ssl-verify-full"
dms_client.endpoints = {
"test-endpoint-ssl-verify-full": Endpoint(
id="test-endpoint-ssl-verify-full", ssl_mode="verify-full"
endpoint_arn: Endpoint(
arn=endpoint_arn,
id="test-endpoint-ssl-verify-full",
region=AWS_REGION_US_EAST_1,
ssl_mode="verify-full",
tags=[{"Key": "Name", "Value": "test-endpoint-ssl-verify-full"}],
)
}
dms_client.audited_account = AWS_ACCOUNT_NUMBER
@@ -141,9 +174,12 @@ class Test_dms_endpoint_ssl_enabled:
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].resource_id == "test-endpoint-ssl-verify-full"
assert result[0].resource_arn == "test-endpoint-ssl-verify-full"
assert result[0].resource_arn == endpoint_arn
assert result[0].region == AWS_REGION_US_EAST_1
assert (
result[0].status_extended
== "DMS Endpoint test-endpoint-ssl-verify-full is using SSL with mode: verify-full."
)
assert result[0].resource_tags == [
{"Key": "Name", "Value": "test-endpoint-ssl-verify-full"}
]
@@ -40,6 +40,7 @@ class Test_dms_instance_minor_version_upgrade_enabled:
auto_minor_version_upgrade=False,
multi_az=True,
region=AWS_REGION_US_EAST_1,
tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}],
)
)
@@ -62,6 +63,9 @@ class Test_dms_instance_minor_version_upgrade_enabled:
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == DMS_INSTANCE_NAME
assert result[0].resource_arn == DMS_INSTANCE_ARN
assert result[0].resource_tags == [
{"Key": "Name", "Value": DMS_INSTANCE_NAME}
]
def test_dms_instance_minor_version_upgrade_enabled(self):
dms_client = mock.MagicMock
@@ -76,6 +80,7 @@ class Test_dms_instance_minor_version_upgrade_enabled:
auto_minor_version_upgrade=True,
multi_az=True,
region=AWS_REGION_US_EAST_1,
tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}],
)
)
@@ -98,3 +103,6 @@ class Test_dms_instance_minor_version_upgrade_enabled:
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == DMS_INSTANCE_NAME
assert result[0].resource_arn == DMS_INSTANCE_ARN
assert result[0].resource_tags == [
{"Key": "Name", "Value": DMS_INSTANCE_NAME}
]
@@ -40,6 +40,7 @@ class Test_dms_instance_multi_az:
auto_minor_version_upgrade=False,
multi_az=False,
region=AWS_REGION_US_EAST_1,
tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}],
)
)
@@ -62,6 +63,9 @@ class Test_dms_instance_multi_az:
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == DMS_INSTANCE_NAME
assert result[0].resource_arn == DMS_INSTANCE_ARN
assert result[0].resource_tags == [
{"Key": "Name", "Value": DMS_INSTANCE_NAME}
]
def test_dms_instance_multi_az_enabled(self):
dms_client = mock.MagicMock
@@ -76,6 +80,7 @@ class Test_dms_instance_multi_az:
auto_minor_version_upgrade=True,
multi_az=True,
region=AWS_REGION_US_EAST_1,
tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}],
)
)
@@ -98,3 +103,6 @@ class Test_dms_instance_multi_az:
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == DMS_INSTANCE_NAME
assert result[0].resource_arn == DMS_INSTANCE_ARN
assert result[0].resource_tags == [
{"Key": "Name", "Value": DMS_INSTANCE_NAME}
]
@@ -45,7 +45,6 @@ class Test_dms_instance_no_public_access:
result = check.execute()
assert len(result) == 0
@mock_aws
def test_dms_private(self):
dms_client = mock.MagicMock
dms_client.instances = []
@@ -60,6 +59,7 @@ class Test_dms_instance_no_public_access:
auto_minor_version_upgrade=False,
multi_az=False,
region=AWS_REGION_US_EAST_1,
tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}],
)
)
@@ -88,8 +88,13 @@ class Test_dms_instance_no_public_access:
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == DMS_INSTANCE_NAME
assert result[0].resource_arn == DMS_INSTANCE_ARN
assert result[0].resource_tags == [
{
"Key": "Name",
"Value": DMS_INSTANCE_NAME,
}
]
@mock_aws
def test_dms_public(self):
dms_client = mock.MagicMock
dms_client.instances = []
@@ -104,6 +109,7 @@ class Test_dms_instance_no_public_access:
auto_minor_version_upgrade=False,
multi_az=False,
region=AWS_REGION_US_EAST_1,
tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}],
)
)
@@ -132,6 +138,12 @@ class Test_dms_instance_no_public_access:
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == DMS_INSTANCE_NAME
assert result[0].resource_arn == DMS_INSTANCE_ARN
assert result[0].resource_tags == [
{
"Key": "Name",
"Value": DMS_INSTANCE_NAME,
}
]
@mock_aws
def test_dms_public_with_public_sg(self):
@@ -163,6 +175,7 @@ class Test_dms_instance_no_public_access:
auto_minor_version_upgrade=False,
multi_az=False,
region=AWS_REGION_US_EAST_1,
tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}],
)
)
@@ -201,6 +214,12 @@ class Test_dms_instance_no_public_access:
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == DMS_INSTANCE_NAME
assert result[0].resource_arn == DMS_INSTANCE_ARN
assert result[0].resource_tags == [
{
"Key": "Name",
"Value": DMS_INSTANCE_NAME,
}
]
@mock_aws
def test_dms_public_with_filtered_sg(self):
@@ -232,6 +251,7 @@ class Test_dms_instance_no_public_access:
auto_minor_version_upgrade=False,
multi_az=False,
region=AWS_REGION_US_EAST_1,
tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}],
)
)
@@ -270,3 +290,9 @@ class Test_dms_instance_no_public_access:
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == DMS_INSTANCE_NAME
assert result[0].resource_arn == DMS_INSTANCE_ARN
assert result[0].resource_tags == [
{
"Key": "Name",
"Value": DMS_INSTANCE_NAME,
}
]
@@ -14,6 +14,9 @@ DMS_INSTANCE_ARN = (
)
KMS_KEY_ID = f"arn:aws:kms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:key/abcdabcd-1234-abcd-1234-abcdabcdabcd"
DMS_ENDPOINT_NAME = "dms-endpoint"
DMS_ENDPOINT_ARN = f"arn:aws:dms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:endpoint:{DMS_ENDPOINT_NAME}"
# Mocking Access Analyzer Calls
make_api_call = botocore.client.BaseClient._make_api_call
@@ -34,6 +37,31 @@ def mock_make_api_call(self, operation_name, kwargs):
},
]
}
elif operation_name == "DescribeEndpoints":
return {
"Endpoints": [
{
"EndpointIdentifier": DMS_ENDPOINT_NAME,
"EndpointArn": DMS_ENDPOINT_ARN,
"SslMode": "require",
}
]
}
elif operation_name == "ListTagsForResource":
if kwargs["ResourceArn"] == DMS_INSTANCE_ARN:
return {
"TagList": [
{"Key": "Name", "Value": "rep-instance"},
{"Key": "Owner", "Value": "admin"},
]
}
elif kwargs["ResourceArn"] == DMS_ENDPOINT_ARN:
return {
"TagList": [
{"Key": "Name", "Value": "dms-endpoint"},
{"Key": "Owner", "Value": "admin"},
]
}
return make_api_call(self, operation_name, kwargs)
@@ -84,3 +112,25 @@ class Test_DMS_Service:
assert dms.instances[0].auto_minor_version_upgrade
assert dms.instances[0].multi_az
assert dms.instances[0].security_groups == []
# Test DMS Endpoints
def test_describe_endpoints(self):
aws_provider = set_mocked_aws_provider()
dms = DMS(aws_provider)
assert len(dms.endpoints) == 1
assert dms.endpoints[DMS_ENDPOINT_ARN].id == DMS_ENDPOINT_NAME
assert dms.endpoints[DMS_ENDPOINT_ARN].ssl_mode == "require"
def test_list_tags(self):
aws_provider = set_mocked_aws_provider()
dms = DMS(aws_provider)
assert dms.instances[0].tags == [
{"Key": "Name", "Value": "rep-instance"},
{"Key": "Owner", "Value": "admin"},
]
assert dms.endpoints[DMS_ENDPOINT_ARN].tags == [
{"Key": "Name", "Value": "dms-endpoint"},
{"Key": "Owner", "Value": "admin"},
]