可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
We are creating an S3 bucket using a CloudFormation template. I would like to associate (Add an event to S3 bucket) a Lambda function whenever a file is added to the S3 bucket.
How is it possible through CloudFormation templates. What are the properties which needs to be used in CloudFormation.
回答1:
Here's a complete, self-contained CloudFormation template that demonstrates how to trigger a Lambda function whenever a file is added to an S3 bucket:

Description: Upload an object to an S3 bucket, triggering a Lambda event, returning the object key as a Stack Output. Parameters: Key: Description: S3 Object key Type: String Default: test Body: Description: S3 Object body content Type: String Default: TEST CONTENT BucketName: Description: S3 Bucket name Type: String Resources: Bucket: Type: AWS::S3::Bucket DependsOn: BucketPermission Properties: BucketName: !Ref BucketName NotificationConfiguration: LambdaConfigurations: - Event: 's3:ObjectCreated:*' Function: !GetAtt BucketWatcher.Arn BucketPermission: Type: AWS::Lambda::Permission Properties: Action: 'lambda:InvokeFunction' FunctionName: !Ref BucketWatcher Principal: s3.amazonaws.com SourceAccount: !Ref "AWS::AccountId" SourceArn: !Sub "arn:aws:s3:::${BucketName}" BucketWatcher: Type: AWS::Lambda::Function Properties: Description: Sends a Wait Condition signal to Handle when invoked Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: !Sub | exports.handler = function(event, context) { console.log("Request received:\n", JSON.stringify(event)); var responseBody = JSON.stringify({ "Status" : "SUCCESS", "UniqueId" : "Key", "Data" : event.Records[0].s3.object.key, "Reason" : "" }); var https = require("https"); var url = require("url"); var parsedUrl = url.parse('${Handle}'); var options = { hostname: parsedUrl.hostname, port: 443, path: parsedUrl.path, method: "PUT", headers: { "content-type": "", "content-length": responseBody.length } }; var request = https.request(options, function(response) { console.log("Status code: " + response.statusCode); console.log("Status message: " + response.statusMessage); context.done(); }); request.on("error", function(error) { console.log("send(..) failed executing https.request(..): " + error); context.done(); }); request.write(responseBody); request.end(); }; Timeout: 30 Runtime: nodejs4.3 Handle: Type: AWS::CloudFormation::WaitConditionHandle Wait: Type: AWS::CloudFormation::WaitCondition Properties: Handle: !Ref Handle Timeout: 300 S3Object: Type: Custom::S3Object Properties: ServiceToken: !GetAtt S3ObjectFunction.Arn Bucket: !Ref Bucket Key: !Ref Key Body: !Ref Body S3ObjectFunction: Type: AWS::Lambda::Function Properties: Description: S3 Object Custom Resource Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: !Sub | var response = require('cfn-response'); var AWS = require('aws-sdk'); var s3 = new AWS.S3(); exports.handler = function(event, context) { console.log("Request received:\n", JSON.stringify(event)); var responseData = {}; if (event.RequestType == 'Create') { var params = { Bucket: event.ResourceProperties.Bucket, Key: event.ResourceProperties.Key, Body: event.ResourceProperties.Body }; s3.putObject(params).promise().then(function(data) { response.send(event, context, response.SUCCESS, responseData); }).catch(function(err) { console.log(JSON.stringify(err)); response.send(event, context, response.FAILED, responseData); }); } else if (event.RequestType == 'Delete') { var deleteParams = { Bucket: event.ResourceProperties.Bucket, Key: event.ResourceProperties.Key }; s3.deleteObject(deleteParams).promise().then(function(data) { response.send(event, context, response.SUCCESS, responseData); }).catch(function(err) { console.log(JSON.stringify(err)); response.send(event, context, response.FAILED, responseData); }); } else { response.send(event, context, response.SUCCESS, responseData); } }; Timeout: 30 Runtime: nodejs4.3 LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: {Service: [lambda.amazonaws.com]} Action: ['sts:AssumeRole'] Path: / ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" Policies: - PolicyName: S3Policy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 's3:PutObject' - 'S3:DeleteObject' Resource: !Sub "arn:aws:s3:::${BucketName}/${Key}" Outputs: Result: Value: !GetAtt Wait.Data
回答2:
You need a NotificationConfiguration property in your CloudFormation template. Unfortunately, it seems to require the bucket to already exist. To get around this, you can create an initial stack, then update it with the NotificationConfiguration. For example:
// template1.json { "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "mylambda": { "Type": "String" } }, "Resources": { "bucketperm": { "Type": "AWS::Lambda::Permission", "Properties" : { "Action": "lambda:InvokeFunction", "FunctionName": {"Ref": "mylambda"}, "Principal": "s3.amazonaws.com", "SourceAccount": {"Ref": "AWS::AccountId"}, "SourceArn": { "Fn::Join": [":", [ "arn", "aws", "s3", "" , "", {"Ref" : "mybucket"}]] } } }, "mybucket": { "Type": "AWS::S3::Bucket" } } } // template2.json -- adds the ConfigurationNotification { "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "mylambda": { "Type": "String" } }, "Resources": { "bucketperm": { "Type": "AWS::Lambda::Permission", "Properties" : { "Action": "lambda:InvokeFunction", "FunctionName": {"Ref": "mylambda"}, "Principal": "s3.amazonaws.com", "SourceAccount": {"Ref": "AWS::AccountId"}, "SourceArn": { "Fn::Join": [":", [ "arn", "aws", "s3", "" , "", {"Ref" : "mybucket"}]] } } }, "mybucket": { "Type": "AWS::S3::Bucket", "Properties": { "NotificationConfiguration": { "LambdaConfigurations": [ { "Event" : "s3:ObjectCreated:*", "Function" : {"Ref": "mylambda"} } ] } } } } }
You can use the aws CLI tool to create the stack like this:
$ aws cloudformation create-stack --stack-name mystack --template-body file://template1.json --parameters ParameterKey=mylambda,ParameterValue=<lambda arn> # wait until stack is created $ aws cloudformation update-stack --stack-name mystack --template-body file://template2.json --parameters ParameterKey=mylambda,ParameterValue=<lambda arn>
回答3:
i have added below bucket perm along with notificationconfiguration in cloudformation which is used to create S3 bucket..it worked !!
"bucketperm": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:invokeFunction", "FunctionName": "<arnvalue>", "Principal": "s3.amazonaws.com" } }
回答4:
Yes, it's possible through Cloudformation, and what you need to configure are:
1) AWS::S3::Bucket
resource and,
2) NotificationConfiguration
configuration (use LambdaConfigurations
in this case) for the s3 resource above.
Related documentation that you need:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-notification
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-notificationconfig.html