API Gateway Stage Has a WAF Web ACL Attached
Overview
This check verifies that your Amazon API Gateway REST API stages have an AWS WAF (Web Application Firewall) web ACL attached. WAF provides a layer of protection that filters and monitors HTTP/HTTPS requests to your API, helping block common web exploits and attacks.
Risk
Without WAF protection, your API Gateway endpoints are exposed to application-layer threats:
- Data exposure: Attackers can exploit injection vulnerabilities (SQL injection, command injection) to access sensitive data
- Data tampering: Parameter manipulation and path traversal attacks can compromise data integrity
- Service disruption: Layer 7 DDoS attacks, bot abuse, and resource exhaustion can make your API unavailable
Public-facing APIs are particularly vulnerable without WAF protection.
Severity: Medium
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to modify API Gateway and WAF settings
- An existing WAF web ACL, or permission to create one
Required IAM permissions (for reference)
To perform this remediation, you need the following permissions:
wafv2:AssociateWebACLwafv2:ListWebACLswafv2:CreateWebACL(if creating a new web ACL)apigateway:GET(to view API Gateway resources)
AWS Console Method
Step 1: Identify the API Gateway Stage
- Sign in to the AWS Console
- Navigate to API Gateway (search for it in the search bar)
- Select APIs from the left sidebar
- Click on the REST API that Prowler flagged
- In the left sidebar, click Stages
- Note the stage name(s) that need WAF protection (e.g.,
prod,dev)
Step 2: Create or Identify a WAF Web ACL
If you already have a WAF web ACL to use, skip to Step 3.
- Open a new browser tab and navigate to WAF & Shield (search for it in the search bar)
- In the left sidebar, click Web ACLs
- Ensure you are in the correct region (e.g., US East (N. Virginia) for us-east-1)
- Click Create web ACL
- Configure the web ACL:
- Name: Enter a descriptive name (e.g.,
my-api-gateway-waf) - Description: Optional description
- CloudWatch metric name: Auto-populated based on the name
- Resource type: Select Regional resources
- Region: Select US East (N. Virginia) (us-east-1)
- Name: Enter a descriptive name (e.g.,
- Click Next
- Add rules (recommended starting point):
- Click Add rules > Add managed rule groups
- Expand AWS managed rule groups
- Enable Core rule set (covers common vulnerabilities)
- Enable Known bad inputs (blocks known malicious patterns)
- Click Add rules, then Next
- Set the default action to Allow (rules will block specific threats)
- Click Next through the remaining steps, then Create web ACL
Step 3: Associate the WAF Web ACL with Your API Gateway Stage
- In the WAF & Shield console, click Web ACLs
- Click on the web ACL you want to attach
- Select the Associated AWS resources tab
- Click Add AWS resources
- Under Resource type, select Amazon API Gateway REST API
- Check the box next to your API Gateway stage (format:
api-name/stage-name) - Click Add
Your API Gateway stage is now protected by WAF.
AWS CLI (optional)
List Available Web ACLs
First, list your existing web ACLs to find the ARN:
aws wafv2 list-web-acls \
--scope REGIONAL \
--region us-east-1
Example output:
{
"WebACLs": [
{
"Name": "my-api-gateway-waf",
"Id": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
"ARN": "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/my-api-gateway-waf/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
]
}
Associate Web ACL with API Gateway Stage
Replace the placeholder values with your actual ARNs:
aws wafv2 associate-web-acl \
--web-acl-arn arn:aws:wafv2:us-east-1:<ACCOUNT_ID>:regional/webacl/<WEB_ACL_NAME>/<WEB_ACL_ID> \
--resource-arn arn:aws:apigateway:us-east-1::/restapis/<REST_API_ID>/stages/<STAGE_NAME> \
--region us-east-1
Parameters to replace:
<ACCOUNT_ID>: Your 12-digit AWS account ID<WEB_ACL_NAME>: Name of your WAF web ACL<WEB_ACL_ID>: ID of your WAF web ACL<REST_API_ID>: Your API Gateway REST API ID (found in the API Gateway console or viaaws apigateway get-rest-apis)<STAGE_NAME>: The stage name (e.g.,prod,dev)
Example with actual values:
aws wafv2 associate-web-acl \
--web-acl-arn arn:aws:wafv2:us-east-1:123456789012:regional/webacl/my-api-gateway-waf/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
--resource-arn arn:aws:apigateway:us-east-1::/restapis/abc123def4/stages/prod \
--region us-east-1
This command produces no output on success.
CloudFormation (optional)
CloudFormation Template
This template creates a WAF web ACL with common AWS managed rules and associates it with an API Gateway stage.
AWSTemplateFormatVersion: '2010-09-09'
Description: WAF Web ACL for API Gateway protection
Parameters:
WebACLName:
Type: String
Description: Name for the WAF Web ACL
Default: api-gateway-waf-acl
ApiGatewayStageArn:
Type: String
Description: ARN of the API Gateway stage to protect
# Format: arn:aws:apigateway:us-east-1::/restapis/<api-id>/stages/<stage-name>
Resources:
ApiGatewayWebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Ref WebACLName
Description: WAF Web ACL for API Gateway protection
Scope: REGIONAL
DefaultAction:
Allow: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: !Sub '${WebACLName}Metrics'
Rules:
- Name: AWSManagedRulesCommonRuleSet
Priority: 1
OverrideAction:
None: {}
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesCommonRuleSetMetric
- Name: AWSManagedRulesKnownBadInputsRuleSet
Priority: 2
OverrideAction:
None: {}
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesKnownBadInputsRuleSet
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesKnownBadInputsRuleSetMetric
WebACLAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
WebACLArn: !GetAtt ApiGatewayWebACL.Arn
ResourceArn: !Ref ApiGatewayStageArn
Outputs:
WebACLArn:
Description: ARN of the created Web ACL
Value: !GetAtt ApiGatewayWebACL.Arn
WebACLId:
Description: ID of the created Web ACL
Value: !GetAtt ApiGatewayWebACL.Id
Deploy the Template
aws cloudformation create-stack \
--stack-name api-gateway-waf-protection \
--template-body file://waf-api-gateway.yaml \
--parameters \
ParameterKey=WebACLName,ParameterValue=my-api-gateway-waf \
ParameterKey=ApiGatewayStageArn,ParameterValue=arn:aws:apigateway:us-east-1::/restapis/abc123def4/stages/prod \
--region us-east-1
Terraform (optional)
Terraform Configuration
# Variables
variable "api_gateway_stage_arn" {
description = "ARN of the API Gateway stage to protect"
type = string
# Example: arn:aws:apigateway:us-east-1::/restapis/abc123def4/stages/prod
}
variable "web_acl_name" {
description = "Name for the WAF Web ACL"
type = string
default = "api-gateway-waf-acl"
}
# WAF Web ACL
resource "aws_wafv2_web_acl" "api_gateway" {
name = var.web_acl_name
description = "WAF Web ACL for API Gateway protection"
scope = "REGIONAL"
default_action {
allow {}
}
# AWS Managed Rules - Common Rule Set
rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 1
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesCommonRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesCommonRuleSetMetric"
sampled_requests_enabled = true
}
}
# AWS Managed Rules - Known Bad Inputs
rule {
name = "AWSManagedRulesKnownBadInputsRuleSet"
priority = 2
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesKnownBadInputsRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesKnownBadInputsRuleSetMetric"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.web_acl_name}Metrics"
sampled_requests_enabled = true
}
tags = {
Name = var.web_acl_name
Environment = "production"
ManagedBy = "terraform"
}
}
# Associate Web ACL with API Gateway Stage
resource "aws_wafv2_web_acl_association" "api_gateway" {
resource_arn = var.api_gateway_stage_arn
web_acl_arn = aws_wafv2_web_acl.api_gateway.arn
}
# Outputs
output "web_acl_arn" {
description = "ARN of the created Web ACL"
value = aws_wafv2_web_acl.api_gateway.arn
}
output "web_acl_id" {
description = "ID of the created Web ACL"
value = aws_wafv2_web_acl.api_gateway.id
}
Apply the Configuration
terraform init
terraform plan -var="api_gateway_stage_arn=arn:aws:apigateway:us-east-1::/restapis/abc123def4/stages/prod"
terraform apply -var="api_gateway_stage_arn=arn:aws:apigateway:us-east-1::/restapis/abc123def4/stages/prod"
Verification
After attaching the WAF web ACL, verify the association:
- Go to the API Gateway console
- Select your REST API and click Stages
- Select the stage you protected
- In the Stage Editor, look for the Web Application Firewall (WAF) section
- Confirm your web ACL name is displayed
Alternatively, in the WAF & Shield console:
- Go to Web ACLs and select your web ACL
- Click the Associated AWS resources tab
- Confirm your API Gateway stage appears in the list
CLI verification commands
List resources associated with your web ACL:
aws wafv2 list-resources-for-web-acl \
--web-acl-arn arn:aws:wafv2:us-east-1:<ACCOUNT_ID>:regional/webacl/<WEB_ACL_NAME>/<WEB_ACL_ID> \
--resource-type API_GATEWAY \
--region us-east-1
Re-run Prowler to confirm the check passes:
prowler aws --check apigateway_restapi_waf_acl_attached
Additional Resources
- AWS WAF Developer Guide
- Protecting API Gateway with AWS WAF
- AWS WAF Managed Rules
- API Gateway Security Best Practices
Notes
- Regional scope: WAF web ACLs for API Gateway must be created with
REGIONALscope (notCLOUDFRONT). CloudFront scope is only for CloudFront distributions. - One web ACL per resource: Each API Gateway stage can only be associated with one web ACL at a time. Associating a new web ACL will replace the existing association.
- Cost considerations: AWS WAF charges based on the number of web ACLs, rules, and requests processed. Review WAF pricing before deployment.
- Rule tuning: Start with managed rules in "count" mode to monitor potential false positives before enabling blocking. Review WAF logs in CloudWatch to fine-tune rules.
- Multiple stages: If you have multiple stages (dev, staging, prod), consider whether each needs the same or different WAF configurations based on their exposure and traffic patterns.