Включить лямбда-функцию в ведро S3 с использованием cloudformation

Мы создаем ведро S3 с использованием шаблона CloudFormation. Я хотел бы связать (добавить событие в ведро S3) функцию Lambda всякий раз, когда файл добавляется в ведро S3.

Как это возможно с помощью шаблонов CloudFormation. Каковы свойства, которые необходимо использовать в CloudFormation.

Ответ 1

Вот полный, автономный шаблон CloudFormation, который демонстрирует, как запускать лямбда-функцию всякий раз, когда файл добавляется в корзину S3:

Launch Stack

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

Вам нужно свойство NotificationConfiguration в вашем шаблоне CloudFormation. К сожалению, кажется, что ведро уже существует. Чтобы обойти это, вы можете создать начальный стек, а затем обновить его с помощью 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 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"}
            }
          ]
        }
      }
    }
  }
}

Вы можете использовать инструмент 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>

Ответ 3

Я добавил ниже ведро perm с конфигурацией уведомлений в облачной информации, которая используется для создания ведра S3.. он работает!!

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

Ответ 4

Да, это возможно благодаря Cloudformation, и что вам нужно настроить:

1) AWS::S3::Bucket ресурс и

2) NotificationConfiguration (используйте LambdaConfigurations в этом случае) для ресурса s3 выше.

Соответствующая документация, которая вам нужна:

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

Ответ 5

В документации AWS четко указано, что AWS :: S3 :: Bucket используется для создания ресурса. Если у нас уже есть область памяти, мы не можем изменить ее, добавив NotificationConfiguration. Таким образом, корзина S3 не должна существовать для работы вышеуказанного шаблона. Пусть CloudFormation создает все ресурсы, включая S3 Bucket.

Ответ 6

создать код ниже, и он работает с CloudFormation ###################################### ##################################### Запуск лямбда-функции всякий раз, когда происходит событие S3

  BucketName: !Sub '${EnvironmentNameShorthand}.product'
  NotificationConfiguration:
    LambdaConfigurations:
    - 
      Function: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:function name'
      Event: "s3:ObjectCreated:*"
      Filter:
        S3Key:
          Rules:
          - 
            Name: suffix
            Value: .json

LambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
  FunctionName: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:function name '
  Action: "lambda:InvokeFunction"
  Principal: "s3.amazonaws.com"
  SourceArn: !Sub 'arn:aws:s3:::${EnvironmentNameShorthand}.product'

Ответ 7

Я создал приведенный ниже код, и он работает с CloudFormation ##################################### ###################################### Запуск лямбда-функции всякий раз, когда происходит событие S3

Properties:
  BucketName: !Sub '${EnvironmentNameShorthand}.product'
  NotificationConfiguration:
    LambdaConfigurations:
    - 
      Function: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:function name'
      Event: "s3:ObjectCreated:*"
      Filter:
        S3Key:
          Rules:
          - 
            Name: suffix
            Value: .json

LambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
  FunctionName: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:function name '
  Action: "lambda:InvokeFunction"
  Principal: "s3.amazonaws.com"
  SourceArn: !Sub 'arn:aws:s3:::${EnvironmentNameShorthand}.product'