From 64090474e1f7dd9b91fbc50a0d00c98d8338c475 Mon Sep 17 00:00:00 2001 From: Gabriel Soltz Date: Mon, 16 Jan 2023 10:23:14 +0100 Subject: [PATCH] fix(apigateway): Add ApiGateway ResourceArn and check fixes (#1707) Co-authored-by: sergargar --- .../apigateway_authorizers_enabled.py | 4 ++-- ...pigateway_client_certificate_enabled.metadata.json | 6 +++--- .../apigateway_client_certificate_enabled.py | 7 +++---- .../apigateway_endpoint_public.py | 4 ++-- .../apigateway_logging_enabled.metadata.json | 6 +++--- .../apigateway_logging_enabled.py | 8 ++++---- .../aws/services/apigateway/apigateway_service.py | 11 +++++++++++ .../apigateway_waf_acl_attached.metadata.json | 6 +++--- .../apigateway_waf_acl_attached.py | 8 ++++---- .../apigateway_authorizers_enabled_test.py | 8 ++++++++ .../apigateway_client_certificate_enabled_test.py | 9 +++++++++ .../apigateway_endpoint_public_test.py | 8 ++++++++ .../apigateway_logging_enabled_test.py | 8 ++++++++ .../apigateway_waf_acl_attached_test.py | 8 ++++++++ 14 files changed, 76 insertions(+), 25 deletions(-) diff --git a/prowler/providers/aws/services/apigateway/apigateway_authorizers_enabled/apigateway_authorizers_enabled.py b/prowler/providers/aws/services/apigateway/apigateway_authorizers_enabled/apigateway_authorizers_enabled.py index b1b247c3..cf39a792 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_authorizers_enabled/apigateway_authorizers_enabled.py +++ b/prowler/providers/aws/services/apigateway/apigateway_authorizers_enabled/apigateway_authorizers_enabled.py @@ -10,14 +10,14 @@ class apigateway_authorizers_enabled(Check): for rest_api in apigateway_client.rest_apis: report = Check_Report_AWS(self.metadata()) report.region = rest_api.region + report.resource_id = rest_api.name + report.resource_arn = rest_api.arn if rest_api.authorizer: report.status = "PASS" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} has authorizer configured." - report.resource_id = rest_api.name else: report.status = "FAIL" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} has not authorizer configured." - report.resource_id = rest_api.name findings.append(report) return findings diff --git a/prowler/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled.metadata.json b/prowler/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled.metadata.json index 6fbff154..8fdb67db 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled.metadata.json +++ b/prowler/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled.metadata.json @@ -1,7 +1,7 @@ { "Provider": "aws", "CheckID": "apigateway_client_certificate_enabled", - "CheckTitle": "Check if API Gateway has client certificate enabled to access your backend endpoint.", + "CheckTitle": "Check if API Gateway Stage has client certificate enabled to access your backend endpoint.", "CheckType": [ "Data Protection" ], @@ -9,8 +9,8 @@ "SubServiceName": "rest_api", "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", "Severity": "medium", - "ResourceType": "AwsApiGatewayRestApi", - "Description": "Check if API Gateway has client certificate enabled to access your backend endpoint.", + "ResourceType": "AwsApiGatewayStage", + "Description": "Check if API Gateway Stage has client certificate enabled to access your backend endpoint.", "Risk": "Possible man in the middle attacks and other similar risks.", "RelatedUrl": "", "Remediation": { diff --git a/prowler/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled.py b/prowler/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled.py index f29be7d4..391ede9d 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled.py +++ b/prowler/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled.py @@ -10,16 +10,15 @@ class apigateway_client_certificate_enabled(Check): for rest_api in apigateway_client.rest_apis: for stage in rest_api.stages: report = Check_Report_AWS(self.metadata()) + report.resource_id = rest_api.name + report.region = rest_api.region + report.resource_arn = stage.arn if stage.client_certificate: report.status = "PASS" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} in stage {stage.name} has client certificate enabled." - report.resource_id = rest_api.name - report.region = rest_api.region else: report.status = "FAIL" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} in stage {stage.name} has not client certificate enabled." - report.resource_id = rest_api.name - report.region = rest_api.region findings.append(report) return findings diff --git a/prowler/providers/aws/services/apigateway/apigateway_endpoint_public/apigateway_endpoint_public.py b/prowler/providers/aws/services/apigateway/apigateway_endpoint_public/apigateway_endpoint_public.py index 3ad47c8e..dd48255b 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_endpoint_public/apigateway_endpoint_public.py +++ b/prowler/providers/aws/services/apigateway/apigateway_endpoint_public/apigateway_endpoint_public.py @@ -10,16 +10,16 @@ class apigateway_endpoint_public(Check): for rest_api in apigateway_client.rest_apis: report = Check_Report_AWS(self.metadata()) report.region = rest_api.region + report.resource_id = rest_api.name + report.resource_arn = rest_api.arn if rest_api.public_endpoint: report.status = "FAIL" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} is internet accesible." - report.resource_id = rest_api.name else: report.status = "PASS" report.status_extended = ( f"API Gateway {rest_api.name} ID {rest_api.id} is private." ) - report.resource_id = rest_api.name findings.append(report) return findings diff --git a/prowler/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled.metadata.json b/prowler/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled.metadata.json index 5e328d57..fefb95cd 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled.metadata.json +++ b/prowler/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled.metadata.json @@ -1,7 +1,7 @@ { "Provider": "aws", "CheckID": "apigateway_logging_enabled", - "CheckTitle": "Check if API Gateway has logging enabled.", + "CheckTitle": "Check if API Gateway Stage has logging enabled.", "CheckType": [ "Logging and Monitoring" ], @@ -9,8 +9,8 @@ "SubServiceName": "rest_api", "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", "Severity": "medium", - "ResourceType": "AwsApiGatewayRestApi", - "Description": "Check if API Gateway has logging enabled.", + "ResourceType": "AwsApiGatewayStage", + "Description": "Check if API Gateway Stage has logging enabled.", "Risk": "If not enabled, monitoring of service use is not possible. Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms.", "RelatedUrl": "", "Remediation": { diff --git a/prowler/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled.py b/prowler/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled.py index a3763a95..e4e84c92 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled.py +++ b/prowler/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled.py @@ -8,17 +8,17 @@ class apigateway_logging_enabled(Check): def execute(self): findings = [] for rest_api in apigateway_client.rest_apis: - report = Check_Report_AWS(self.metadata()) - report.region = rest_api.region for stage in rest_api.stages: + report = Check_Report_AWS(self.metadata()) + report.region = rest_api.region + report.resource_id = rest_api.name + report.resource_arn = stage.arn if stage.logging: report.status = "PASS" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} in stage {stage.name} has logging enabled." - report.resource_id = rest_api.name else: report.status = "FAIL" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} in stage {stage.name} has logging disabled." - report.resource_id = rest_api.name findings.append(report) return findings diff --git a/prowler/providers/aws/services/apigateway/apigateway_service.py b/prowler/providers/aws/services/apigateway/apigateway_service.py index cdccbb58..cec35a36 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_service.py +++ b/prowler/providers/aws/services/apigateway/apigateway_service.py @@ -11,6 +11,7 @@ class APIGateway: self.service = "apigateway" self.session = audit_info.audit_session self.audited_account = audit_info.audited_account + self.audited_partition = audit_info.audited_partition self.regional_clients = generate_regional_clients(self.service, audit_info) self.rest_apis = [] self.__threading_call__(self.__get_rest_apis__) @@ -36,9 +37,11 @@ class APIGateway: get_rest_apis_paginator = regional_client.get_paginator("get_rest_apis") for page in get_rest_apis_paginator.paginate(): for apigw in page["items"]: + arn = f"arn:{self.audited_partition}:apigateway:{regional_client.region}::/apis/{apigw['id']}" self.rest_apis.append( RestAPI( apigw["id"], + arn, regional_client.region, apigw["name"], ) @@ -89,9 +92,11 @@ class APIGateway: logging = True if "clientCertificateId" in stage: client_certificate = True + arn = f"arn:{self.audited_partition}:apigateway:{regional_client.region}::/apis/{rest_api.id}/stages/{stage['stageName']}" rest_api.stages.append( Stage( stage["stageName"], + arn, logging, client_certificate, waf, @@ -104,6 +109,7 @@ class APIGateway: @dataclass class Stage: name: str + arn: str logging: bool client_certificate: bool waf: str @@ -111,11 +117,13 @@ class Stage: def __init__( self, name, + arn, logging, client_certificate, waf, ): self.name = name + self.arn = arn self.logging = logging self.client_certificate = client_certificate self.waf = waf @@ -124,6 +132,7 @@ class Stage: @dataclass class RestAPI: id: str + arn: str region: str name: str authorizer: bool @@ -133,10 +142,12 @@ class RestAPI: def __init__( self, id, + arn, region, name, ): self.id = id + self.arn = arn self.region = region self.name = name self.authorizer = False diff --git a/prowler/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached.metadata.json b/prowler/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached.metadata.json index 835e3662..e733b663 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached.metadata.json +++ b/prowler/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached.metadata.json @@ -1,7 +1,7 @@ { "Provider": "aws", "CheckID": "apigateway_waf_acl_attached", - "CheckTitle": "Check if API Gateway has a WAF ACL attached.", + "CheckTitle": "Check if API Gateway Stage has a WAF ACL attached.", "CheckType": [ "Infrastructure Security" ], @@ -9,8 +9,8 @@ "SubServiceName": "rest_api", "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", "Severity": "medium", - "ResourceType": "AwsApiGatewayRestApi", - "Description": "Check if API Gateway has a WAF ACL attached.", + "ResourceType": "AwsApiGatewayStage", + "Description": "Check if API Gateway Stage has a WAF ACL attached.", "Risk": "Potential attacks and / or abuse of service, more even for even for internet reachable services.", "RelatedUrl": "", "Remediation": { diff --git a/prowler/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached.py b/prowler/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached.py index 128a04ce..68cc887d 100644 --- a/prowler/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached.py +++ b/prowler/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached.py @@ -8,17 +8,17 @@ class apigateway_waf_acl_attached(Check): def execute(self): findings = [] for rest_api in apigateway_client.rest_apis: - report = Check_Report_AWS(self.metadata()) - report.region = rest_api.region for stage in rest_api.stages: + report = Check_Report_AWS(self.metadata()) + report.region = rest_api.region + report.resource_id = rest_api.name + report.resource_arn = stage.arn if stage.waf: report.status = "PASS" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} in stage {stage.name} has {stage.waf} WAF ACL attached." - report.resource_id = rest_api.name else: report.status = "FAIL" report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} in stage {stage.name} has not WAF ACL attached." - report.resource_id = rest_api.name findings.append(report) return findings diff --git a/tests/providers/aws/services/apigateway/apigateway_authorizers_enabled/apigateway_authorizers_enabled_test.py b/tests/providers/aws/services/apigateway/apigateway_authorizers_enabled/apigateway_authorizers_enabled_test.py index 0b15333c..4ccb9f18 100644 --- a/tests/providers/aws/services/apigateway/apigateway_authorizers_enabled/apigateway_authorizers_enabled_test.py +++ b/tests/providers/aws/services/apigateway/apigateway_authorizers_enabled/apigateway_authorizers_enabled_test.py @@ -88,6 +88,10 @@ class Test_apigateway_authorizers_enabled: == f"API Gateway test-rest-api ID {rest_api['id']} has authorizer configured." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}" + ) @mock_apigateway def test_apigateway_one_rest_api_without_lambda_authorizer(self): @@ -123,3 +127,7 @@ class Test_apigateway_authorizers_enabled: == f"API Gateway test-rest-api ID {rest_api['id']} has not authorizer configured." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}" + ) diff --git a/tests/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled_test.py b/tests/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled_test.py index dbdb3026..d373bdfc 100644 --- a/tests/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled_test.py +++ b/tests/providers/aws/services/apigateway/apigateway_client_certificate_enabled/apigateway_client_certificate_enabled_test.py @@ -99,6 +99,10 @@ class Test_apigateway_client_certificate_enabled: == f"API Gateway test-rest-api ID {rest_api['id']} in stage test has not client certificate enabled." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}/stages/test" + ) @mock_apigateway def test_apigateway_one_stage_with_certificate(self): @@ -128,6 +132,7 @@ class Test_apigateway_client_certificate_enabled: service_client.rest_apis[0].stages.append( Stage( "test", + f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/test-rest-api/stages/test", logging=True, client_certificate=True, waf=True, @@ -144,3 +149,7 @@ class Test_apigateway_client_certificate_enabled: == f"API Gateway test-rest-api ID {rest_api['id']} in stage test has client certificate enabled." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/test-rest-api/stages/test" + ) diff --git a/tests/providers/aws/services/apigateway/apigateway_endpoint_public/apigateway_endpoint_public_test.py b/tests/providers/aws/services/apigateway/apigateway_endpoint_public/apigateway_endpoint_public_test.py index cf6f8955..ca540a7a 100644 --- a/tests/providers/aws/services/apigateway/apigateway_endpoint_public/apigateway_endpoint_public_test.py +++ b/tests/providers/aws/services/apigateway/apigateway_endpoint_public/apigateway_endpoint_public_test.py @@ -69,6 +69,10 @@ class Test_apigateway_endpoint_public: == f"API Gateway test-rest-api ID {rest_api['id']} is private." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}" + ) @mock_apigateway def test_apigateway_one_public_rest_api(self): @@ -109,3 +113,7 @@ class Test_apigateway_endpoint_public: == f"API Gateway test-rest-api ID {rest_api['id']} is internet accesible." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}" + ) diff --git a/tests/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled_test.py b/tests/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled_test.py index 58a00f0d..83d55518 100644 --- a/tests/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled_test.py +++ b/tests/providers/aws/services/apigateway/apigateway_logging_enabled/apigateway_logging_enabled_test.py @@ -101,6 +101,10 @@ class Test_apigateway_logging_enabled: == f"API Gateway test-rest-api ID {rest_api['id']} in stage test has logging enabled." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}/stages/test" + ) @mock_apigateway def test_apigateway_one_rest_api_without_logging(self): @@ -164,3 +168,7 @@ class Test_apigateway_logging_enabled: == f"API Gateway test-rest-api ID {rest_api['id']} in stage test has logging disabled." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}/stages/test" + ) diff --git a/tests/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached_test.py b/tests/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached_test.py index 6cd18cb9..8c9ddb3e 100644 --- a/tests/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached_test.py +++ b/tests/providers/aws/services/apigateway/apigateway_waf_acl_attached/apigateway_waf_acl_attached_test.py @@ -107,6 +107,10 @@ class Test_apigateway_waf_acl_attached: == f"API Gateway test-rest-api ID {rest_api['id']} in stage test has {waf_arn} WAF ACL attached." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}/stages/test" + ) @mock_apigateway def test_apigateway_one_rest_api_without_waf(self): @@ -170,3 +174,7 @@ class Test_apigateway_waf_acl_attached: == f"API Gateway test-rest-api ID {rest_api['id']} in stage test has not WAF ACL attached." ) assert result[0].resource_id == "test-rest-api" + assert ( + result[0].resource_arn + == f"arn:{current_audit_info.audited_partition}:apigateway:{AWS_REGION}::/apis/{rest_api['id']}/stages/test" + )