Skip to content

Commit

Permalink
fix: Don't duplicate PolicyDocument statement for stream events (serv…
Browse files Browse the repository at this point in the history
…erless#12313)

Each function consuming a stream event would emit its own PolicyDocument
statement. This statement would contain a list of actions that doesn't
change between functions. For DynamoDB streams the list is:

```
"Action": [
    "dynamodb:GetRecords",
    "dynamodb:GetShardIterator",
    "dynamodb:DescribeStream",
    "dynamodb:ListStreams"
],
```

Duplicating these for each function causes the IAM policy to exceed the
AWS limit after about 30 functions.

The resource names are still duplicated, if they happen to be the same.
  • Loading branch information
tibbe committed Jan 4, 2024
1 parent 7b1e012 commit f81b4b5
Showing 1 changed file with 74 additions and 74 deletions.
148 changes: 74 additions & 74 deletions lib/plugins/aws/package/compile/events/stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,56 +114,56 @@ class AwsCompileStreamEvents {
}

compileStreamEvents() {
const dynamodbStreamStatement = {
Effect: 'Allow',
Action: [
'dynamodb:GetRecords',
'dynamodb:GetShardIterator',
'dynamodb:DescribeStream',
'dynamodb:ListStreams',
],
Resource: [],
};
const kinesisStreamStatement = {
Effect: 'Allow',
Action: [
'kinesis:GetRecords',
'kinesis:GetShardIterator',
'kinesis:DescribeStream',
'kinesis:ListStreams',
],
Resource: [],
};
const kinesisStreamWithConsumerStatement = {
Effect: 'Allow',
Action: [
'kinesis:GetRecords',
'kinesis:GetShardIterator',
'kinesis:DescribeStreamSummary',
'kinesis:ListShards',
],
Resource: [],
};
const kinesisConsumerStatement = {
Effect: 'Allow',
Action: ['kinesis:SubscribeToShard'],
Resource: [],
};
const onFailureSnsStatement = {
Effect: 'Allow',
Action: ['sns:Publish'],
Resource: [],
};
const onFailureSqsStatement = {
Effect: 'Allow',
Action: ['sqs:ListQueues', 'sqs:SendMessage'],
Resource: [],
};

this.serverless.service.getAllFunctions().forEach((functionName) => {
const functionObj = this.serverless.service.getFunction(functionName);

if (functionObj.events) {
const dynamodbStreamStatement = {
Effect: 'Allow',
Action: [
'dynamodb:GetRecords',
'dynamodb:GetShardIterator',
'dynamodb:DescribeStream',
'dynamodb:ListStreams',
],
Resource: [],
};
const kinesisStreamStatement = {
Effect: 'Allow',
Action: [
'kinesis:GetRecords',
'kinesis:GetShardIterator',
'kinesis:DescribeStream',
'kinesis:ListStreams',
],
Resource: [],
};
const kinesisStreamWithConsumerStatement = {
Effect: 'Allow',
Action: [
'kinesis:GetRecords',
'kinesis:GetShardIterator',
'kinesis:DescribeStreamSummary',
'kinesis:ListShards',
],
Resource: [],
};
const kinesisConsumerStatement = {
Effect: 'Allow',
Action: ['kinesis:SubscribeToShard'],
Resource: [],
};
const onFailureSnsStatement = {
Effect: 'Allow',
Action: ['sns:Publish'],
Resource: [],
};
const onFailureSqsStatement = {
Effect: 'Allow',
Action: ['sqs:ListQueues', 'sqs:SendMessage'],
Resource: [],
};

functionObj.events.forEach((event) => {
if (event.stream) {
let EventSourceArn;
Expand Down Expand Up @@ -363,36 +363,36 @@ class AwsCompileStreamEvents {
);
}
});

// update the PolicyDocument statements (if default policy is used)
if (
this.serverless.service.provider.compiledCloudFormationTemplate.Resources
.IamRoleLambdaExecution
) {
const statement =
this.serverless.service.provider.compiledCloudFormationTemplate.Resources
.IamRoleLambdaExecution.Properties.Policies[0].PolicyDocument.Statement;
if (dynamodbStreamStatement.Resource.length) {
statement.push(dynamodbStreamStatement);
}
if (kinesisStreamStatement.Resource.length) {
statement.push(kinesisStreamStatement);
}
if (kinesisStreamWithConsumerStatement.Resource.length) {
statement.push(kinesisStreamWithConsumerStatement);
}
if (kinesisConsumerStatement.Resource.length) {
statement.push(kinesisConsumerStatement);
}
if (onFailureSnsStatement.Resource.length) {
statement.push(onFailureSnsStatement);
}
if (onFailureSqsStatement.Resource.length) {
statement.push(onFailureSqsStatement);
}
}
}
});

// update the PolicyDocument statements (if default policy is used)
if (
this.serverless.service.provider.compiledCloudFormationTemplate.Resources
.IamRoleLambdaExecution
) {
const statement =
this.serverless.service.provider.compiledCloudFormationTemplate.Resources
.IamRoleLambdaExecution.Properties.Policies[0].PolicyDocument.Statement;
if (dynamodbStreamStatement.Resource.length) {
statement.push(dynamodbStreamStatement);
}
if (kinesisStreamStatement.Resource.length) {
statement.push(kinesisStreamStatement);
}
if (kinesisStreamWithConsumerStatement.Resource.length) {
statement.push(kinesisStreamWithConsumerStatement);
}
if (kinesisConsumerStatement.Resource.length) {
statement.push(kinesisConsumerStatement);
}
if (onFailureSnsStatement.Resource.length) {
statement.push(onFailureSnsStatement);
}
if (onFailureSqsStatement.Resource.length) {
statement.push(onFailureSqsStatement);
}
}
}
}

Expand Down

0 comments on commit f81b4b5

Please sign in to comment.