Skip to content

Commit

Permalink
feat(apigateway): add new check apigateway_restapi_tracing_enabled (#…
Browse files Browse the repository at this point in the history
…5470)

Co-authored-by: Sergio <[email protected]>
  • Loading branch information
danibarranqueroo and sergargar authored Oct 21, 2024
1 parent 5b0868e commit d00afbd
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 0 deletions.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"Provider": "aws",
"CheckID": "apigateway_restapi_tracing_enabled",
"CheckTitle": "Check if AWS X-Ray tracing is enabled for API Gateway REST API stages.",
"CheckType": [
"Software and Configuration Checks/AWS Security Best Practices"
],
"ServiceName": "apigateway",
"SubServiceName": "",
"ResourceIdTemplate": "arn:aws:apigateway:region:account-id:/restapis/restapi-id/stages/stage-name",
"Severity": "low",
"ResourceType": "AwsApiGatewayStage",
"Description": "This control checks whether AWS X-Ray active tracing is enabled for your Amazon API Gateway REST API stages.",
"Risk": "Without X-Ray active tracing, it may be difficult to quickly identify and respond to performance issues that could lead to decreased availability or degradation of the API's performance.",
"RelatedUrl": "https://docs.aws.amazon.com/xray/latest/devguide/xray-services-apigateway.html",
"Remediation": {
"Code": {
"CLI": "aws apigateway update-stage --rest-api-id <restapi-id> --stage-name <stage-name> --patch-operations op=replace,path=/tracingEnabled,value=true",
"NativeIaC": "",
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/apigateway-controls.html#apigateway-3",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable AWS X-Ray tracing for API Gateway REST API stages to monitor and analyze performance in real time.",
"Url": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/APIGateway/tracing.html"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.apigateway.apigateway_client import (
apigateway_client,
)


class apigateway_restapi_tracing_enabled(Check):
def execute(self):
findings = []
for rest_api in apigateway_client.rest_apis:
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
report.resource_tags = stage.tags
report.status = "FAIL"
report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} in stage {stage.name} does not have X-Ray tracing enabled."
if stage.tracing_enabled:
report.status = "PASS"
report.status_extended = f"API Gateway {rest_api.name} ID {rest_api.id} in stage {stage.name} has X-Ray tracing enabled."
findings.append(report)

return findings
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ def _get_stages(self):
waf = None
logging = False
client_certificate = False
tracing_enabled = False
if "tracingEnabled" in stage:
if stage["tracingEnabled"]:
tracing_enabled = True
cache_enabled = False
cache_data_encrypted = False
if "webAclArn" in stage:
Expand All @@ -137,6 +141,7 @@ def _get_stages(self):
client_certificate=client_certificate,
waf=waf,
tags=[stage.get("tags")],
tracing_enabled=tracing_enabled,
cache_enabled=cache_enabled,
cache_data_encrypted=cache_data_encrypted,
)
Expand Down Expand Up @@ -222,6 +227,7 @@ class Stage(BaseModel):
client_certificate: bool
waf: Optional[str]
tags: Optional[list] = []
tracing_enabled: Optional[bool]
cache_enabled: Optional[bool]
cache_data_encrypted: Optional[bool]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
from unittest import mock

from boto3 import client
from moto import mock_aws

from tests.providers.aws.utils import (
AWS_REGION_EU_WEST_1,
AWS_REGION_US_EAST_1,
set_mocked_aws_provider,
)


class Test_apigateway_restapi_tracing_enabled:
@mock_aws
def test_apigateway_no_rest_apis(self):
from prowler.providers.aws.services.apigateway.apigateway_service import (
APIGateway,
)

aws_provider = set_mocked_aws_provider(
[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
)

with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
), mock.patch(
"prowler.providers.aws.services.apigateway.apigateway_restapi_tracing_enabled.apigateway_restapi_tracing_enabled.apigateway_client",
new=APIGateway(aws_provider),
):
# Test Check
from prowler.providers.aws.services.apigateway.apigateway_restapi_tracing_enabled.apigateway_restapi_tracing_enabled import (
apigateway_restapi_tracing_enabled,
)

check = apigateway_restapi_tracing_enabled()
result = check.execute()

assert len(result) == 0

@mock_aws
def test_apigateway_one_rest_api_with_logging(self):
# Create APIGateway Mocked Resources
apigateway_client = client("apigateway", region_name=AWS_REGION_US_EAST_1)
rest_api = apigateway_client.create_rest_api(
name="test-rest-api",
)
# Get the rest api's root id
root_resource_id = apigateway_client.get_resources(restApiId=rest_api["id"])[
"items"
][0]["id"]
resource = apigateway_client.create_resource(
restApiId=rest_api["id"],
parentId=root_resource_id,
pathPart="test-path",
)
apigateway_client.put_method(
restApiId=rest_api["id"],
resourceId=resource["id"],
httpMethod="GET",
authorizationType="NONE",
)
apigateway_client.put_integration(
restApiId=rest_api["id"],
resourceId=resource["id"],
httpMethod="GET",
type="HTTP",
integrationHttpMethod="POST",
uri="http://test.com",
)
apigateway_client.create_deployment(
restApiId=rest_api["id"],
stageName="test",
)
apigateway_client.update_stage(
restApiId=rest_api["id"],
stageName="test",
patchOperations=[
{
"op": "replace",
"path": "/tracingEnabled",
"value": "true",
},
],
)
from prowler.providers.aws.services.apigateway.apigateway_service import (
APIGateway,
)

aws_provider = set_mocked_aws_provider(
[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
)

with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
), mock.patch(
"prowler.providers.aws.services.apigateway.apigateway_restapi_tracing_enabled.apigateway_restapi_tracing_enabled.apigateway_client",
new=APIGateway(aws_provider),
):
# Test Check
from prowler.providers.aws.services.apigateway.apigateway_restapi_tracing_enabled.apigateway_restapi_tracing_enabled import (
apigateway_restapi_tracing_enabled,
)

check = apigateway_restapi_tracing_enabled()
result = check.execute()

assert result[0].status == "PASS"
assert len(result) == 1
assert (
result[0].status_extended
== f"API Gateway test-rest-api ID {rest_api['id']} in stage test has X-Ray tracing enabled."
)
assert result[0].resource_id == "test-rest-api"
assert (
result[0].resource_arn
== f"arn:{aws_provider.identity.partition}:apigateway:{AWS_REGION_US_EAST_1}::/restapis/{rest_api['id']}/stages/test"
)
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_tags == [None]

@mock_aws
def test_apigateway_one_rest_api_without_logging(self):
# Create APIGateway Mocked Resources
apigateway_client = client("apigateway", region_name=AWS_REGION_US_EAST_1)
# Create APIGateway Rest API
rest_api = apigateway_client.create_rest_api(
name="test-rest-api",
)
# Get the rest api's root id
root_resource_id = apigateway_client.get_resources(restApiId=rest_api["id"])[
"items"
][0]["id"]
resource = apigateway_client.create_resource(
restApiId=rest_api["id"],
parentId=root_resource_id,
pathPart="test-path",
)
apigateway_client.put_method(
restApiId=rest_api["id"],
resourceId=resource["id"],
httpMethod="GET",
authorizationType="NONE",
)
apigateway_client.put_integration(
restApiId=rest_api["id"],
resourceId=resource["id"],
httpMethod="GET",
type="HTTP",
integrationHttpMethod="POST",
uri="http://test.com",
)
apigateway_client.create_deployment(
restApiId=rest_api["id"],
stageName="test",
)
apigateway_client.update_stage(
restApiId=rest_api["id"],
stageName="test",
patchOperations=[
{
"op": "replace",
"path": "/tracingEnabled",
"value": "false",
},
],
)

from prowler.providers.aws.services.apigateway.apigateway_service import (
APIGateway,
)

aws_provider = set_mocked_aws_provider(
[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
)

with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
), mock.patch(
"prowler.providers.aws.services.apigateway.apigateway_restapi_tracing_enabled.apigateway_restapi_tracing_enabled.apigateway_client",
new=APIGateway(aws_provider),
):
# Test Check
from prowler.providers.aws.services.apigateway.apigateway_restapi_tracing_enabled.apigateway_restapi_tracing_enabled import (
apigateway_restapi_tracing_enabled,
)

check = apigateway_restapi_tracing_enabled()
result = check.execute()

assert result[0].status == "FAIL"
assert len(result) == 1
assert (
result[0].status_extended
== f"API Gateway test-rest-api ID {rest_api['id']} in stage test does not have X-Ray tracing enabled."
)
assert result[0].resource_id == "test-rest-api"
assert (
result[0].resource_arn
== f"arn:{aws_provider.identity.partition}:apigateway:{AWS_REGION_US_EAST_1}::/restapis/{rest_api['id']}/stages/test"
)
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_tags == [None]
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ def test_get_stages(self):
"path": "/*/*/logging/loglevel",
"value": "INFO",
},
{
"op": "replace",
"path": "/tracingEnabled",
"value": "true",
},
{
"op": "replace",
"path": "/*/*/caching/enabled",
Expand All @@ -156,6 +161,7 @@ def test_get_stages(self):
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
apigateway = APIGateway(aws_provider)
assert apigateway.rest_apis[0].stages[0].logging is True
assert apigateway.rest_apis[0].stages[0].tracing_enabled is True
assert apigateway.rest_apis[0].stages[0].cache_enabled is True
assert apigateway.rest_apis[0].stages[0].cache_data_encrypted is False

Expand Down

0 comments on commit d00afbd

Please sign in to comment.