Cloud Formation 将多个 S3 触发器添加到 LambdaConfigurations 中的同一个 S3 存储桶

Posted

技术标签:

【中文标题】Cloud Formation 将多个 S3 触发器添加到 LambdaConfigurations 中的同一个 S3 存储桶【英文标题】:Cloud Formation to add multiple S3 triggers to same S3 bucket in LambdaConfigurations 【发布时间】:2020-06-28 18:41:05 【问题描述】:

如果input.txt 文件在 S3 存储桶中创建,我的要求是触发 Lambda_Function_1,如果 output.txt 文件在同一个 S3 存储桶中创建,则触发 Lambda_Function_2

下面的 cfn 不起作用,但如果我只将一个事件而不是两个事件放在同一个 LambdaConfigurations 中,它就可以正常工作。

有人可以帮我吗?

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

【问题讨论】:

无法正常工作,cloudformation 堆栈创建失败或 lambda 调用未发生? 云形成堆栈失败,因为它两次不允许前缀。模板格式错误:YAML 格式不正确。 这里没有前缀重叠,多条带前缀的规则只要没有重叠就有效。你能发布整个模板吗? 代码很大,我无法在评论部分添加它,因此我在帖子答案部分添加了它。 不,这不是答案,请使用格式正确的完整模板编辑您的问题 【参考方案1】:

允许以prefixsuffix 作为名称的多个过滤规则,只要它们不重叠。请参阅here 了解各种示例,说明如何发生重叠以及如何避免重叠。

在这种情况下,错误Template format error: YAML not well-formed 可能是由于不正确的 YAML 格式。使用cfn-lint 验证模板。

添加一个显式指定 S3 对象的预期前缀和后缀的 sn-p。

      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

【讨论】:

【参考方案2】:

我实际上不得不这样做,创建多个 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"
                    ]
                
            
        
    ]

【讨论】:

以上是关于Cloud Formation 将多个 S3 触发器添加到 LambdaConfigurations 中的同一个 S3 存储桶的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Cloud Formation 模板在 S3 存储桶上设置 SSE-S3 或 SSE-KMS 加密?

如何在 Elastic Beanstalk Cloud Formation 脚本中强制 ELB 配置

Cloud Formation 模板将入口规则添加到现有安全组

AWS:Cloud Formation:是不是可以使用多个“DependsOn”?

如何使用 Cloud Formation 模板自动扩展 DynamoDB?

在单个 S3 对象上传事件上触发多个 lambda