Merge pull request #6240 from serverless/fix-smart-policy-name-resolution

Fix IAM policies setup for functions with custom name
This commit is contained in:
Mariusz Nowak 2019-06-12 16:38:15 +02:00 committed by GitHub
commit f0b3d9f42a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 166 additions and 25 deletions

View File

@ -1,3 +1,12 @@
# 1.45.1 (2019-06-12)
- [Fix IAM policies setup for functions with custom name](https://github.com/serverless/serverless/pull/6240)
- [Fix Travis CI deploy config](https://github.com/serverless/serverless/pull/6234)
## Meta
- [Comparison since last release](https://github.com/serverless/serverless/compare/v1.45.0...v1.45.1)
# 1.45.0 (2019-06-12)
- [Add `--config` option](https://github.com/serverless/serverless/pull/6216)

View File

@ -83,33 +83,58 @@ module.exports = {
}
);
const canonicalFunctionNamePrefix =
`${this.provider.serverless.service.service}-${this.provider.getStage()}`;
const logGroupsPrefix = this.provider.naming
.getLogGroupName(`${this.provider.serverless.service.service}-${this.provider.getStage()}`);
.getLogGroupName(canonicalFunctionNamePrefix);
this.serverless.service.provider.compiledCloudFormationTemplate
const policyDocumentStatements = this.serverless.service.provider.compiledCloudFormationTemplate
.Resources[this.provider.naming.getRoleLogicalId()]
.Properties
.Policies[0]
.PolicyDocument
.Statement[0]
.Statement;
// Ensure general polices for functions with default name resolution
policyDocumentStatements[0]
.Resource
.push({
'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' +
`:log-group:${logGroupsPrefix}*:*`,
});
this.serverless.service.provider.compiledCloudFormationTemplate
.Resources[this.provider.naming.getRoleLogicalId()]
.Properties
.Policies[0]
.PolicyDocument
.Statement[1]
policyDocumentStatements[1]
.Resource
.push({
'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' +
`:log-group:${logGroupsPrefix}*:*:*`,
});
// Ensure policies for functions with custom name resolution
this.serverless.service.getAllFunctions().forEach((functionName) => {
const { name: resolvedFunctionName } = this.serverless.service.getFunction(functionName);
if (!resolvedFunctionName || resolvedFunctionName.startsWith(canonicalFunctionNamePrefix)) {
return;
}
const customFunctionNamelogGroupsPrefix =
this.provider.naming.getLogGroupName(resolvedFunctionName);
policyDocumentStatements[0]
.Resource
.push({
'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' +
`:log-group:${customFunctionNamelogGroupsPrefix}:*`,
});
policyDocumentStatements[1]
.Resource
.push({
'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' +
`:log-group:${customFunctionNamelogGroupsPrefix}:*:*`,
});
});
if (this.serverless.service.provider.iamRoleStatements) {
// add custom iam role statements
this.serverless.service.provider.compiledCloudFormationTemplate
@ -117,12 +142,8 @@ module.exports = {
.Properties
.Policies[0]
.PolicyDocument
.Statement = this.serverless.service.provider.compiledCloudFormationTemplate
.Resources[this.provider.naming.getRoleLogicalId()]
.Properties
.Policies[0]
.PolicyDocument
.Statement.concat(this.serverless.service.provider.iamRoleStatements);
.Statement = policyDocumentStatements
.concat(this.serverless.service.provider.iamRoleStatements);
}
if (this.serverless.service.provider.iamManagedPolicies) {

View File

@ -9,12 +9,15 @@ const AwsPackage = require('../index');
describe('#mergeIamTemplates()', () => {
let awsPackage;
let serverless;
const serviceName = 'new-service';
const functionName = 'test';
const stage = 'dev';
const resolvedFunctionName = `${serviceName}-${stage}-${functionName}`;
beforeEach(() => {
serverless = new Serverless();
const options = {
stage: 'dev',
stage,
region: 'us-east-1',
};
serverless.setProvider('aws', new AwsProvider(serverless, options));
@ -23,14 +26,14 @@ describe('#mergeIamTemplates()', () => {
awsPackage.serverless.service.provider.compiledCloudFormationTemplate = {
Resources: {},
};
awsPackage.serverless.service.service = 'new-service';
awsPackage.serverless.service.service = serviceName;
awsPackage.serverless.service.functions = {
[functionName]: {
name: 'test',
artifact: 'test.zip',
handler: 'handler.hello',
},
};
serverless.service.setFunctionNames(); // Ensure to resolve function names
});
it('should not merge if there are no functions', () => {
@ -136,6 +139,114 @@ describe('#mergeIamTemplates()', () => {
})
);
it('should ensure IAM policies for custom named functions', () => {
const customFunctionName = 'foo-bar';
awsPackage.serverless.service.functions = {
[functionName]: {
name: customFunctionName,
artifact: 'test.zip',
handler: 'handler.hello',
},
};
serverless.service.setFunctionNames(); // Ensure to resolve function names
return awsPackage.mergeIamTemplates()
.then(() => {
const canonicalFunctionsPrefix =
`${awsPackage.serverless.service.service}-${awsPackage.provider.getStage()}`;
expect(awsPackage.serverless.service.provider.compiledCloudFormationTemplate
.Resources[awsPackage.provider.naming.getRoleLogicalId()]
).to.deep.equal({
Type: 'AWS::IAM::Role',
Properties: {
AssumeRolePolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Principal: {
Service: [
'lambda.amazonaws.com',
],
},
Action: [
'sts:AssumeRole',
],
},
],
},
Path: '/',
Policies: [
{
PolicyName: {
'Fn::Join': [
'-',
[
awsPackage.provider.getStage(),
awsPackage.serverless.service.service,
'lambda',
],
],
},
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: [
'logs:CreateLogStream',
],
Resource: [
{
'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:'
+ `log-group:/aws/lambda/${canonicalFunctionsPrefix}*:*`,
},
{
'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:'
+ `log-group:/aws/lambda/${customFunctionName}:*`,
},
],
},
{
Effect: 'Allow',
Action: [
'logs:PutLogEvents',
],
Resource: [
{
'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:'
+ `log-group:/aws/lambda/${canonicalFunctionsPrefix}*:*:*`,
},
{
'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:'
+ `log-group:/aws/lambda/${customFunctionName}:*:*`,
},
],
},
],
},
},
],
RoleName: {
'Fn::Join': [
'-',
[
awsPackage.serverless.service.service,
awsPackage.provider.getStage(),
{
Ref: 'AWS::Region',
},
'lambdaRole',
],
],
},
},
});
});
});
it('should add custom IAM policy statements', () => {
awsPackage.serverless.service.provider.iamRoleStatements = [
{
@ -291,7 +402,7 @@ describe('#mergeIamTemplates()', () => {
{
Type: 'AWS::Logs::LogGroup',
Properties: {
LogGroupName: awsPackage.provider.naming.getLogGroupName(functionName),
LogGroupName: awsPackage.provider.naming.getLogGroupName(resolvedFunctionName),
},
}
);
@ -310,7 +421,7 @@ describe('#mergeIamTemplates()', () => {
{
Type: 'AWS::Logs::LogGroup',
Properties: {
LogGroupName: awsPackage.provider.naming.getLogGroupName(functionName),
LogGroupName: awsPackage.provider.naming.getLogGroupName(resolvedFunctionName),
RetentionInDays: 5,
},
}

8
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "serverless",
"version": "1.45.0",
"version": "1.45.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -7521,9 +7521,9 @@
}
},
"resolve": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz",
"integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
"integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"

View File

@ -1,6 +1,6 @@
{
"name": "serverless",
"version": "1.45.0",
"version": "1.45.1",
"engines": {
"node": ">=6.0"
},