Quero usar um bucket existente do Amazon Simple Storage Service (Amazon S3) para criar uma configuração de notificação do Amazon S3 para uma função do AWS Lambda.
Breve descrição
Para criar uma configuração de notificação do Amazon S3, use o CloudFormation para criar um novo bucket do S3. Em seguida, adicione uma configuração de notificação a esse bucket usando a propriedade NotificationConfiguration. Ou adicione manualmente uma configuração de notificação a um bucket S3 existente.
As etapas a seguir mostram como adicionar uma configuração de notificação ao seu bucket S3 existente com o CloudFormation. Para fazer isso, crie um recurso personalizado baseado em Lambda no Python 3.9. O recurso personalizado inicia uma função do Lambda que inicia a API PutBucketNotification para adicionar uma configuração de notificação ao seu bucket do S3.
Observação: se você receber erros ao executar comandos da AWS Command Line Interface (AWS CLI), verifique se está usando a versão mais recente.
Resolução
Importante: As etapas a seguir se aplicam somente às configurações de notificação do Amazon S3 para buckets do S3 que não têm configurações de notificação existentes. Se o seu bucket do S3 já tiver uma configuração de notificação existente ou criada manualmente, as etapas a seguir substituirão essas configurações. Depois de excluir sua pilha, o Amazon S3 remove todas as notificações. Se sua solução parecer funcionar, talvez haja configurações abaixo do ideal em seu caso de uso. É uma prática recomendada testar sua solução em um bucket de teste do S3 antes de implantá-la em um ambiente de produção.
1. Crie um modelo do CloudFormation chamado LambdaS3.template que inclua o seguinte código:
Importante: No exemplo a seguir, você adiciona a configuração de notificação do S3 ao recurso S3NotificationLambdaFunction. Você usa a função do Lambda CustomResourceLambdaFunction para adicionar a configuração de notificação do S3 para S3NotificationLambdaFunction. Para atender aos seus requisitos, é possível modificar o código no recurso 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. Para iniciar uma pilha do CloudFormation com o arquivo LambdaS3.template, use o console do CloudFormation ou o seguinte comando da 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
Importante: Ao iniciar sua pilha do CloudFormation, você precisa passar seu bucket do S3. Por exemplo, execute existing-bucket-for-lambda-notification.
A pilha cria uma função do Lambda e permissões do Lambda para o Amazon S3. Como a pilha adicionou a configuração de notificação necessária ao seu bucket do S3, agora você pode usar seu bucket do S3 para notificações do Lambda.