WAF setup using cloudformation for API and CLoudfront

Photo by NASA on Unsplash

WAF setup using cloudformation for API and CLoudfront

AWS WAF is a web application firewall that lets you monitor the HTTP(S) requests that are forwarded to your protected web application resources. You can protect the following resource types:

  • Amazon CloudFront distribution

  • Amazon API Gateway REST API

  • Application Load Balancer

  • AWS AppSync GraphQL API

  • Amazon Cognito user pool

  • AWS App Runner service

  • AWS Verified Access instance

In this article, we will go through WAF setup for API gateway and Cloudfront

First, let's start with WAF for Apigateway first (my-wafapi-template.yaml)

with some free managed rule by aws

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyApiGateway:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: MyApi
      Description: My API Gateway
  MyWafWebAcl:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: APIGatewayWAFWebACL
      Scope: REGIONAL # Use 'CLOUDFRONT' if you're using CloudFront in front of API Gateway
      DefaultAction:
        Allow: {}
      Rules:
        - Name: AWSManagedRulesCommonRuleSet
          Priority: 1
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: CommonRuleSet
          OverrideAction:
            None: {}
        - Name: AWSManagedRulesAmazonIpReputationList
          Priority: 2
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAmazonIpReputationList
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: AmazonIpReputationList
          OverrideAction:
            None: {}
        - Name: AWSManagedRulesKnownBadInputsRuleSet
          Priority: 3
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: KnownBadInputsRuleSet
          OverrideAction:
            None: {}

  MyApiGatewayStage:
    Type: AWS::ApiGateway::Stage
    Properties:
      StageName: prod
      RestApiId: !Ref MyApiGateway

  MyApiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    DependsOn: MyApiGatewayStage
    Properties:
      RestApiId: !Ref MyApiGateway
      StageName: !Ref MyApiGatewayStage.StageName

  MyApiGatewayWafAssociation:
    Type: AWS::WAFv2::WebACLAssociation
    Properties:
      ResourceArn: !Sub arn:aws:apigateway:${AWS::Region}::/restapis/${MyApiGateway}/stages/${MyApiGatewayStage}
      WebACLArn: !Ref MyWafWebAcl

Outputs:
  ApiGatewayEndpoint:
    Value: !Sub "https://${MyApiGateway}.execute-api.${AWS::Region}.amazonaws.com/${MyApiGatewayStage.StageName}"
    Description: Endpoint URL for the API Gateway

AWS::WAFv2::WebACLAssociation is used to associate the WAF with agi gateway resource

The important part is SCOPE here which can differ in the case of Apigateway and Cloudfront

The scope is 'REGIONAL' in the case of API gateway and 'CLOUDFRONT' in the case of CloudFront

REGIONAL Scope WAF can be deployed in any region which supports it
CLOUDFRONT Scope WAF can be deployed only in the 'us-east-1' region.

Cloudformation for WAF for cloudfront (my-wafcf-template.yaml)

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyWebACLCF:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: MyWebACL
      Scope: CLOUDFRONT
      DefaultAction:
        Allow: {}
      Rules:
        - Name: AWSManagedRulesCommonRuleSet
          Priority: 1
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: CommonRuleSet
          OverrideAction:
            None: {}
        - Name: AWSManagedRulesAmazonIpReputationList
          Priority: 2
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAmazonIpReputationList
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: AmazonIpReputationList
          OverrideAction:
            None: {}
        - Name: AWSManagedRulesKnownBadInputsRuleSet
          Priority: 3
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: KnownBadInputsRuleSet
          OverrideAction:
            None: {}

  MyCloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        WebACLId: !Ref MyWebACLCF
        Comment: My CloudFront Distribution
        # Add other necessary properties for your CloudFront distribution configuration

AWS::CloudFront::Distribution is used to connect the CloudFront distribution to WAF

If you are deploying the same cloud formation template in multiple regions then you can use the conditions
main.yaml (parent stack - with two child stack)

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
    SetWAFCF: 
      Description": "Create WAFs for cloudfront y/n ?"
      Type: String
      Default: FALSE
      AllowedValues: [TRUE, FALSE]
Conditions:
  CreateWAFCF: !Equals [!Ref SetWAFCF, TRUE]

Resources:
  WAFAgiGateway:
    Type: AWS::CloudFormation::Stack
    Condition: CreateWAFCF
    Properties:
      TemplateURL: https://s3.amazonaws.com/my-bucket/my-wafapi-template.yaml
      Parameters:
        - ParameterKey: Environment
          ParameterValue: test
      TimeoutInMinutes: 30
  WAFCloufront:
    Type: AWS::CloudFormation::Stack
    Condition: CreateWAFCF
    Properties:
      TemplateURL: https://s3.amazonaws.com/my-bucket/my-wafcf-template.yaml
      Parameters:
        - ParameterKey: Environment
          ParameterValue: test
      TimeoutInMinutes: 30

Hope this article helps you!!