簡體   English   中英

使用 cloudformation 為 S3 存儲桶啟用 Lambda 函數

[英]Enable Lambda function to an S3 bucket using cloudformation

我們正在使用 CloudFormation 模板創建一個 S3 存儲桶。 每當將文件添加到 S3 存儲桶時,我都想關聯(將事件添加到 S3 存儲桶)一個 Lambda 函數。

怎么可能通過 CloudFormation 模板。 CloudFormation 中需要使用哪些屬性。

這是一個完整的、自包含的 CloudFormation 模板,演示了在將文件添加到 S3 存儲桶時如何觸發 Lambda 函數:

啟動堆棧

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

您的 CloudFormation 模板中需要一個NotificationConfiguration屬性。 不幸的是,它似乎要求存儲桶已經存在。 為了解決這個問題,您可以創建一個初始堆棧,然后使用NotificationConfiguration更新它。 例如:

    // 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"}
                }
              ]
            }
          }
        }
      }
    }

您可以使用 AWS CLI 工具創建堆棧,如下所示:

    $ 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>

我在用於創建 S3 存儲桶的 cloudformation 中添加了存儲桶 perm 和通知配置。它起作用了!

"bucketperm": {
            "Type": "AWS::Lambda::Permission",
            "Properties": {
                "Action": "lambda:invokeFunction",
                "FunctionName": "<arnvalue>",
                "Principal": "s3.amazonaws.com"
            }
}

是的,可以通過 Cloudformation 實現,您需要配置的是:

1) AWS::S3::Bucket資源和,

2) 上面 s3 資源的NotificationConfiguration配置(在這種情況下使用LambdaConfigurations )。

您需要的相關文檔:

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

AWS 文檔中明確指出AWS::S3::Bucket用於創建資源,如果我們有一個已經存在的存儲桶,我們無法修改它以添加 NotificationConfiguration。 因此,必須不存在 S3 存儲桶才能使上述模板正常工作。 讓 CloudFormation 創建包括 S3 存儲桶在內的所有資源。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM