Review API Gateway stage logging

Configure API Gateway stage access logs separately from the execution logs you need.

Description

API Gateway access logs can record request identifiers and response status, while execution logs help investigate processing errors. These are separate settings. Without the required logs, requests and failures are harder to trace.

API Gateway is often an entry point for external requests. Missing access records reduce the evidence available for troubleshooting, abuse investigation and incident response.

Potential impact

  • Request activity can be harder to trace.
  • Investigating abnormal calls or attempted attacks can take longer.
  • Error patterns and usage changes can be harder to analyze.

Remediation

  • Configure access_log_settings on the stage to collect access logs.
  • When execution logs are needed, set aws_api_gateway_method_settings.settings.logging_level for REST APIs or default_route_settings.logging_level for WebSocket APIs. These execution logging settings do not apply to HTTP APIs.
  • Configure the destination, format, delivery permissions and retention, then verify actual collection. Limit sensitive request data in logs.

Examples

These are REST API stage and method-setting excerpts. Configure the referenced API, deployment, log group and CloudWatch log delivery permissions separately.

Before

hcl
resource "aws_api_gateway_stage" "example" {
  stage_name    = "dev"
  rest_api_id   = aws_api_gateway_rest_api.example.id
  deployment_id = aws_api_gateway_deployment.example.id
}

resource "aws_api_gateway_method_settings" "example" {
  rest_api_id = aws_api_gateway_rest_api.example.id
  stage_name  = aws_api_gateway_stage.example.stage_name
  method_path = "*/*"

  settings {
    logging_level = "ERROR"
  }
}

After

hcl
resource "aws_api_gateway_stage" "example" {
  stage_name    = "dev"
  rest_api_id   = aws_api_gateway_rest_api.example.id
  deployment_id = aws_api_gateway_deployment.example.id

  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.example.arn
    format = jsonencode({ requestId = "$context.requestId", status = "$context.status" })
  }
}

resource "aws_api_gateway_method_settings" "example" {
  rest_api_id = aws_api_gateway_rest_api.example.id
  stage_name  = aws_api_gateway_stage.example.stage_name
  method_path = "*/*"

  settings {
    metrics_enabled = true
    logging_level   = "ERROR"
  }
}

Explanation:

  • Before: An execution logging level is set, but this stage has no access log delivery configuration.
  • After: Access logs record request identifiers and status, alongside execution error logging. Verify actual delivery.

References