-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into PRWLR-4468-ensure-dms-replication-tasks-fo…
…r-the-source-database-have-logging-enabled
- Loading branch information
Showing
16 changed files
with
702 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from prowler.providers.aws.services.appsync.appsync_service import AppSync | ||
from prowler.providers.common.provider import Provider | ||
|
||
appsync_client = AppSync(Provider.get_global_provider()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
from typing import Optional | ||
|
||
from pydantic import BaseModel | ||
|
||
from prowler.lib.logger import logger | ||
from prowler.lib.scan_filters.scan_filters import is_resource_filtered | ||
from prowler.providers.aws.lib.service.service import AWSService | ||
|
||
|
||
class AppSync(AWSService): | ||
def __init__(self, provider): | ||
# Call AWSService's __init__ | ||
super().__init__(__class__.__name__, provider) | ||
self.graphql_apis = {} | ||
self.__threading_call__(self._list_graphql_apis) | ||
|
||
def _list_graphql_apis(self, regional_client): | ||
logger.info("AppSync - Describing APIs...") | ||
try: | ||
list_graphql_apis_paginator = regional_client.get_paginator( | ||
"list_graphql_apis" | ||
) | ||
for page in list_graphql_apis_paginator.paginate(): | ||
for api in page["graphqlApis"]: | ||
api_arn = api["arn"] | ||
if not self.audit_resources or ( | ||
is_resource_filtered( | ||
api_arn, | ||
self.audit_resources, | ||
) | ||
): | ||
self.graphql_apis[api_arn] = GraphqlApi( | ||
id=api["apiId"], | ||
name=api["name"], | ||
arn=api_arn, | ||
region=regional_client.region, | ||
type=api.get("apiType", "GRAPHQL"), | ||
field_log_level=api.get("logConfig", {}).get( | ||
"fieldLogLevel", "" | ||
), | ||
authentication_type=api.get("authenticationType", ""), | ||
tags=[api.get("tags", {})], | ||
) | ||
|
||
except Exception as error: | ||
logger.error( | ||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" | ||
) | ||
|
||
|
||
class GraphqlApi(BaseModel): | ||
id: str | ||
name: str | ||
arn: str | ||
region: str | ||
type: str | ||
field_log_level: str | ||
authentication_type: str | ||
tags: Optional[list] = [] |
Empty file.
32 changes: 32 additions & 0 deletions
32
...transit_encryption_enabled/dms_endpoint_redis_in_transit_encryption_enabled.metadata.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"Provider": "aws", | ||
"CheckID": "dms_endpoint_redis_in_transit_encryption_enabled", | ||
"CheckTitle": "Check if DMS endpoints for Redis OSS are encrypted in transit.", | ||
"CheckType": [ | ||
"Software and Configuration Checks/AWS Security Best Practices" | ||
], | ||
"ServiceName": "dms", | ||
"SubServiceName": "", | ||
"ResourceIdTemplate": "arn:aws:dms:region:account-id:endpoint/endpoint-id", | ||
"Severity": "medium", | ||
"ResourceType": "AwsDmsEndpoint", | ||
"Description": "This control checks whether an AWS DMS endpoint for Redis OSS is configured with a TLS connection. The control fails if the endpoint doesn't have TLS enabled.", | ||
"Risk": "Without TLS, data transmitted between databases may be vulnerable to interception or eavesdropping, increasing the risk of data breaches and other security incidents.", | ||
"RelatedUrl": "https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.Redis.html", | ||
"Remediation": { | ||
"Code": { | ||
"CLI": "aws dms modify-endpoint --endpoint-arn <endpoint-arn> --redis-settings '{'SslSecurityProtocol': 'ssl-encryption'}'", | ||
"NativeIaC": "", | ||
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/dms-controls.html#dms-12", | ||
"Terraform": "" | ||
}, | ||
"Recommendation": { | ||
"Text": "Enable TLS for DMS endpoints for Redis OSS to ensure encrypted communication during data migration.", | ||
"Url": "https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Redis.html#CHAP_Target.Redis.EndpointSettings" | ||
} | ||
}, | ||
"Categories": [], | ||
"DependsOn": [], | ||
"RelatedTo": [], | ||
"Notes": "" | ||
} |
42 changes: 42 additions & 0 deletions
42
...t_redis_in_transit_encryption_enabled/dms_endpoint_redis_in_transit_encryption_enabled.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from typing import List | ||
|
||
from prowler.lib.check.models import Check, Check_Report_AWS | ||
from prowler.providers.aws.services.dms.dms_client import dms_client | ||
|
||
|
||
class dms_endpoint_redis_in_transit_encryption_enabled(Check): | ||
""" | ||
Check if AWS DMS Endpoints for Redis OSS have TLS enabled. | ||
This class verifies whether each AWS DMS Endpoint configured for Redis OSS is encrypted in transit | ||
by checking the `TlsEnabled` property in the endpoint's configuration. The check ensures that | ||
TLS is enabled to secure data in transit, preventing unauthorized access and ensuring data integrity. | ||
""" | ||
|
||
def execute(self) -> List[Check_Report_AWS]: | ||
""" | ||
Execute the DMS Redis TLS enabled check. | ||
Iterates over all DMS Endpoints and generates a report indicating whether | ||
each Redis OSS endpoint is encrypted in transit. | ||
Returns: | ||
List[Check_Report_AWS]: A list of report objects with the results of the check. | ||
""" | ||
findings = [] | ||
for endpoint_arn, endpoint in dms_client.endpoints.items(): | ||
if endpoint.engine_name == "redis": | ||
report = Check_Report_AWS(self.metadata()) | ||
report.resource_id = endpoint.id | ||
report.resource_arn = endpoint_arn | ||
report.region = endpoint.region | ||
report.resource_tags = endpoint.tags | ||
report.status = "FAIL" | ||
report.status_extended = f"DMS Endpoint {endpoint.id} for Redis OSS is not encrypted in transit." | ||
if endpoint.redis_ssl_protocol == "ssl-encryption": | ||
report.status = "PASS" | ||
report.status_extended = f"DMS Endpoint {endpoint.id} for Redis OSS is encrypted in transit." | ||
|
||
findings.append(report) | ||
|
||
return findings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
6 changes: 6 additions & 0 deletions
6
prowler/providers/aws/services/servicecatalog/servicecatalog_client.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from prowler.providers.aws.services.servicecatalog.servicecatalog_service import ( | ||
ServiceCatalog, | ||
) | ||
from prowler.providers.common.provider import Provider | ||
|
||
servicecatalog_client = ServiceCatalog(Provider.get_global_provider()) |
101 changes: 101 additions & 0 deletions
101
prowler/providers/aws/services/servicecatalog/servicecatalog_service.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
from typing import Optional | ||
|
||
from pydantic import BaseModel | ||
|
||
from prowler.lib.logger import logger | ||
from prowler.lib.scan_filters.scan_filters import is_resource_filtered | ||
from prowler.providers.aws.lib.service.service import AWSService | ||
|
||
PORTFOLIO_SHARE_TYPES = [ | ||
"ACCOUNT", | ||
"ORGANIZATION", | ||
"ORGANIZATION_UNIT", | ||
"ORGANIZATION_MEMBER_ACCOUNT", | ||
] | ||
|
||
|
||
class ServiceCatalog(AWSService): | ||
def __init__(self, provider): | ||
# Call AWSService's __init__ | ||
super().__init__(__class__.__name__, provider) | ||
self.portfolios = {} | ||
self.__threading_call__(self._list_portfolios) | ||
self.__threading_call__( | ||
self._describe_portfolio_shares, self.portfolios.values() | ||
) | ||
self.__threading_call__(self._describe_portfolio, self.portfolios.values()) | ||
|
||
def _list_portfolios(self, regional_client): | ||
logger.info("ServiceCatalog - listing portfolios...") | ||
try: | ||
response = regional_client.list_portfolios() | ||
for portfolio in response["PortfolioDetails"]: | ||
portfolio_arn = portfolio["ARN"] | ||
if not self.audit_resources or ( | ||
is_resource_filtered(portfolio_arn, self.audit_resources) | ||
): | ||
self.portfolios[portfolio_arn] = Portfolio( | ||
arn=portfolio_arn, | ||
id=portfolio["Id"], | ||
name=portfolio["DisplayName"], | ||
region=regional_client.region, | ||
) | ||
except Exception as error: | ||
logger.error( | ||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" | ||
) | ||
|
||
def _describe_portfolio_shares(self, portfolio): | ||
try: | ||
logger.info("ServiceCatalog - describing portfolios shares...") | ||
try: | ||
regional_client = self.regional_clients[portfolio.region] | ||
for portfolio_type in PORTFOLIO_SHARE_TYPES: | ||
for share in regional_client.describe_portfolio_shares( | ||
PortfolioId=portfolio.id, | ||
Type=portfolio_type, | ||
).get("PortfolioShareDetails", []): | ||
portfolio_share = PortfolioShare( | ||
type=portfolio_type, | ||
accepted=share["Accepted"], | ||
) | ||
portfolio.shares.append(portfolio_share) | ||
except Exception as error: | ||
logger.error( | ||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" | ||
) | ||
except Exception as error: | ||
logger.error( | ||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" | ||
) | ||
|
||
def _describe_portfolio(self, portfolio): | ||
try: | ||
logger.info("ServiceCatalog - describing portfolios...") | ||
try: | ||
regional_client = self.regional_clients[portfolio.region] | ||
portfolio.tags = regional_client.describe_portfolio( | ||
PortfolioId=portfolio.id, | ||
)["Tags"] | ||
except Exception as error: | ||
logger.error( | ||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" | ||
) | ||
except Exception as error: | ||
logger.error( | ||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" | ||
) | ||
|
||
|
||
class PortfolioShare(BaseModel): | ||
type: str | ||
accepted: bool | ||
|
||
|
||
class Portfolio(BaseModel): | ||
id: str | ||
name: str | ||
arn: str | ||
region: str | ||
shares: Optional[list[PortfolioShare]] = [] | ||
tags: Optional[list] = [] |
66 changes: 66 additions & 0 deletions
66
tests/providers/aws/services/appsync/appsync_service_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from boto3 import client | ||
from mock import patch | ||
from moto import mock_aws | ||
|
||
from prowler.providers.aws.services.appsync.appsync_service import AppSync | ||
from tests.providers.aws.utils import ( | ||
AWS_ACCOUNT_NUMBER, | ||
AWS_REGION_US_EAST_1, | ||
set_mocked_aws_provider, | ||
) | ||
|
||
|
||
def mock_generate_regional_clients(provider, service): | ||
regional_client = provider._session.current_session.client( | ||
service, region_name=AWS_REGION_US_EAST_1 | ||
) | ||
regional_client.region = AWS_REGION_US_EAST_1 | ||
return {AWS_REGION_US_EAST_1: regional_client} | ||
|
||
|
||
@patch( | ||
"prowler.providers.aws.aws_provider.AwsProvider.generate_regional_clients", | ||
new=mock_generate_regional_clients, | ||
) | ||
class Test_AppSync_Service: | ||
# Test AppSync Service | ||
def test_service(self): | ||
aws_provider = set_mocked_aws_provider() | ||
appsync = AppSync(aws_provider) | ||
assert appsync.service == "appsync" | ||
|
||
# Test AppSync Client | ||
def test_client(self): | ||
aws_provider = set_mocked_aws_provider() | ||
appsync = AppSync(aws_provider) | ||
assert appsync.client.__class__.__name__ == "AppSync" | ||
|
||
# Test AppSync Session | ||
def test__get_session__(self): | ||
aws_provider = set_mocked_aws_provider() | ||
appsync = AppSync(aws_provider) | ||
assert appsync.session.__class__.__name__ == "Session" | ||
|
||
# Test AppSync Session | ||
def test_audited_account(self): | ||
aws_provider = set_mocked_aws_provider() | ||
appsync = AppSync(aws_provider) | ||
assert appsync.audited_account == AWS_ACCOUNT_NUMBER | ||
|
||
# Test AppSync Describe File Systems | ||
@mock_aws | ||
def test_list_graphql_apis(self): | ||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) | ||
appsync = client("appsync", region_name=AWS_REGION_US_EAST_1) | ||
api = appsync.create_graphql_api( | ||
name="test-api", | ||
authenticationType="API_KEY", | ||
logConfig={"fieldLogLevel": "ALL", "cloudWatchLogsRoleArn": "test"}, | ||
) | ||
api_arn = api["graphqlApi"]["arn"] | ||
appsync_client = AppSync(aws_provider) | ||
|
||
assert appsync_client.graphql_apis[api_arn].name == "test-api" | ||
assert appsync_client.graphql_apis[api_arn].field_log_level == "ALL" | ||
assert appsync_client.graphql_apis[api_arn].authentication_type == "API_KEY" | ||
assert appsync_client.graphql_apis[api_arn].tags == [{}] |
Oops, something went wrong.