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:
  • 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.


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
    Type: AWS::WAFRegional::SqlInjectionMatchSet
      Name: Find SQL injections
          Type: QUERY_STRING
        TextTransformation: URL_DECODE
        FieldToMatch: ** ADD AS NEEDED **

    Type: AWS::WAFRegional::WebACL
        Type: ALLOW
    MetricName: SqlInjWebACL
    Name: Web ACL to block SQL injection in the query string
            Type: BLOCK
        Priority: 1
            Ref: YourRegionalSqlInjRule

    Type: AWS::WAFRegional::Rule
        Name: YourRegionalSqlInjRule
        MetricName : YourRegionalSqlInjRule
            DataId :  
                Ref : YourRegionalSqlInjDetection
            Negated : false
            Type : YourSqlInjectionMatch

    Type: AWS::WAFRegional::WebACLAssociation
        ResourceArn: !Ref YourApiARN
        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:

    - serverless-associate-waf

You will then need to append the following snippet:

    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
        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.


Further Reading