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

上次更新时间:2020 年 7 月 8 日

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

简短描述

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

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

解决方法

重要提示:以下步骤仅适用于不具有任何现有通知配置的 S3 存储桶的 S3 通知配置。如果您的 S3 存储桶已有现有的或手动创建的通知配置,以下步骤将覆盖其配置。

1.    创建一个包含以下代码的名为 LambdaS3.template 的 AWS 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 = 'FAILURE'
                    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 文件启动 AWS CloudFormation 堆栈,请使用 AWS CloudFormation 控制台或以下 AWS 命令行界面 (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

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

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


这篇文章对您有帮助吗?


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