I recently had to attach a Web Application Firewall (WAF) regional Access Control List (ACL) to an API gateway created using the Serverless Framework. The only quality documentation I could find was from our very own Natalie Laing in this post she wrote back in 2019. I ran into an issue where my WebACL would not properly associate to the API. After some research I found that many others also faced this issue, mainly because the ‘Classic WAF’ has been depreciated by AWS.

AWS WAFV2 is the latest version of the AWS WAF API released in November 2019. Configuring the WAFV2 with an API is pretty straightforward, however, there are little resources available online. Hence, this post is to help those who are as lost as I was configuring a WAFV2 with an API gateway.

Things to be aware of

I got the tip on these ahead of my implementation thanks to Natalie’s article.

  • YAML indentation - I’d recommend installing cfn-lint, a huge help for formatting YAML files and catching bugs early.
  • Formatting your API Gateway’s Application Resource Name (ARN), you will need this to associate it to the WebACL. This should look like:
arn:aws:apigateway:{region}::/restapis/{rest_api_id}/stages/{stage_name}

Solution

To configure your WAF you’ll need to provision a WebACL then associate it to your API. In this case I was configuring a WAF to block SQL injection, however, this format could be used for other security protocols as well. Hence, the resources required at a minimum are:

WebACL:
  Type: "AWS::WAFv2::WebACL"
  Properties:
    Name: WebACLSQLi
    Scope: REGIONAL
    Description: Web ACL to block SQL injection
    DefaultAction:
      Allow: {}
    VisibilityConfig:
      SampledRequestsEnabled: true
      CloudWatchMetricsEnabled: true
      MetricName: MyMetricName
    Rules:
      - Name: SQLInject-RuleSet
        Priority: 0
        Statement:
          ManagedRuleGroupStatement:
            VendorName: AWS
            Name: AWSManagedRulesSQLiRuleSet
        OverrideAction:
          None: {}
        VisibilityConfig:
          SampledRequestsEnabled: true
          CloudWatchMetricsEnabled: true
          MetricName: SQLInjection-ruleset-metric

WebACLAssociation:
  Type: "AWS::WAFv2::WebACLAssociation"
  Properties:
    WebACLArn: !GetAtt WebACL.Arn
    ResourceArn: !Ref ApiARN

I have used Amazon’s Managed Rules to do the hard work of SQL injection blocking. You can see the other rule sets available here

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:  WebACLSQLi
    version: V2

The name must be the name you specified in your WebACL.

Wrapping up

And voila, that’s it. Simple right? Hopefully this post saves you the hours of frustration I endured.

If you’d like your API’s secured, feel free to contact-us.

References

Further Reading