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

3 分钟阅读
0

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

简短描述

要创建 Amazon S3 通知配置,请使用 CloudFormation 创建新的 S3 存储桶。然后,使用通知配置属性,向该存储桶添加通知配置。或手动向现有 S3 存储桶添加通知配置

以下步骤向您展示如何使用 CloudFormation 向现有 S3 存储桶添加通知配置。为此,请在 Python 3.9 中创建一个由 Lambda 支持的自定义资源自定义资源会启动 Lambda 函数,该函数启动 PutBucketNotification API,向您的 S3 存储桶添加通知配置。

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

解决方法

**重要信息:**以下步骤仅适用于没有通知配置的 S3 存储桶的 Amazon S3 通知配置。如果您的 S3 存储桶已经有现有或手动创建的通知配置,则以下步骤会覆盖这些配置。删除堆栈后,Amazon S3 会删除所有通知。如果您的解决方案似乎可行,则表明您的用例中可能存在次优配置。最佳做法是先在测试 S3 存储桶上测试解决方案,然后再将其部署到生产环境。

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

**重要信息:**在以下示例中,将 S3 通知配置添加到 S3NotificationLambdaFunction 资源。您可以使用 Lambda 函数 CustomResourceLambdaFunction 将 S3 通知配置添加到 S3NotificationLambdaFunction。为了满足您的要求,您可以修改 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.9
      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, "CustomResourcePhysicalID")

            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.9
      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 存储桶添加了所需的通知配置,因此您现在可以使用 S3 存储桶创建 Lambda 通知配置。

AWS 官方
AWS 官方已更新 10 个月前