From 91fa043ecc8bab61bc23add1bc59784541075195 Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Wed, 16 Nov 2016 16:08:21 +0700 Subject: [PATCH 1/3] limited permissions for s3, sns and apig --- .../events/apiGateway/lib/method/index.js | 17 ++++++++++++----- .../apiGateway/lib/method/integration.js | 4 +--- .../events/apiGateway/lib/permissions.js | 18 +++++++++++------- .../aws/deploy/compile/events/s3/index.js | 15 +++++++++++---- .../aws/deploy/compile/events/sns/index.js | 3 ++- lib/plugins/aws/lib/naming.js | 10 ++++++---- 6 files changed, 43 insertions(+), 24 deletions(-) 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..0d76e56e1 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 = { methodLogicalId, 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..7169f47fb 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,29 @@ 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, + singlePermissionMapping.event.http.method); _.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::GetAtt': [singlePermissionMapping.methodLogicalId, 'Arn'], + }, }, }, }); - 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); @@ -37,6 +39,8 @@ module.exports = { FunctionName: authorizer.arn, Action: 'lambda:InvokeFunction', Principal: 'apigateway.amazonaws.com', + // no need for SourceArn here because authorizers + // are created at the REST API Level }, }, }); diff --git a/lib/plugins/aws/deploy/compile/events/s3/index.js b/lib/plugins/aws/deploy/compile/events/s3/index.js index e98e883df..0f47d01de 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,11 @@ 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 bucketLogicalId = this.provider.naming + .getBucketLogicalId(s3EnabledFunction.bucketName); const permissionTemplate = { Type: 'AWS::Lambda::Permission', Properties: { @@ -164,10 +167,14 @@ class AwsCompileS3Events { }, Action: 'lambda:InvokeFunction', Principal: 's3.amazonaws.com', + SourceArn: { + 'Fn::GetAtt': [bucketLogicalId, 'Arn'], + }, }, }; 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/sns/index.js b/lib/plugins/aws/deploy/compile/events/sns/index.js index 83995d4c0..76df0f9ad 100644 --- a/lib/plugins/aws/deploy/compile/events/sns/index.js +++ b/lib/plugins/aws/deploy/compile/events/sns/index.js @@ -79,7 +79,8 @@ class AwsCompileSNSEvents { "Properties": { "FunctionName": { "Fn::GetAtt": ["${lambdaLogicalId}", "Arn"] }, "Action": "lambda:InvokeFunction", - "Principal": "sns.amazonaws.com" + "Principal": "sns.amazonaws.com", + "SourceArn": { "Fn::GetAtt": ["${topicLogicalId}", "Arn"] } } } `; diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js index a77d14a8a..9f8136044 100644 --- a/lib/plugins/aws/lib/naming.js +++ b/lib/plugins/aws/lib/naming.js @@ -136,8 +136,9 @@ module.exports = { }, // Permissions - getLambdaS3PermissionLogicalId(functionName) { - return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionS3`; + getLambdaS3PermissionLogicalId(functionName, bucketName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${this + .normalizeBucketName(bucketName)}`; }, getLambdaSnsPermissionLogicalId(functionName, topicName) { return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${ @@ -147,7 +148,8 @@ module.exports = { return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionEventsRuleSchedule${ scheduleIndex}`; }, - getLambdaApiGatewayPermissionLogicalId(functionName) { - return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionApiGateway`; + getLambdaApiGatewayPermissionLogicalId(functionName, methodName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${this + .normalizeMethodName(methodName)}ApiGateway`; }, }; From ad2117423b4b0d661db1c9e667c36293f69af4eb Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Thu, 17 Nov 2016 18:38:33 +0700 Subject: [PATCH 2/3] limited lambda permissions for events --- .../events/apiGateway/lib/method/index.js | 2 +- .../events/apiGateway/lib/permissions.js | 20 ++++-- .../events/apiGateway/tests/permissions.js | 64 ++++++++++++++----- .../aws/deploy/compile/events/s3/index.js | 10 +-- .../deploy/compile/events/s3/tests/index.js | 7 +- .../aws/deploy/compile/events/sns/index.js | 11 +++- .../deploy/compile/events/sns/tests/index.js | 6 +- lib/plugins/aws/lib/naming.js | 11 ++-- lib/plugins/aws/tests/naming.js | 18 ++++-- 9 files changed, 107 insertions(+), 42 deletions(-) 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 0d76e56e1..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 @@ -34,7 +34,7 @@ module.exports = { const lambdaLogicalId = this.provider.naming .getLambdaLogicalId(event.functionName); - const singlePermissionMapping = { methodLogicalId, lambdaLogicalId, event }; + const singlePermissionMapping = { resourceName, lambdaLogicalId, event }; this.permissionMapping.push(singlePermissionMapping); _.merge(template, 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 7169f47fb..c4d53bce0 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js @@ -9,6 +9,7 @@ module.exports = { this.permissionMapping.forEach((singlePermissionMapping) => { const lambdaPermissionLogicalId = this.provider.naming .getLambdaApiGatewayPermissionLogicalId(singlePermissionMapping.event.functionName, + singlePermissionMapping.resourceName, singlePermissionMapping.event.http.method); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { @@ -20,9 +21,18 @@ module.exports = { }, Action: 'lambda:InvokeFunction', Principal: 'apigateway.amazonaws.com', - SourceArn: { - 'Fn::GetAtt': [singlePermissionMapping.methodLogicalId, 'Arn'], - }, + SourceArn: { 'Fn::Join': ['', + [ + 'arn:aws:execute-api:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':', + { Ref: this.apiGatewayRestApiLogicalId }, + `/*/${singlePermissionMapping.event.http.method + .toUpperCase()}/${singlePermissionMapping.event.http.path}`, + ], + ] }, }, }, }); @@ -30,7 +40,7 @@ module.exports = { if (singlePermissionMapping.event.http.authorizer) { const authorizer = singlePermissionMapping.event.http.authorizer; const authorizerPermissionLogicalId = this.provider.naming - .getLambdaApiGatewayPermissionLogicalId(authorizer.name); + .getLambdaApiGatewayAuthorizerPermissionLogicalId(authorizer.name); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [authorizerPermissionLogicalId]: { @@ -39,8 +49,6 @@ module.exports = { FunctionName: authorizer.arn, Action: 'lambda:InvokeFunction', Principal: 'apigateway.amazonaws.com', - // no need for SourceArn here because authorizers - // are created at the REST API Level }, }, }); 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..e302803af 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', () => { awsCompileApigEvents.validated.events = [ { functionName: 'First', @@ -26,28 +26,43 @@ 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', }, }, ]; return awsCompileApigEvents.compilePermissions().then(() => { expect(awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate - .Resources.FirstLambdaPermissionApiGateway + .Resources.FirstLambdaPermissionFooBarPostApiGateway .Properties.FunctionName['Fn::GetAtt'][0]).to.equal('FirstLambdaFunction'); + + const deepObj = { 'Fn::Join': ['', + [ + 'arn:aws:execute-api:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':', + { Ref: 'ApiGatewayRestApi' }, + '/*/POST/foo/bar', + ], + ] }; + expect(awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate - .Resources.SecondLambdaPermissionApiGateway - .Properties.FunctionName['Fn::GetAtt'][0]).to.equal('SecondLambdaFunction'); + .Resources.FirstLambdaPermissionFooBarPostApiGateway + .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 0f47d01de..0db67be13 100644 --- a/lib/plugins/aws/deploy/compile/events/s3/index.js +++ b/lib/plugins/aws/deploy/compile/events/s3/index.js @@ -154,8 +154,6 @@ class AwsCompileS3Events { s3EnabledFunctions.forEach(s3EnabledFunction => { const lambdaLogicalId = this.provider.naming .getLambdaLogicalId(s3EnabledFunction.functionName); - const bucketLogicalId = this.provider.naming - .getBucketLogicalId(s3EnabledFunction.bucketName); const permissionTemplate = { Type: 'AWS::Lambda::Permission', Properties: { @@ -167,9 +165,11 @@ class AwsCompileS3Events { }, Action: 'lambda:InvokeFunction', Principal: 's3.amazonaws.com', - SourceArn: { - 'Fn::GetAtt': [bucketLogicalId, 'Arn'], - }, + SourceArn: { 'Fn::Join': ['', + [ + `arn:aws:s3:::${s3EnabledFunction.bucketName}`, + ], + ] }, }, }; const lambdaPermissionLogicalId = this.provider.naming 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 76df0f9ad..abcc11c66 100644 --- a/lib/plugins/aws/deploy/compile/events/sns/index.js +++ b/lib/plugins/aws/deploy/compile/events/sns/index.js @@ -80,7 +80,16 @@ class AwsCompileSNSEvents { "FunctionName": { "Fn::GetAtt": ["${lambdaLogicalId}", "Arn"] }, "Action": "lambda:InvokeFunction", "Principal": "sns.amazonaws.com", - "SourceArn": { "Fn::GetAtt": ["${topicLogicalId}", "Arn"] } + "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 9f8136044..8e01655f5 100644 --- a/lib/plugins/aws/lib/naming.js +++ b/lib/plugins/aws/lib/naming.js @@ -138,18 +138,21 @@ module.exports = { // Permissions getLambdaS3PermissionLogicalId(functionName, bucketName) { return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${this - .normalizeBucketName(bucketName)}`; + .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${ scheduleIndex}`; }, - getLambdaApiGatewayPermissionLogicalId(functionName, methodName) { - return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${this + getLambdaApiGatewayPermissionLogicalId(functionName, resourceId, methodName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${resourceId}${this .normalizeMethodName(methodName)}ApiGateway`; }, + getLambdaApiGatewayAuthorizerPermissionLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionApiGateway`; + }, }; diff --git a/lib/plugins/aws/tests/naming.js b/lib/plugins/aws/tests/naming.js index a2bd86fd1..85df8e999 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'); }); }); @@ -348,7 +348,15 @@ describe('#naming()', () => { describe('#getLambdaApiGatewayPermissionLogicalId()', () => { it('should normalize the function name and append the standard suffix', () => { - expect(sdk.naming.getLambdaApiGatewayPermissionLogicalId('functionName')) + expect(sdk.naming.getLambdaApiGatewayPermissionLogicalId('functionName', + 'UsersCreate', 'get')) + .to.equal('FunctionNameLambdaPermissionUsersCreateGetApiGateway'); + }); + }); + + describe('#getLambdaApiGatewayAuthorizerPermissionLogicalId()', () => { + it('should normalize the authorizer name and append the standard suffix', () => { + expect(sdk.naming.getLambdaApiGatewayAuthorizerPermissionLogicalId('functionName')) .to.equal('FunctionNameLambdaPermissionApiGateway'); }); }); From cfdac252da90da1c94ad933a3f448d76eb6047d4 Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Fri, 18 Nov 2016 21:05:21 +0700 Subject: [PATCH 3/3] relaxed apig permissions to be rest api scoped --- docs/providers/aws/guide/resources.md | 2 +- .../compile/events/apiGateway/lib/permissions.js | 9 +++------ .../compile/events/apiGateway/tests/permissions.js | 8 ++++---- lib/plugins/aws/lib/naming.js | 6 +----- lib/plugins/aws/tests/naming.js | 10 +--------- 5 files changed, 10 insertions(+), 25 deletions(-) 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/permissions.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js index c4d53bce0..3fe5d5546 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js @@ -8,9 +8,7 @@ module.exports = { compilePermissions() { this.permissionMapping.forEach((singlePermissionMapping) => { const lambdaPermissionLogicalId = this.provider.naming - .getLambdaApiGatewayPermissionLogicalId(singlePermissionMapping.event.functionName, - singlePermissionMapping.resourceName, - singlePermissionMapping.event.http.method); + .getLambdaApiGatewayPermissionLogicalId(singlePermissionMapping.event.functionName); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [lambdaPermissionLogicalId]: { @@ -29,8 +27,7 @@ module.exports = { { Ref: 'AWS::AccountId' }, ':', { Ref: this.apiGatewayRestApiLogicalId }, - `/*/${singlePermissionMapping.event.http.method - .toUpperCase()}/${singlePermissionMapping.event.http.path}`, + '/*/*', ], ] }, }, @@ -40,7 +37,7 @@ module.exports = { if (singlePermissionMapping.event.http.authorizer) { const authorizer = singlePermissionMapping.event.http.authorizer; const authorizerPermissionLogicalId = this.provider.naming - .getLambdaApiGatewayAuthorizerPermissionLogicalId(authorizer.name); + .getLambdaApiGatewayPermissionLogicalId(authorizer.name); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [authorizerPermissionLogicalId]: { 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 e302803af..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 limited permission resource', () => { + it('should create limited permission resource scope to REST API', () => { awsCompileApigEvents.validated.events = [ { functionName: 'First', @@ -45,7 +45,7 @@ describe('#awsCompilePermissions()', () => { return awsCompileApigEvents.compilePermissions().then(() => { expect(awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate - .Resources.FirstLambdaPermissionFooBarPostApiGateway + .Resources.FirstLambdaPermissionApiGateway .Properties.FunctionName['Fn::GetAtt'][0]).to.equal('FirstLambdaFunction'); const deepObj = { 'Fn::Join': ['', @@ -56,12 +56,12 @@ describe('#awsCompilePermissions()', () => { { Ref: 'AWS::AccountId' }, ':', { Ref: 'ApiGatewayRestApi' }, - '/*/POST/foo/bar', + '/*/*', ], ] }; expect(awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate - .Resources.FirstLambdaPermissionFooBarPostApiGateway + .Resources.FirstLambdaPermissionApiGateway .Properties.SourceArn).to.deep.equal(deepObj); }); }); diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js index 8e01655f5..2fd5020ed 100644 --- a/lib/plugins/aws/lib/naming.js +++ b/lib/plugins/aws/lib/naming.js @@ -148,11 +148,7 @@ module.exports = { return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionEventsRuleSchedule${ scheduleIndex}`; }, - getLambdaApiGatewayPermissionLogicalId(functionName, resourceId, methodName) { - return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${resourceId}${this - .normalizeMethodName(methodName)}ApiGateway`; - }, - getLambdaApiGatewayAuthorizerPermissionLogicalId(functionName) { + getLambdaApiGatewayPermissionLogicalId(functionName) { return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionApiGateway`; }, }; diff --git a/lib/plugins/aws/tests/naming.js b/lib/plugins/aws/tests/naming.js index 85df8e999..7a106f9d1 100644 --- a/lib/plugins/aws/tests/naming.js +++ b/lib/plugins/aws/tests/naming.js @@ -348,15 +348,7 @@ describe('#naming()', () => { describe('#getLambdaApiGatewayPermissionLogicalId()', () => { it('should normalize the function name and append the standard suffix', () => { - expect(sdk.naming.getLambdaApiGatewayPermissionLogicalId('functionName', - 'UsersCreate', 'get')) - .to.equal('FunctionNameLambdaPermissionUsersCreateGetApiGateway'); - }); - }); - - describe('#getLambdaApiGatewayAuthorizerPermissionLogicalId()', () => { - it('should normalize the authorizer name and append the standard suffix', () => { - expect(sdk.naming.getLambdaApiGatewayAuthorizerPermissionLogicalId('functionName')) + expect(sdk.naming.getLambdaApiGatewayPermissionLogicalId('functionName')) .to.equal('FunctionNameLambdaPermissionApiGateway'); }); });