diff --git a/docs/providers/aws/guide/resources.md b/docs/providers/aws/guide/resources.md
index 2e2a7f673..e5909d19b 100644
--- a/docs/providers/aws/guide/resources.md
+++ b/docs/providers/aws/guide/resources.md
@@ -70,7 +70,7 @@ We're also using the term `normalizedName` or similar terms in this guide. This
|IAM::Policy | IamPolicyLambdaExecution | IamPolicyLambdaExecution |
|Lambda::Function | {normalizedFunctionName}LambdaFunction | HelloLambdaFunction |
|Logs::LogGroup | {normalizedFunctionName}LogGroup | HelloLogGroup |
-|Lambda::Permission |
- **Schedule**: {normalizedFunctionName}LambdaPermissionEventsRuleSchedule{index}
- **S3**: {normalizedFunctionName}LambdaPermissionS3
- **APIG**: {normalizedFunctionName}LambdaPermissionApiGateway
- **SNS**: {normalizedFunctionName}LambdaPermission{normalizedTopicName}
| - **Schedule**: HelloLambdaPermissionEventsRuleSchedule1
- **S3**: HelloLambdaPermissionS3
- **APIG**: HelloLambdaPermissionApiGateway
- **SNS**: HelloLambdaPermissionSometopic
|
+|Lambda::Permission | - **Schedule**: {normalizedFunctionName}LambdaPermissionEventsRuleSchedule{index}
- **S3**: {normalizedFunctionName}LambdaPermission{normalizedBucketName}S3
- **APIG**: {normalizedFunctionName}LambdaPermissionApiGateway
- **SNS**: {normalizedFunctionName}LambdaPermission{normalizedTopicName}SNS
| - **Schedule**: HelloLambdaPermissionEventsRuleSchedule1
- **S3**: HelloLambdaPermissionBucketS3
- **APIG**: HelloLambdaPermissionApiGateway
- **SNS**: HelloLambdaPermissionTopicSNS
|
|Events::Rule | {normalizedFuntionName}EventsRuleSchedule{SequentialID} | HelloEventsRuleSchedule1 |
|ApiGateway::RestApi | ApiGatewayRestApi | ApiGatewayRestApi |
|ApiGateway::Resource | ApiGatewayResource{normalizedPath} | ApiGatewayResourceUsers |
diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js
index 07190ad86..9353e14ac 100644
--- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js
+++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js
@@ -7,6 +7,7 @@ module.exports = {
compileMethods() {
this.apiGatewayMethodLogicalIds = [];
+ this.permissionMapping = [];
this.validated.events.forEach((event) => {
const resourceId = this.getResourceId(event.http.path);
@@ -27,14 +28,20 @@ module.exports = {
template.Properties.ApiKeyRequired = true;
}
- _.merge(template,
- this.getMethodAuthorization(event.http),
- this.getMethodIntegration(event.http, event.functionName),
- this.getMethodResponses(event.http)
- );
const methodLogicalId = this.provider.naming
.getMethodLogicalId(resourceName, event.http.method);
+ const lambdaLogicalId = this.provider.naming
+ .getLambdaLogicalId(event.functionName);
+
+ const singlePermissionMapping = { resourceName, lambdaLogicalId, event };
+ this.permissionMapping.push(singlePermissionMapping);
+
+ _.merge(template,
+ this.getMethodAuthorization(event.http),
+ this.getMethodIntegration(event.http, lambdaLogicalId, methodLogicalId),
+ this.getMethodResponses(event.http)
+ );
this.apiGatewayMethodLogicalIds.push(methodLogicalId);
diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js
index 2d429b180..31645049c 100644
--- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js
+++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js
@@ -3,9 +3,7 @@
const _ = require('lodash');
module.exports = {
- getMethodIntegration(http, functionName) {
- const lambdaLogicalId = this.provider.naming
- .getLambdaLogicalId(functionName);
+ getMethodIntegration(http, lambdaLogicalId) {
const integration = {
IntegrationHttpMethod: 'POST',
Type: http.integration,
diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js
index 3085327cf..3fe5d5546 100644
--- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js
+++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js
@@ -6,27 +6,36 @@ const BbPromise = require('bluebird');
module.exports = {
compilePermissions() {
- this.validated.events.forEach((event) => {
+ this.permissionMapping.forEach((singlePermissionMapping) => {
const lambdaPermissionLogicalId = this.provider.naming
- .getLambdaApiGatewayPermissionLogicalId(event.functionName);
- const lambdaLogicalId = this.provider.naming
- .getLambdaLogicalId(event.functionName);
+ .getLambdaApiGatewayPermissionLogicalId(singlePermissionMapping.event.functionName);
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, {
[lambdaPermissionLogicalId]: {
Type: 'AWS::Lambda::Permission',
Properties: {
FunctionName: {
- 'Fn::GetAtt': [lambdaLogicalId, 'Arn'],
+ 'Fn::GetAtt': [singlePermissionMapping.lambdaLogicalId, 'Arn'],
},
Action: 'lambda:InvokeFunction',
Principal: 'apigateway.amazonaws.com',
+ SourceArn: { 'Fn::Join': ['',
+ [
+ 'arn:aws:execute-api:',
+ { Ref: 'AWS::Region' },
+ ':',
+ { Ref: 'AWS::AccountId' },
+ ':',
+ { Ref: this.apiGatewayRestApiLogicalId },
+ '/*/*',
+ ],
+ ] },
},
},
});
- if (event.http.authorizer) {
- const authorizer = event.http.authorizer;
+ if (singlePermissionMapping.event.http.authorizer) {
+ const authorizer = singlePermissionMapping.event.http.authorizer;
const authorizerPermissionLogicalId = this.provider.naming
.getLambdaApiGatewayPermissionLogicalId(authorizer.name);
diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/permissions.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/permissions.js
index 6df28f264..3602cab8f 100644
--- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/permissions.js
+++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/permissions.js
@@ -18,7 +18,7 @@ describe('#awsCompilePermissions()', () => {
awsCompileApigEvents.validated = {};
});
- it('should create permission resource when http events are given', () => {
+ it('should create limited permission resource scope to REST API', () => {
awsCompileApigEvents.validated.events = [
{
functionName: 'First',
@@ -26,17 +26,19 @@ describe('#awsCompilePermissions()', () => {
path: 'foo/bar',
method: 'post',
},
- }, {
- functionName: 'First',
- http: {
- path: 'foo/bar',
- method: 'get',
- },
- }, {
- functionName: 'Second',
- http: {
- path: 'bar/foo',
- method: 'get',
+ },
+ ];
+ awsCompileApigEvents.apiGatewayRestApiLogicalId = 'ApiGatewayRestApi';
+ awsCompileApigEvents.permissionMapping = [
+ {
+ lambdaLogicalId: 'FirstLambdaFunction',
+ resourceName: 'FooBar',
+ event: {
+ http: {
+ path: 'foo/bar',
+ method: 'post',
+ },
+ functionName: 'First',
},
},
];
@@ -45,9 +47,22 @@ describe('#awsCompilePermissions()', () => {
expect(awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.FirstLambdaPermissionApiGateway
.Properties.FunctionName['Fn::GetAtt'][0]).to.equal('FirstLambdaFunction');
+
+ const deepObj = { 'Fn::Join': ['',
+ [
+ 'arn:aws:execute-api:',
+ { Ref: 'AWS::Region' },
+ ':',
+ { Ref: 'AWS::AccountId' },
+ ':',
+ { Ref: 'ApiGatewayRestApi' },
+ '/*/*',
+ ],
+ ] };
+
expect(awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
- .Resources.SecondLambdaPermissionApiGateway
- .Properties.FunctionName['Fn::GetAtt'][0]).to.equal('SecondLambdaFunction');
+ .Resources.FirstLambdaPermissionApiGateway
+ .Properties.SourceArn).to.deep.equal(deepObj);
});
});
@@ -65,6 +80,24 @@ describe('#awsCompilePermissions()', () => {
},
},
];
+ awsCompileApigEvents.apiGatewayRestApiLogicalId = 'ApiGatewayRestApi';
+ awsCompileApigEvents.permissionMapping = [
+ {
+ lambdaLogicalId: 'FirstLambdaFunction',
+ resourceName: 'FooBar',
+ event: {
+ http: {
+ authorizer: {
+ name: 'authorizer',
+ arn: { 'Fn::GetAtt': ['AuthorizerLambdaFunction', 'Arn'] },
+ },
+ path: 'foo/bar',
+ method: 'post',
+ },
+ functionName: 'First',
+ },
+ },
+ ];
return awsCompileApigEvents.compilePermissions().then(() => {
expect(awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.AuthorizerLambdaPermissionApiGateway
@@ -74,6 +107,7 @@ describe('#awsCompilePermissions()', () => {
it('should not create permission resources when http events are not given', () => {
awsCompileApigEvents.validated.events = [];
+ awsCompileApigEvents.permissionMapping = [];
return awsCompileApigEvents.compilePermissions().then(() => {
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources
diff --git a/lib/plugins/aws/deploy/compile/events/s3/index.js b/lib/plugins/aws/deploy/compile/events/s3/index.js
index e98e883df..0db67be13 100644
--- a/lib/plugins/aws/deploy/compile/events/s3/index.js
+++ b/lib/plugins/aws/deploy/compile/events/s3/index.js
@@ -119,7 +119,8 @@ class AwsCompileS3Events {
filter
);
}
- s3EnabledFunctions.push(functionName);
+ const s3EnabledFunction = { functionName, bucketName };
+ s3EnabledFunctions.push(s3EnabledFunction);
}
});
}
@@ -150,9 +151,9 @@ class AwsCompileS3Events {
// iterate over all functions with S3 events
// and give S3 permission to invoke them all
// by adding Lambda::Permission resource for each
- s3EnabledFunctions.forEach(functionName => {
+ s3EnabledFunctions.forEach(s3EnabledFunction => {
const lambdaLogicalId = this.provider.naming
- .getLambdaLogicalId(functionName);
+ .getLambdaLogicalId(s3EnabledFunction.functionName);
const permissionTemplate = {
Type: 'AWS::Lambda::Permission',
Properties: {
@@ -164,10 +165,16 @@ class AwsCompileS3Events {
},
Action: 'lambda:InvokeFunction',
Principal: 's3.amazonaws.com',
+ SourceArn: { 'Fn::Join': ['',
+ [
+ `arn:aws:s3:::${s3EnabledFunction.bucketName}`,
+ ],
+ ] },
},
};
const lambdaPermissionLogicalId = this.provider.naming
- .getLambdaS3PermissionLogicalId(functionName);
+ .getLambdaS3PermissionLogicalId(s3EnabledFunction.functionName,
+ s3EnabledFunction.bucketName);
const permissionCFResource = {
[lambdaPermissionLogicalId]: permissionTemplate,
};
diff --git a/lib/plugins/aws/deploy/compile/events/s3/tests/index.js b/lib/plugins/aws/deploy/compile/events/s3/tests/index.js
index cf33a0a29..529ca938a 100644
--- a/lib/plugins/aws/deploy/compile/events/s3/tests/index.js
+++ b/lib/plugins/aws/deploy/compile/events/s3/tests/index.js
@@ -118,7 +118,10 @@ describe('AwsCompileS3Events', () => {
.Resources.S3BucketFirstfunctionbuckettwo.Type
).to.equal('AWS::S3::Bucket');
expect(awsCompileS3Events.serverless.service.provider.compiledCloudFormationTemplate
- .Resources.FirstLambdaPermissionS3.Type
+ .Resources.FirstLambdaPermissionFirstfunctionbucketoneS3.Type
+ ).to.equal('AWS::Lambda::Permission');
+ expect(awsCompileS3Events.serverless.service.provider.compiledCloudFormationTemplate
+ .Resources.FirstLambdaPermissionFirstfunctionbuckettwoS3.Type
).to.equal('AWS::Lambda::Permission');
expect(awsCompileS3Events.serverless.service.provider.compiledCloudFormationTemplate
.Resources.S3BucketFirstfunctionbuckettwo.Properties.NotificationConfiguration
@@ -156,7 +159,7 @@ describe('AwsCompileS3Events', () => {
.Resources.S3BucketFirstfunctionbucketone.Properties.NotificationConfiguration
.LambdaConfigurations.length).to.equal(2);
expect(awsCompileS3Events.serverless.service.provider.compiledCloudFormationTemplate
- .Resources.FirstLambdaPermissionS3.Type
+ .Resources.FirstLambdaPermissionFirstfunctionbucketoneS3.Type
).to.equal('AWS::Lambda::Permission');
});
diff --git a/lib/plugins/aws/deploy/compile/events/sns/index.js b/lib/plugins/aws/deploy/compile/events/sns/index.js
index 83995d4c0..abcc11c66 100644
--- a/lib/plugins/aws/deploy/compile/events/sns/index.js
+++ b/lib/plugins/aws/deploy/compile/events/sns/index.js
@@ -79,7 +79,17 @@ class AwsCompileSNSEvents {
"Properties": {
"FunctionName": { "Fn::GetAtt": ["${lambdaLogicalId}", "Arn"] },
"Action": "lambda:InvokeFunction",
- "Principal": "sns.amazonaws.com"
+ "Principal": "sns.amazonaws.com",
+ "SourceArn": {
+ "Fn::Join": ["",
+ ["arn:aws:sns:",
+ { "Ref": "AWS::Region"},
+ ":",
+ { "Ref": "AWS::AccountId"},
+ ":",
+ "${topicName}"]
+ ]
+ }
}
}
`;
diff --git a/lib/plugins/aws/deploy/compile/events/sns/tests/index.js b/lib/plugins/aws/deploy/compile/events/sns/tests/index.js
index a0807480d..e15006d01 100644
--- a/lib/plugins/aws/deploy/compile/events/sns/tests/index.js
+++ b/lib/plugins/aws/deploy/compile/events/sns/tests/index.js
@@ -62,10 +62,10 @@ describe('AwsCompileSNSEvents', () => {
.provider.compiledCloudFormationTemplate.Resources.SNSTopicTopic2.Type
).to.equal('AWS::SNS::Topic');
expect(awsCompileSNSEvents.serverless.service
- .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic1.Type
+ .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic1SNS.Type
).to.equal('AWS::Lambda::Permission');
expect(awsCompileSNSEvents.serverless.service
- .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic2.Type
+ .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic2SNS.Type
).to.equal('AWS::Lambda::Permission');
});
@@ -96,7 +96,7 @@ describe('AwsCompileSNSEvents', () => {
.Properties.Subscription.length
).to.equal(2);
expect(awsCompileSNSEvents.serverless.service
- .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic1.Type
+ .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic1SNS.Type
).to.equal('AWS::Lambda::Permission');
});
diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js
index a77d14a8a..2fd5020ed 100644
--- a/lib/plugins/aws/lib/naming.js
+++ b/lib/plugins/aws/lib/naming.js
@@ -136,12 +136,13 @@ module.exports = {
},
// Permissions
- getLambdaS3PermissionLogicalId(functionName) {
- return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionS3`;
+ getLambdaS3PermissionLogicalId(functionName, bucketName) {
+ return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${this
+ .normalizeBucketName(bucketName)}S3`;
},
getLambdaSnsPermissionLogicalId(functionName, topicName) {
return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${
- this.normalizeTopicName(topicName)}`;
+ this.normalizeTopicName(topicName)}SNS`;
},
getLambdaSchedulePermissionLogicalId(functionName, scheduleIndex) {
return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionEventsRuleSchedule${
diff --git a/lib/plugins/aws/tests/naming.js b/lib/plugins/aws/tests/naming.js
index a2bd86fd1..7a106f9d1 100644
--- a/lib/plugins/aws/tests/naming.js
+++ b/lib/plugins/aws/tests/naming.js
@@ -325,16 +325,16 @@ describe('#naming()', () => {
describe('#getLambdaS3PermissionLogicalId()', () => {
it('should normalize the function name and add the standard suffix', () => {
- expect(sdk.naming.getLambdaS3PermissionLogicalId('functionName'))
- .to.equal('FunctionNameLambdaPermissionS3');
+ expect(sdk.naming.getLambdaS3PermissionLogicalId('functionName', 'bucket'))
+ .to.equal('FunctionNameLambdaPermissionBucketS3');
});
});
describe('#getLambdaSnsPermissionLogicalId()', () => {
it('should normalize the function and topic names and add them as prefix and suffix to the ' +
'standard permission center', () => {
- expect(sdk.naming.getLambdaSnsPermissionLogicalId('functionName', 'topicName'))
- .to.equal('FunctionNameLambdaPermissionTopicName');
+ expect(sdk.naming.getLambdaSnsPermissionLogicalId('functionName', 'topic'))
+ .to.equal('FunctionNameLambdaPermissionTopicSNS');
});
});