Open dan-lind opened 5 years ago
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.
Yes, I also need this feature
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?
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.
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.
@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.
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
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.htmlHere'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.
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 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
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.
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!
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```
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
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
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.
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