From 853b833cfb342f3879d7594ddf90eba551972f42 Mon Sep 17 00:00:00 2001 From: Amogh Bantwal <100332169+abant07@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:13:43 -0700 Subject: [PATCH] feat(aws): Add new check `opensearch_service_domains_access_control_enabled ` (#5203) Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com> --- .../services/opensearch/opensearch_service.py | 4 + ...mains_access_control_enabled.metadata.json | 30 ++++++ ..._service_domains_access_control_enabled.py | 24 +++++ ...ice_domains_access_control_enabled_test.py | 94 +++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled.metadata.json create mode 100644 prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled.py create mode 100644 tests/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled_test.py diff --git a/prowler/providers/aws/services/opensearch/opensearch_service.py b/prowler/providers/aws/services/opensearch/opensearch_service.py index ddb8cfdf8e..5b4c3fb162 100644 --- a/prowler/providers/aws/services/opensearch/opensearch_service.py +++ b/prowler/providers/aws/services/opensearch/opensearch_service.py @@ -127,6 +127,9 @@ class OpenSearchService(AWSService): "ServiceSoftwareOptions" ]["UpdateAvailable"] domain.version = describe_domain["DomainStatus"]["EngineVersion"] + domain.advanced_settings_enabled = describe_domain["DomainStatus"][ + "AdvancedSecurityOptions" + ]["Enabled"] except Exception as error: logger.error( f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" @@ -169,3 +172,4 @@ class OpenSearchDomain(BaseModel): update_available: bool = None version: str = None tags: Optional[list] = [] + advanced_settings_enabled: bool = None diff --git a/prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled.metadata.json b/prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled.metadata.json new file mode 100644 index 0000000000..710f09535f --- /dev/null +++ b/prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "aws", + "CheckID": "opensearch_service_domains_access_control_enabled", + "CheckTitle": "Check if Amazon Elasticsearch/Opensearch Service domains have fine grained access control enabled", + "CheckType": [], + "ServiceName": "opensearch", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "high", + "ResourceType": "AwsOpenSearchServiceDomain", + "Description": "Check if Amazon Elasticsearch/Opensearch Service domains have fine grained access control enabled", + "Risk": "Amazon ES's fine graine access control enhances security by verifying that access to OpenSearch domains is controlled at a granular level, allowing for more precise permissions management and reducing the risk of unauthorised access.", + "RelatedUrl": "https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/opensearch-controls.html#opensearch-7", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable fine grained access control for your OpenSearch domains", + "Url": "https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html#fgac-enabling" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled.py b/prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled.py new file mode 100644 index 0000000000..2427be6878 --- /dev/null +++ b/prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled.py @@ -0,0 +1,24 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.opensearch.opensearch_client import ( + opensearch_client, +) + + +class opensearch_service_domains_access_control_enabled(Check): + def execute(self): + findings = [] + for domain in opensearch_client.opensearch_domains: + report = Check_Report_AWS(self.metadata()) + report.region = domain.region + report.resource_id = domain.name + report.resource_arn = domain.arn + report.resource_tags = domain.tags + report.status = "FAIL" + report.status_extended = f"Opensearch domain {domain.name} does not have fine grained access control enabled." + if domain.advanced_settings_enabled: + report.status = "PASS" + report.status_extended = f"Opensearch domain {domain.name} has fine grained access control enabled." + + findings.append(report) + + return findings diff --git a/tests/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled_test.py b/tests/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled_test.py new file mode 100644 index 0000000000..c679dd1965 --- /dev/null +++ b/tests/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/opensearch_service_domains_access_control_enabled_test.py @@ -0,0 +1,94 @@ +from re import search +from unittest import mock + +from prowler.providers.aws.services.opensearch.opensearch_service import ( + OpenSearchDomain, +) +from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1 + +domain_name = "test-domain" +domain_arn = f"arn:aws:es:us-west-2:{AWS_ACCOUNT_NUMBER}:domain/{domain_name}" + + +class Test_opensearch_service_domains_access_control_enabled: + def test_no_domains(self): + opensearch_client = mock.MagicMock + opensearch_client.opensearch_domains = [] + + with mock.patch( + "prowler.providers.aws.services.opensearch.opensearch_service.OpenSearchService", + new=opensearch_client, + ), mock.patch( + "prowler.providers.aws.services.opensearch.opensearch_service_domains_access_control_enabled.opensearch_service_domains_access_control_enabled.opensearch_client", + new=opensearch_client, + ): + from prowler.providers.aws.services.opensearch.opensearch_service_domains_access_control_enabled.opensearch_service_domains_access_control_enabled import ( + opensearch_service_domains_access_control_enabled, + ) + + check = opensearch_service_domains_access_control_enabled() + result = check.execute() + assert len(result) == 0 + + def test_no_fine_grained_access_enabled(self): + opensearch_client = mock.MagicMock + opensearch_client.opensearch_domains = [] + opensearch_client.opensearch_domains.append( + OpenSearchDomain( + name=domain_name, region=AWS_REGION_EU_WEST_1, arn=domain_arn + ) + ) + opensearch_client.opensearch_domains[0].advanced_settings_enabled = False + + with mock.patch( + "prowler.providers.aws.services.opensearch.opensearch_service.OpenSearchService", + new=opensearch_client, + ), mock.patch( + "prowler.providers.aws.services.opensearch.opensearch_service_domains_access_control_enabled.opensearch_service_domains_access_control_enabled.opensearch_client", + new=opensearch_client, + ): + from prowler.providers.aws.services.opensearch.opensearch_service_domains_access_control_enabled.opensearch_service_domains_access_control_enabled import ( + opensearch_service_domains_access_control_enabled, + ) + + check = opensearch_service_domains_access_control_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert search( + "does not have fine grained access control enabled.", + result[0].status_extended, + ) + assert result[0].resource_id == domain_name + assert result[0].resource_arn == domain_arn + + def test_logging_AUDIT_LOGS_enabled(self): + opensearch_client = mock.MagicMock + opensearch_client.opensearch_domains = [] + opensearch_client.opensearch_domains.append( + OpenSearchDomain( + name=domain_name, region=AWS_REGION_EU_WEST_1, arn=domain_arn + ) + ) + opensearch_client.opensearch_domains[0].advanced_settings_enabled = True + + with mock.patch( + "prowler.providers.aws.services.opensearch.opensearch_service.OpenSearchService", + new=opensearch_client, + ), mock.patch( + "prowler.providers.aws.services.opensearch.opensearch_service_domains_access_control_enabled.opensearch_service_domains_access_control_enabled.opensearch_client", + new=opensearch_client, + ): + from prowler.providers.aws.services.opensearch.opensearch_service_domains_access_control_enabled.opensearch_service_domains_access_control_enabled import ( + opensearch_service_domains_access_control_enabled, + ) + + check = opensearch_service_domains_access_control_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert search( + "has fine grained access control enabled.", result[0].status_extended + ) + assert result[0].resource_id == domain_name + assert result[0].resource_arn == domain_arn