Issue Summary
Currently, SAM creates two permissions (one for production and one for test) for every API event defined in the CloudFormation stack. The test permission is needed for the Test button to work on the console. Because of this extra permission for the test button, the limit of 200 resources per stack can be quickly reached. Related Issues: #285, #337
Design Spec
The approach is to combine both permisions into a single permission and give the exact same functionality without a spec change. This is achieved by using a "*" in place of the stage name in the single permission, which is exactly what the "Test" permission does today.
Sample Template:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
InlineCode: |
print("hello world")
Handler: app.lambda_handler
Runtime: python3.6
Events:
HttpGetUserExample:
Type: Api
Properties:
Path: '/users/userid'
Method: GET
For this sample template, the resources generated by existing approach look like:
...
"HelloWorldFunctionHttpGetUserExamplePermissionProd": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:invokeFunction",
"Principal": "apigateway.amazonaws.com",
"FunctionName": {
"Ref": "HelloWorldFunction"
},
"SourceArn": {
"Fn::Sub": [
"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/users/userid",
{
"__Stage__": "Prod",
"__ApiId__": {
"Ref": "ServerlessRestApi"
}
}
]
}
}
},
"HelloWorldFunctionHttpGetUserExamplePermissionTest": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:invokeFunction",
"Principal": "apigateway.amazonaws.com",
"FunctionName": {
"Ref": "HelloWorldFunction"
},
"SourceArn": {
"Fn::Sub": [
"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/users/userid",
{
"__Stage__": "*",
"__ApiId__": {
"Ref": "ServerlessRestApi"
}
}
]
}
}
},
...
With the proposed approach the resources generated would look like:
...
"HelloWorldFunctionHttpGetUserExamplePermissionProd": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:invokeFunction",
"Principal": "apigateway.amazonaws.com",
"FunctionName": {
"Ref": "HelloWorldFunction"
},
"SourceArn": {
"Fn::Sub": [
"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/users/userid",
{
"__Stage__": "*",
"__ApiId__": {
"Ref": "ServerlessRestApi"
}
}
]
}
}
},
...
This approach will reduce the number of permissions created for api events by half. This approach gives the same functionality as the existing approach without any change in the spec. Hence, it is backward compatible.
This looks good. Thanks for getting to this eventually.
Could SAM just create one permission that works for both without specifying any flag? like this
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "HelloLambdaPermissionApiGateway-123",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:0123456789:function:hello",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:execute-api:us-east-1:0123456789:{api-id}/*/*"
}
}
}
]
}
I'd be happy with whatever way to reduce the number of generated permissions, the situation is getting unbearable with some deployments, especially in cases when the permission resources end up being replaced. In addition to disabling the test permissions I'd also like having the option to disable permission generation completely and bringing my own permissions instead.
@ferdingler This is an interesting approach. We had a discussion about this approach in the team and we did a deep dive on this approach. Both the permissions look similar except for the change in {stage} part of the arn.
ProdPermission Arn: ("AWS:SourceArn": "arn:aws:execute-api:us-east-1:0123456789:{api-id}/{stage}/{path}")
TestPermission Arn: ("AWS:SourceArn": "arn:aws:execute-api:us-east-1:0123456789:{api-id}/*/{path}")
If we make a change to the ProdPermission arn by replacing {stage} with *, we can combine both permissions into one without changing the spec.
The single permission arn would look like this:
"AWS:SourceArn": "arn:aws:execute-api:us-east-1:0123456789:{api-id}/*/{path}"
This reduces the number of permissions by half by giving exact same functionality with two permissions. As we are not removing/revoking any permissions, this approach seems to be backward compatible.
@ShreyaGangishetty awesome, thanks for considering my input!
@ferdingler We ended up going with your approach (see #1119), which is a much simpler change. Really appreciate your feedback!
Any idea when this will be released?
@kriztoph this is going out in v1.15, which is our next planned release. It will be coming out soon!
Closing this issue as v1.15.0 is released