Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically add multiple event notifications to s3 bucket

I would like to use the below cloudformation template to create multiple event notifications on a single existing S3 bucket. However, even if I specify another "LambdaFunctionConfigurations" under the BucketConfiguration resource I only see one event created on the S3 bucket. I've also tried creating another BucketConfiguration resource with a separate event configured without any luck. I'm looking for any tips or advice that would help point me in the right direction. From what I gather the s3.putBucketNotification method will clear any existing event notification configuration. Please keep in mind that the CF template does create a single event notification (I'm looking to create multiple event notifications).

Model for below template: Create a Lambda notification in an S3 bucket with CloudFormation

Description: >-
  Create an event notification for an existing S3 bucket
Parameters:
  BucketName:
    Description: S3 Bucket name (must already exist)
    Type: String
Resources:
  BucketConfiguration:
    Type: 'Custom::S3BucketConfiguration'
    DependsOn:
      - BucketPermission
      - NotificationBucketPolicy
    Properties:
      ServiceToken: !GetAtt S3BucketConfiguration.Arn
      Bucket: !Ref BucketName
      NotificationConfiguration:
        LambdaFunctionConfigurations:
          - Events:
              - 's3:ObjectCreated:*'
            LambdaFunctionArn: MyLambdaArn
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 606b322f-42fa-4d20-bae4-53374d7ad7ba
  S3BucketConfiguration:
    Type: 'AWS::Lambda::Function'
    Properties:
      Description: S3 Object Custom Resource
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var response = require('cfn-response');
          var AWS = require('aws-sdk');
          var s3 = new AWS.S3();
          exports.handler = function(event, context) {
            var respond = (e) => response.send(event, context, e ? response.FAILED : response.SUCCESS, e ? e : {});
            process.on('uncaughtException', e=>failed(e));
            var params = event.ResourceProperties;
            delete params.ServiceToken;
            if (event.RequestType === 'Delete') {
              params.NotificationConfiguration = {};
              s3.putBucketNotificationConfiguration(params).promise()
                .then((data)=>respond())
                .catch((e)=>respond());
            } else {
              s3.putBucketNotificationConfiguration(params).promise()
                .then((data)=>respond())
                .catch((e)=>respond(e));
            }
          };
      Timeout: 30
      Runtime: nodejs6.10
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 1cefd553-f888-4b3b-8184-d96932a29227
  BucketPermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      Principal: s3.amazonaws.com
      SourceAccount: !Ref 'AWS::AccountId'
      SourceArn: !Sub 'arn:aws:s3:::${BucketName}'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 29f90f84-cfd0-43d2-8c2b-c173ec96c409
  LambdaExecutionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
      Policies:
        - PolicyName: S3Policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 's3:PutObject'
                  - 'S3:DeleteObject'
                Resource: !Sub 'arn:aws:s3:::${BucketName}'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 3556f770-b7cd-4ac1-8afa-62a0319721b8
  NotificationBucketPolicy:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
      Bucket: !Ref BucketName
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - 's3:PutBucketNotification'
            Resource: !Sub 'arn:aws:s3:::${BucketName}'
            Principal:
              AWS: !GetAtt LambdaExecutionRole.Arn
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 1f82086e-0d71-4731-8173-e3b8ee0da4dd
Metadata:
  'AWS::CloudFormation::Designer':
    3556f770-b7cd-4ac1-8afa-62a0319721b8:
      size:
        width: 60
        height: 60
      position:
        x: 60
        'y': 90
      z: 1
      embeds: []
    1f82086e-0d71-4731-8173-e3b8ee0da4dd:
      size:
        width: 60
        height: 60
      position:
        x: 180
        'y': 90
      z: 1
      embeds: []
    29f90f84-cfd0-43d2-8c2b-c173ec96c409:
      size:
        width: 60
        height: 60
      position:
        x: 410
        'y': 90
      z: 1
      embeds: []
    1cefd553-f888-4b3b-8184-d96932a29227:
      size:
        width: 60
        height: 60
      position:
        x: 300
        'y': 190
      z: 1
      embeds: []
    606b322f-42fa-4d20-bae4-53374d7ad7ba:
      size:
        width: 60
        height: 60
      position:
        x: 300
        'y': 90
      z: 1
      embeds: []
      dependson:
        - 29f90f84-cfd0-43d2-8c2b-c173ec96c409
        - 1f82086e-0d71-4731-8173-e3b8ee0da4dd
like image 259
Kirby02235 Avatar asked Oct 17 '22 05:10

Kirby02235


1 Answers

You are correct that it is not possible to have multiple Events defined for the same 'triggers'.

For example, in the S3 console I was successfully able to define:

  • Multiple rules for the same event but a different prefix
  • Multiple rules for the same prefix but a different event

However, I could not define multiple rules for the same event and same prefix. The error message was:

Configuration is ambiguously defined. Cannot have overlapping suffixes in two rules if the prefixes are overlapping for the same event type.

Based on your question, it appears you want to trigger multiple Lambda functions for the same event within the same prefix (which includes 'the whole bucket'). For that, I would recommend:

  • Create an Amazon SNS topic
  • Create an S3 Event that points to the SNS topic
  • Subscribe each Lambda function to the SNS topic
like image 198
John Rotenstein Avatar answered Nov 03 '22 06:11

John Rotenstein