I was recently trying to attach a WAF (Web Application Firewall) regional ACL (Access Control List) to an API Gateway using CloudFormation and I ran into problems when the API Gateway was created using Serverless Framework. The majority of the docs that I found online outlined how to attach your WAF to an ELB (Elastic Load Balancer), My suspicion is because support for attaching WAF to API Gateway was announced in November 2018 where support for ELB's has been around since 2016.
I tried to hardcode the ARN and web ACL id into the AWS::WAFRegional::WebACLAssociation properties and still when I went into the AWS console the ACL and API Gateway was not associated in the test account but they were in the production account. I spent way too much time looking over the API Gateway ARN and trying to ascertain why it wasn't functioning correctly.
WAF v WAF Regional
Amazons Web Applications Firewall allows you to attach your WAF ACL to your API Gateway. Your API Gateway will be region-specific so where you would use AWS::WAF::WebACL to attach to CloudFront traditionally you will need to use the regional WAF resource type AWS::WAFRegional::WebACL.
if(CloudFront) {
return AWS WAF
} else {
return AWS WAF Regional
}
Common gotchas
The errors I encountered when deploying the stack were inadequate, I would get a lot of null error responses.
- YAML indentation
- Formatting your API Gateway ARN. This should look like:
arn:aws:apigateway:{region}::/restapis/{rest_api_id}/stages/{stage_name}
- Find out where the API Gateway was created, was it in your CloudFormation or a Serverless Framework deployment.
Status Code: 400; Error Code: WAFInvalidParameterException
This could be a whole list of reasons according to the aws documentation so have fun figuring out which one it is.
Solution
So how did I resolve the issues I was having? Ensure you have all the resources needed to set up your ACL, these include but are not limited to:
- AWS::WAFRegional::WebACL
- AWS::WAFRegional::Rule
- AWS::WAFRegional::WebACLAssociation
YourRegionalSqlInjDetection:
Type: AWS::WAFRegional::SqlInjectionMatchSet
Properties:
Name: Find SQL injections
SqlInjectionMatchTuples:
-
FieldToMatch:
Type: QUERY_STRING
TextTransformation: URL_DECODE
-
FieldToMatch: ** ADD AS NEEDED **
Type:
TextTransformation:
YourRegionalWafWebAcl:
Type: AWS::WAFRegional::WebACL
Properties:
DefaultAction:
Type: ALLOW
MetricName: SqlInjWebACL
Name: Web ACL to block SQL injection in the query string
Rules:
-
Action:
Type: BLOCK
Priority: 1
RuleId:
Ref: YourRegionalSqlInjRule
YourRegionalSqlInjRule:
Type: AWS::WAFRegional::Rule
Properties:
Name: YourRegionalSqlInjRule
MetricName : YourRegionalSqlInjRule
Predicates:
-
DataId :
Ref : YourRegionalSqlInjDetection
Negated : false
Type : YourSqlInjectionMatch
YourWebACLAssociation:
Type: AWS::WAFRegional::WebACLAssociation
Properties:
ResourceArn: !Ref YourApiARN
WebACLId:
Ref: YourRegionalWafWebAcl
So remember that serverless file I mentioned?
If your API was created using the Serverless Framework you will need to run npm i serverless-associate-waf
in your serverless yml you will need to utilize this plugin:
plugins:
- serverless-associate-waf
You will then need to append the following snippet:
custom:
associateWaf:
name: Web ACL to block SQL injection in the query string
The name must be the name you specified in your web ACL.
Type: AWS::WAFRegional::WebACL
Properties:
DefaultAction:
Type: ALLOW
MetricName: SqlInjWebACL
Name: Web ACL to block SQL injection in the query string ** HERE **
Wrapping up
After X amount of hours spent trying to associate a WAF ACL to an API Gateway, I finally got the development and production accounts associated with the correct ACL. Hopefully, after reading this blog, this means you don't have to.
If you think we can help you secure your API Gateways, feel free to contact-us.
References
- https://aws.amazon.com/about-aws/whats-new/2016/12/AWS-WAF-now-available-on-Application-Load-Balancer/
- https://aws.amazon.com/blogs/compute/amazon-api-gateway-adds-support-for-aws-waf
- https://docs.aws.amazon.com/waf/latest/APIReference/API_regional_GetWebACLForResource.html
- https://www.npmjs.com/package/serverless-associate-waf