Enable Lambda function to an S3 bucket using cloudformation

后端 未结 5 637
醉话见心
醉话见心 2021-01-30 13:46

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.

相关标签:
5条回答
  • 2021-01-30 14:17

    It is clearly stated in AWS docs that AWS::S3::Bucket is used to create a resource, If we have a bucket that exists already we can not modify it to add NotificationConfiguration. So S3 bucket must not exist for above template to work. Let CloudFormation creates all resources including S3 bucket.

    0 讨论(0)
  • 2021-01-30 14:18

    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
    
    0 讨论(0)
  • 2021-01-30 14:29

    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"
                }
    }
    
    0 讨论(0)
  • 2021-01-30 14:36

    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

    0 讨论(0)
  • 2021-01-30 14:40

    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 NotificationConfiguration
        {
          "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>
    
    0 讨论(0)
提交回复
热议问题