serverless-application-model icon indicating copy to clipboard operation
serverless-application-model copied to clipboard

Support WAF for API Gateway

Open dan-lind opened this issue 6 years ago • 16 comments

As announced here, API Gateway now natively supports WAF.

Would be great to have access to this functionality through SAM More detailed description of steps required to set this up currently can be found here

dan-lind avatar Feb 04 '19 07:02 dan-lind

It looks like the CFN API Stage resource does not yet support adding a WAF, so I don't think SAM can connect a WAF to an API Gateway Stage yet. However, it looks like it is possible to create WAF Resources in CFN, so this functionality might be available soon. I'll keep this issue open as a feature request; we can create an RFC for this feature when CFN support is available.

It looks like there are some WAF examples in aws-samples: https://github.com/awslabs/aws-waf-security-automations . They use custom resources to connect the WAF to ApiGw.

keetonian avatar Feb 05 '19 18:02 keetonian

Yes, I also need this feature

azarboon avatar Jun 20 '19 06:06 azarboon

Just checked one of the templates: https://github.com/awslabs/aws-waf-security-automations/blob/master/deployment/aws-waf-security-automations.template

It's too crowded and has lots of things to configure. Can you pleasep oint out which of those are needed? Or even better, can you please provide a bare example of how can one create WAF and attach it to APG stage with current limitations?

azarboon avatar Jun 20 '19 08:06 azarboon

It looks like there is a way to do this in CloudFormation. This requires more investigation still.

It looks like you need to create a Regional WAF: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafregional-webacl.html

Then associate it with your API stage by using the API stage arn (by using !GetAtt MyApi.Stage): https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafregional-webaclassociation.html

Here's more information about how to set this up using the console/sdk/cli: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-aws-waf.html

I'm tagging this to indicate that we need more information. It seems like SAM could offer a lot of value in this area. We would need some simple default values for rules, more information on common WAF setups, and how SAM can make this process easier as well as keep it configurable for more advanced features.

For now, you can use the native CloudFormation resources in your template to create this WAF and associate it with your API.

keetonian avatar Jun 21 '19 17:06 keetonian

I already tried this but without success. Please find here my example template and a description of my attempt. Would be happy if somebody sees what I'm missing out here.

MartinasGit avatar Jun 27 '19 15:06 MartinasGit

@keetonian aws waf-regional list-web-acls gives a WebACLId value. Now when the URL of your stage is something like https://RestApiId.execute-api.us-east-1.amazonaws.com/StageName, using the RestApiId and StageName and WebACLId you can call aws waf-regional associate-web-acl --web-acl-id WebACLId --resource-arn arn:aws:apigateway:us-east-1::restapis/RestApiId/stages/StageName. After this the aws waf-regional get-web-acl --web-acl-id WebACLId returns data with the WebACLArn so you see that it is associated. A CloudFormation/SAM example using the WAFRegional to RestAPI and/or Stage would be nice.

amkuipers avatar Jul 07 '19 21:07 amkuipers

I contacted the AWS Support: ...[this is a ] limitation we have with CloudFormation when dealing with AWS::WAFRegional::RateBasedRule.

Despite the fact that CloudFormation supports creating WAF regional rate-based rules, the association of them with a Web ACL is not currently supported. If you observe link [1] below, you will realize that:

"To add the rate-based rules created through CloudFormation to a web ACL, use the AWS WAF console, API, or command line interface (CLI)."

[1] AWS::WAFRegional::RateBasedRule: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafregional-ratebasedrule.html

@amkuipers an example for WAFRegional with a RESTApi can be found in my post here: https://stackoverflow.com/questions/56683755/sam-api-gateway-with-cloudformation-wafregional

MartinasGit avatar Jul 08 '19 08:07 MartinasGit

It looks like there is a way to do this in CloudFormation. This requires more investigation still.

It looks like you need to create a Regional WAF: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafregional-webacl.html

Then associate it with your API stage by using the API arn (by using !Ref MyApi.Stage): https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafregional-webaclassociation.html

Here's more information about how to set this up using the console/sdk/cli: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-aws-waf.html

I'm tagging this to indicate that we need more information. It seems like SAM could offer a lot of value in this area. We would need some simple default values for rules, more information on common WAF setups, and how SAM can make this process easier as well as keep it configurable for more advanced features.

For now, you can use the native CloudFormation resources in your template to create this WAF and associate it with your API.

I tried this for AWS::WAFRegional::IPSet and can confirm that it works. Thanks.

azarboon avatar Aug 01 '19 09:08 azarboon

Then associate it with your API stage by using the API arn (by using !Ref MyApi.Stage) [...]

@keetonian Doesn't !Ref MyApi.Stage give the name of the stage? In order to associate the ARN of an API Gateway stage, it would have to be constructed, like this:

!Sub arn:${AWS::Partition}:apigateway:${AWS::Region}::/restapis/${ServerlessRestApi}/stages/${ServerlessRestApi.Stage}

...except I think that will fail because it will try to !GetAtt ServerlessRestApi.Stage. So it will have to become:

!Sub
- arn:${AWS::Partition}:apigateway:${AWS::Region}::/restapis/${ServerlessRestApi}/stages/${Stage}
- Stage: !Ref ServerlessRestApi.Stage

Er, right? Or have I missed something?

ETA What I've written certainly works, but I'm not confident it's optimal. Th-There must be a way to get the ARN of a stage, right?

chrisoverzero avatar Sep 10 '19 18:09 chrisoverzero

@chrisoverzero you are correct, it looks like you can't get the arn of the stage: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-stage.html

keetonian avatar Sep 10 '19 21:09 keetonian

Perhaps that's the first small value SAM could provide in this area, then. Moving the relationship into the AWS::Serverless::Api so that the Stage ARN construction is abstracted away, that is. Something like:

Globals:
  Api:
    OpenApiVersion: '3.0.1'
    WebACL: !Ref WebACLId
    ... #etc.

...expanding into:

"ServerlessRestApi": {
  "Type": "AWS::ApiGateway::RestApi",
  "Properties": {
    "Body": "<All the generated OpenAPI>",
    "Etc.": {}
  }
},
"ServerlessRestApiProdStage": {
  "Type": "AWS::ApiGateway::Stage",
  "Properties": {
    "RestApiId": { "Ref": "ServerlessRestApi" },
    "Etc.": {}
  }
},
"ServerlessRestApiProdStageWebACLAssociation": {
  "Type": "AWS::WAFRegional::WebACLAssociation",
  "Properties": {
    "WebACLId": { "Ref": "WebACLId" },
    "ResourceArn": {
      "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}::/restapis/${ServerlessRestApi}/stages/${ServerlessRestApiProdStage}"
    }
  }
}

...except maybe with a better generated name.

I think this is even forwards compatible -- in that other places in SAM accept different shapes of data to determine behavior, so this could, as well. Something like:

  • WebACL: true => Use the "simple default values for rules" mentioned above.
  • WebACL: false|null|missing => Disable WebACL entirely.
  • WebACL: string => Associate the stage with the WebACL of the given ID.
  • WebACL: object => Some advanced configuration which would be come up with later.

ETA Ah, but in thinking about it, !If makes this idea intractable. Oh, well.

chrisoverzero avatar Sep 11 '19 13:09 chrisoverzero

Hello there,

I was hoping this would be an already supported feature but got disappointed when I saw it is now. Is there any estimation on when this would be supported?

Thank you!

piersf avatar Apr 01 '20 00:04 piersf

I'm also having problems with this.

ApiGatewayWebACLAssociation:
    Type: AWS::WAFRegional::WebACLAssociation
    Properties:
      ResourceArn: !Sub "arn:aws:apigateway:${AWS::Region}::/restapis/${ServerlessRestApi}/stages/${ServerlessRestApiProdStage}"
      WebACLId: !Ref WAFRegionalWebACLId

  Api:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod

Fails when deployed.

As does

    Type: AWS::WAFRegional::WebACLAssociation
    DependsOn: ProvisionalOrdersApi
    Properties:
      ResourceArn: !Sub "arn:aws:apigateway:${AWS::Region}::/restapis/${Api}/stages/Prod"
      WebACLId: !Ref WAFRegionalWebACLId

  Api:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod```

tkeeber avatar Jun 19 '20 08:06 tkeeber

I solved this problem by removing the AWS::Serverless::Api completely and defining any of the properties i needed (in this case -> Auth) in a global

Api:
  EndpointConfiguration: REGIONAL
  Auth:
    DefaultAuthorizer: MyLambdaAuthorizer
    Authorizers:
      LambdaAuthorizer:
        FunctionArn: !GetAtt MyAuthorizerFunction.Arn

tkeeber avatar Jun 23 '20 11:06 tkeeber

The following code works for me:

  ApplicationApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      EndpointConfiguration: EDGE
......
  ApiGatewayWebACLAssociation:
    Type: AWS::WAFRegional::WebACLAssociation
    Properties:
      WebACLId: !Ref WafWebAcl
      ResourceArn:
        !Sub
          - "arn:aws:apigateway:${AWS::Region}::/restapis/${ApplicationApi}/stages/${ApiStage}"
          - ApiStage: !Ref ApplicationApi.Stage

nekoni avatar Sep 10 '20 09:09 nekoni

After hours of reading and researching, I finally found how to do it. Here's how I did it:

mainBackendApi:
  Type: AWS::Serverless::Api
  Properties:
    StageName: !Ref Stage
    EndpointConfiguration:
      Type: REGIONAL
mainBackendWebAcl:
  Type: AWS::WAFv2::WebACL
  Properties:
    DefaultAction:
      Block: {}
    Scope: REGIONAL
    VisibilityConfig: 
      CloudWatchMetricsEnabled: true
      MetricName: web-acl
      SampledRequestsEnabled: true
    Rules:
      - Action:
          Block: {}
        Name: RateLimit
        Statement:
          RateBasedStatement:
            AggregateKeyType: IP
            Limit: 1500
        VisibilityConfig: 
          CloudWatchMetricsEnabled: true
          MetricName: rate-limit
          SampledRequestsEnabled: true
        Priority: 0
      - Action:
          Allow: {}
        Name: AllowedCounties
        Statement:
          GeoMatchStatement:
            CountryCodes:
              - AU
              - PH
        VisibilityConfig: 
          CloudWatchMetricsEnabled: true
          MetricName: allowed-countries
          SampledRequestsEnabled: true
        Priority: 1
mainBackendWebAclAssociations:
  Type: AWS::WAFv2::WebACLAssociation
  Properties: 
    ResourceArn: !Sub "arn:aws:apigateway:${AWS::Region}::/restapis/${mainBackendApi}/stages/${Stage}"
    WebACLArn: !GetAtt mainBackendWebAcl.Arn

This will implement a rate-limiting of 5 requests per second and also only allow requests coming from defined countries.

aprilmintacpineda avatar Mar 03 '21 14:03 aprilmintacpineda