Kiran Annamaneni
Kiran Annamaneni

Reputation: 91

Cloud Formation to add multiple S3 triggers to same S3 bucket in LambdaConfigurations

My requirement is to trigger Lambda_Function_1 if input.txt file creates in S3 bucket and trigger Lambda_Function_2 if output.txt file creates in same S3 bucket.

The below cfn is not working, but it works fine if I put only one event instead of two events in same LambdaConfigurations.

Can some one please help me here?

Parameters:
  S3BucketBaseName:
    Type: String
    Description: The base name of the Amazon S3 bucket.
    Default: dw-trip


Resources:
  LambdaStart: 
    DependsOn:
      - LambdaStartStopEC2
    Type: "AWS::Lambda::Function"
    Properties:
      FunctionName: "dw-trip-start-ec2"
      Handler: "index.handler"
      Role: !GetAtt LambdaStartStopEC2.Arn
      Runtime: python3.7
      MemorySize: 3008
      Timeout: 900
      Code:
        ZipFile: |
          import boto3
          region = 'us-east-1'
          instances = ['i-05d5fbec4c82956b6']
          ec2 = boto3.client('ec2', region_name=region)
          def lambda_handler(event, context):
              ec2.start_instances(InstanceIds=instances)
              print('started your instances: ' + str(instances))

  ProcessingLambdaPermissionStart:
    Type: AWS::Lambda::Permission
    DependsOn:
      - LambdaStart    
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref LambdaStart
      Principal: s3.amazonaws.com
      SourceArn:
                Fn::Join: 
                  - ''
                  - - 'arn:aws:s3:::'
                    - !Join ["-",[!Ref "S3BucketBaseName",!Ref "AWS::AccountId"]]
      SourceAccount: !Ref AWS::AccountId

  LambdaStop: 
    DependsOn:
      - ProcessingLambdaPermissionStart
    Type: "AWS::Lambda::Function"
    Properties:
      FunctionName: "dw-trip-stop-ec2"
      Handler: "index.handler"
      Role: !GetAtt LambdaStartStopEC2.Arn
      Runtime: python3.7
      MemorySize: 3008
      Timeout: 900
      Code:
        ZipFile: |
          import boto3
          region = 'us-east-1'
          instances = ['i-05d5fbec4c82956b6']
          ec2 = boto3.client('ec2', region_name=region)
          def lambda_handler(event, context):
              ec2.stop_instances(InstanceIds=instances)
              print('stopping your instances: ' + str(instances))

  ProcessingLambdaPermissionStop:
    Type: AWS::Lambda::Permission
    DependsOn:
      - LambdaStop  
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref LambdaStop
      Principal: s3.amazonaws.com
      SourceArn:
                Fn::Join: 
                  - ''
                  - - 'arn:aws:s3:::'
                    - !Join ["-",[!Ref "S3BucketBaseName",!Ref "AWS::AccountId"]]
      SourceAccount: !Ref AWS::AccountId

  S3KmsKey:
    Type: AWS::KMS::Key
    DependsOn:
      - ProcessingLambdaPermissionStop
    Properties:
      Description: KMS key for trip S3 bucket.
      Enabled: true
      EnableKeyRotation: true
      KeyPolicy:
        Statement:
          - Sid: Administration
            Effect: Allow
            Principal:
              AWS:
                - Fn::Join:
                    - ''
                    - - 'arn:aws:iam::'
                      - Ref: AWS::AccountId
                      - ':role/DW01-codepipeline-action-us-east-1'              
                - Fn::Join:
                    - ''
                    - - 'arn:aws:iam::'
                      - Ref: AWS::AccountId
                      - ':root'
            Action: 'kms:*'
            Resource: '*'

  S3bucketCreate:
    DependsOn:
      - S3KmsKey
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Join ["-",[!Ref "S3BucketBaseName",!Ref "AWS::AccountId"]]
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              KMSMasterKeyID: !Ref S3KmsKey
              SSEAlgorithm: "aws:kms"
      NotificationConfiguration:
        LambdaConfigurations:
          - Event: s3:ObjectCreated:*
            Function: !GetAtt LambdaStart.Arn
            Filter:
              S3Key:
                Rules:
                - Name: prefix
                  Value: input.txt               
          - Event: s3:ObjectCreated:*
            Function: !GetAtt LambdaStop.Arn
            Filter:
              S3Key:
                Rules:
                - Name: prefix
                  Value: output.txt     

  S3bucketPolicy:
    DependsOn:
      - S3bucketCreate        
    Type: AWS::S3::BucketPolicy
    Properties: 
      Bucket: 
        Ref: 'S3bucketCreate'
      PolicyDocument: 
        Statement: 
          - Sid: AllowEc2AccesstoBucket
            Action: 
              - 's3:GetObject'
              - 's3:PutObject'              
            Effect: Allow
            Principal:
              AWS:
                - Fn::Join:          
                  - ''
                  - - 'arn:aws:iam::'
                    - Ref: AWS::AccountId
                    - ':role/DevDW01-EC2-us-east-1'
            Resource: 
                Fn::Join: 
                  - ''
                  - - 'arn:aws:s3:::'
                    - Ref: 'S3bucketCreate'
                    - '/*'              
  LambdaStartStopEC2:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: 
              - lambda.amazonaws.com
            Action: sts:AssumeRole
      RoleName: Lambda-StartStop-EC2
      MaxSessionDuration: 43200
      Policies:
        - PolicyName: StartStop-EC2
          PolicyDocument:
            Statement:
            - Action:
              - s3:*
              Effect: Allow
              Resource: '*'
            - Action:
              - ec2:*
              Effect: Allow
              Resource: '*'
        - PolicyName: logs
          PolicyDocument:
            Statement:
            - Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:DescribeLogGroups
              - logs:DescribeLogStreams
              - logs:PutLogEvents
              - logs:GetLogEvents
              - logs:FilterLogEvents
              Effect: Allow
              Resource: '*'

Outputs:
  S3bucketCreateName:
    Value:
      Ref: S3bucketCreate
    Export:
      Name: S3bucketCreateName
  S3bucketCreateArn:
    Value:
      Fn::GetAtt: S3bucketCreate.Arn
    Export:
      Name: S3bucketCreateArn
  S3KmsKeyArn:
    Value:
      Fn::GetAtt: S3KmsKey.Arn
    Export:
      Name: S3KmsKeyArn

Upvotes: 4

Views: 2996

Answers (2)

user1503606
user1503606

Reputation: 4300

I actually had to do it like this create multiple LambdaConfigurations.

"NotificationConfiguration": {
    "LambdaConfigurations": [{
            "Event": "s3:ObjectCreated:*",
            "Function": {
                "Fn::GetAtt": ["lambdaVodFunction", "Arn"]
            },
            "Filter": {
                "S3Key": {
                    "Rules": [{
                        "Name": "suffix",
                        "Value": ".mp4"
                    }]
                }
            }
        },
        {
            "Event": "s3:ObjectCreated:*",
            "Function": {
                "Fn::GetAtt": ["lambdaVodFunction", "Arn"]
            },
            "Filter": {
                "S3Key": {
                    "Rules": [{
                        "Name": "suffix",
                        "Value": ".mov"
                    }]
                }
            }
        }
    ]
}

Upvotes: 0

franklinsijo
franklinsijo

Reputation: 18270

Multiple filter rules with prefix and suffix as name are allowed as long as they do not overlap. Refer here for various examples explaining how overlapping may occur and how to avoid them.

In this case, the error Template format error: YAML not well-formed is possibly due to improper YAML formatting. Use cfn-lint to validate the templates.

Adding a snippet that explicitly specifies the expected prefix and suffix of the S3 object.

      NotificationConfiguration:
        LambdaConfigurations:
          - Event: s3:ObjectCreated:*
            Function: !GetAtt LambdaStart.Arn
            Filter:
              S3Key:
                Rules:
                - Name: prefix
                  Value: input
                - Name: suffix
                  Value: txt           
          - Event: s3:ObjectCreated:*
            Function: !GetAtt LambdaStop.Arn
            Filter:
              S3Key:
                Rules:
                - Name: prefix
                  Value: output
                - Name: suffix
                  Value: txt

Upvotes: 2

Related Questions