如何使用 CloudFormation 在现有 S3 存储桶上为 Lambda 创建 Amazon S3 通知配置?

上次更新日期:2021 年 8 月 5 日

我想要使用现有的 Amazon Simple Storage Service (Amazon S3) 存储桶为 Amazon Lambda 函数创建 Amazon S3 通知配置。我想使用 AWS CloudFormation 来实现这一点。

简短描述

要创建 Amazon S3 通知配置,可以使用 CloudFormation 创建新的 S3 存储桶。然后,使用 NotificationConfiguration 属性在该存储桶中添加通知配置。或者,在现有 S3 存储桶中手动添加通知配置

以下步骤将向您介绍如何通过 Python 3.6 中创建的 Lambda 支持的自定义资源,使用 CloudFormation 在现有 S3 存储桶中添加通知配置。自定义资源会触发 Lambda 函数,该函数将触发 PutBucketNotification API 在您的 S3 存储桶中添加通知配置。

注意:如果您在运行 AWS 命令行界面 (AWS CLI) 命令时遇到错误,请确保您使用的是最新版的 AWS CLI

解决方法

重要提示:以下步骤仅适用于不具有现有通知配置的 S3 存储桶的 Amazon S3 通知配置。如果您的 S3 存储桶已有现有的或手动创建的通知配置,以下步骤将覆盖其配置。移除堆栈后,将删除所有通知。如果您的解决方案看起来可行,则与使用案例相关的配置可能不够理想。最佳实践是在部署到生产环境之前,在测试 S3 存储桶上测试您的解决方案。

1.    创建一个包含以下代码的名为 LambdaS3.template 的 CloudFormation 模板。

重要提示:在下面的示例中,您将 S3 通知配置添加到 S3NotificationLambdaFunction 资源。您使用 Lambda 函数 CustomResourceLambdaFunctionS3NotificationLambdaFunction 添加 S3 通知配置。要满足您的要求,您可以修改 CustomResourceLambdaFunction 资源中的代码。

AWSTemplateFormatVersion: 2010-09-09
Description: >-
  Sample template to illustrate use of existing S3 bucket as an event source for a Lambda function
Parameters:
  NotificationBucket:
    Type: String
    Description: S3 bucket that's used for the Lambda event notification

Resources:
  S3NotificationLambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Code:
        ZipFile: !Join
          - |+

          - - import json
            - 'def lambda_handler(event,context):'
            - '    return ''Welcome... This is a test Lambda Function'''
      Handler: index.lambda_handler
      Role: !GetAtt LambdaIAMRole.Arn
      Runtime: python3.6
      Timeout: 5

  LambdaInvokePermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      FunctionName: !GetAtt S3NotificationLambdaFunction.Arn
      Action: 'lambda:InvokeFunction'
      Principal: s3.amazonaws.com
      SourceAccount: !Ref 'AWS::AccountId'
      SourceArn: !Sub 'arn:aws:s3:::${NotificationBucket}'

  LambdaIAMRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 's3:GetBucketNotification'
                  - 's3:PutBucketNotification'
                Resource: !Sub 'arn:aws:s3:::${NotificationBucket}'
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: 'arn:aws:logs:*:*:*'

  CustomResourceLambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.lambda_handler
      Role: !GetAtt LambdaIAMRole.Arn
      Code:
        ZipFile: |

            from __future__ import print_function
            import json
            import boto3
            import cfnresponse
            
            SUCCESS = "SUCCESS"
            FAILED = "FAILED"
            
            print('Loading function')
            s3 = boto3.resource('s3')
            
            def lambda_handler(event, context):
                print("Received event: " + json.dumps(event, indent=2))
                responseData={}
                try:
                    if event['RequestType'] == 'Delete':
                        print("Request Type:",event['RequestType'])
                        Bucket=event['ResourceProperties']['Bucket']
                        delete_notification(Bucket)
                        print("Sending response to custom resource after Delete")
                    elif event['RequestType'] == 'Create' or event['RequestType'] == 'Update':
                        print("Request Type:",event['RequestType'])
                        LambdaArn=event['ResourceProperties']['LambdaArn']
                        Bucket=event['ResourceProperties']['Bucket']
                        add_notification(LambdaArn, Bucket)
                        responseData={'Bucket':Bucket}
                        print("Sending response to custom resource")
                    responseStatus = 'SUCCESS'
                except Exception as e:
                    print('Failed to process:', e)
                    responseStatus = 'FAILED'
                    responseData = {'Failure': 'Something bad happened.'}
                cfnresponse.send(event, context, responseStatus, responseData)

            def add_notification(LambdaArn, Bucket):
                bucket_notification = s3.BucketNotification(Bucket)
                response = bucket_notification.put(
                  NotificationConfiguration={
                    'LambdaFunctionConfigurations': [
                      {
                          'LambdaFunctionArn': LambdaArn,
                          'Events': [
                              's3:ObjectCreated:*'
                          ]
                      }
                    ]
                  }
                )
                print("Put request completed....")
              
            def delete_notification(Bucket):
                bucket_notification = s3.BucketNotification(Bucket)
                response = bucket_notification.put(
                    NotificationConfiguration={}
                )
                print("Delete request completed....")
      Runtime: python3.6
      Timeout: 50

  LambdaTrigger:
    Type: 'Custom::LambdaTrigger'
    DependsOn: LambdaInvokePermission
    Properties:
      ServiceToken: !GetAtt CustomResourceLambdaFunction.Arn
      LambdaArn: !GetAtt S3NotificationLambdaFunction.Arn
      Bucket: !Ref NotificationBucket

2.    要使用 LambdaS3.template 文件启动 CloudFormation 堆栈,请使用 CloudFormation 控制台或以下 AWS CLI 命令:

aws cloudformation create-stack --stack-name lambda-s3-notification --template-body file://LambdaS3.template --parameters ParameterKey=NotificationBucket,ParameterValue=existing-bucket-for-lambda-notification --capabilities CAPABILITY_NAMED_IAM --region us-east-1

重要提示:当您启动 CloudFormation 堆栈时,必须传递您的 S3 存储桶信息。例如:existing-bucket-for-lambda-notification

该堆栈将为 Amazon S3 创建 Lambda 函数和 Lambda 权限。现在,您可以使用 S3 存储桶来处理 Lambda 通知,因为该堆栈已在您的 S3 存储桶中添加了所需的通知配置。


这篇文章对您有帮助吗?


您是否需要账单或技术支持?