使用CloudFormation在S3存储桶中创建Lambda通知 [英] Create a Lambda notification in an S3 bucket with CloudFormation

查看:110
本文介绍了使用CloudFormation在S3存储桶中创建Lambda通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在CloudFormation模板中为Lambda函数创建S3触发器。 S3存储桶已经存在,并且正在创建Lambda函数。



 描述:将对象上传到S3存储桶,触发Lambda事件,将对象键作为堆栈输出返回。 
参数:
键:
说明:S3对象键
类型:字符串
默认值:test
正文:
说明:S3对象正文内容
类型:字符串
默认值:TEST CONTENT
BucketName:
描述:S3存储桶名称(必须已经存在)
类型:String
资源:
BucketConfiguration:
类型:自定义:: S3BucketConfiguration
DependsOn:
-BucketPermission
-NotificationBucketPolicy
属性:
ServiceToken:!GetAtt S3BucketConfiguration.Arn
存储桶:!Ref BucketName
NotificationConfiguration:
LambdaFunctionConfigurations:
-事件:['s3:ObjectCreated:*']
LambdaFunctionArn:!GetAtt BucketWatcher.Arn
S3BucketConfiguration:
类型:AWS :: Lambda :: Function
属性:
描述:S3对象自定义资源
处理程序:index.handler
作用:!GetAtt LambdaEx ecutionRole.Arn
代码:
ZipFile:!Sub |
var response = require(‘cfn-response’);
var AWS = require('aws-sdk');
var s3 =新的AWS.S3();
exports.handler =函数(事件,上下文){
var response =(e)=> response.send(event,context,e?response.FAILED:response.SUCCESS,e?e:{});
process.on('uncaughtException',e => failed(e));
var params = event.ResourceProperties;
delete params.ServiceToken;
if(event.RequestType ===删除){
params.NotificationConfiguration = {};
s3.putBucketNotificationConfiguration(params).promise()
.then((data)=> respond())
.catch((e)=> respond());
}否则{
s3.putBucketNotificationConfiguration(params).promise()
.then((data)=> respond())
.catch((e)=> ; respond(e));
}
};
超时:30
运行时:nodejs4.3
BucketPermission:
类型:AWS :: Lambda :: Permission
属性:
操作:'lambda: InvokeFunction'
FunctionName:!Ref BucketWatcher
主体:s3.amazonaws.com
SourceAccount:!Ref AWS :: AccountId
SourceArn:!Sub arn:aws:s3 ::: $ {BucketName}
BucketWatcher:
类型:AWS :: Lambda :: Function
属性:
说明:调用$ b时向处理发送一个等待条件信号$ b处理程序:index.handler
角色:!GetAtt LambdaExecutionRole.Arn
代码:
ZipFile:!Sub |
exports.handler =函数(事件,上下文){
console.log(收到请求:\n,JSON.stringify(event));
var responseBody = JSON.stringify({
Status: SUCCESS,
UniqueId: Key,
Data:event.Records [0] .s3.object.key,
原因:
});
var https = require( https);
var url = require( url);
var parsedUrl = url.parse(’$ {Handle}’);
var选项= {
主机名:parsedUrl.hostname,
端口:443,
路径:parsedUrl.path,
方法: PUT,
标头:{
content-type:,
content-length:responseBody.length
}
};
var request = https.request(options,function(response){
console.log(状态代码: + response.statusCode);
console.log(状态消息: + response.statusMessage);
context.done();
});
request.on(错误,函数(错误){
console.log( send(..)执行https.request(..)失败: +错误);
context.done();
});
request.write(responseBody);
request.end();
};
超时:30
运行时:nodejs4.3
处理:
类型:AWS :: CloudFormation :: WaitConditionHandle
等待:
类型:AWS :: CloudFormation :: WaitCondition
属性:
句柄:!Ref句柄
超时:300
S3Object:
类型:Custom :: S3Object
DependsOn:BucketConfiguration
属性:
ServiceToken:!GetAtt S3ObjectFunction.Arn
存储桶:!Ref BucketName
键:!Ref键
主体:!Ref主体
S3ObjectFunction:
类型:AWS :: Lambda :: Function
属性:
说明:S3对象自定义资源
处理程序:index.handler
角色:!GetAtt LambdaExecutionRole.Arn
代码:
ZipFile:!Sub |
var response = require(‘cfn-response’);
var AWS = require('aws-sdk');
var s3 =新的AWS.S3();
exports.handler =函数(事件,上下文){
var response =(e)=> response.send(event,context,e?response.FAILED:response.SUCCESS,e?e:{});
var params = event.ResourceProperties;
delete params.ServiceToken;
if(event.RequestType =='创建'|| event.RequestType =='更新'){
s3.putObject(params).promise()
.then((data) => respond())
.catch((e)=> respond(e));
}否则,如果(event.RequestType ==‘Delete’){
delete params.Body;
s3.deleteObject(params).promise()
.then((data)=> respond())
.catch((e)=> respond(e));
}否则{
响应({错误:无效的请求类型}));
}
};
超时:30
运行时:nodejs4.3
LambdaExecutionRole:
类型:AWS :: IAM :: Role
属性:
AssumeRolePolicyDocument:
版本: 2012-10-17
声明:
-效果:允许
委托人:{服务:[lambda.amazonaws.com]} ​​
操作:['sts :AssumeRole']
路径:/
ManagedPolicyArns:
- arn:aws:iam :: aws:policy / service-role / AWSLambdaBasicExecutionRole
政策:
-PolicyName:S3Policy
PolicyDocument:
版本:'2012-10-17'
声明:
-作用:允许
操作:
-'s3 :PutObject'
-'S3:DeleteObject'
资源:!Sub arn:aws:s3 ::: $$ {BucketName} / $ {Key}
NotificationBucketPolicy:
类型:AWS :: S3 :: BucketPolicy
属性:
存储桶:!Ref BucketName
PolicyDocument:
语句:
-效果:允许
动作:
-'s3:PutBucketNotification'
资源:!Sub arn:aws:s3 ::: $ {BucketName}
委托人:
AWS:!GetAtt LambdaExecutionRole.Arn
输出:
结果:
值:!GetAtt Wait.Data


I'm trying to create an S3 trigger for a Lambda function in a CloudFormation Template. The S3 bucket already exists, and the Lambda function is being created.

This says it's not possible to modify pre-existing infrastructure (S3 in this case) with a CFT, but this seems to say that the bucket has to be pre-existing.

  1. It seems that the trigger can't be created using a CFT type "AWS::Lambda..." and that the source service needs to create the trigger. In my case, that's a NotificationConfiguration-LambdaConfiguration for an s3 bucket. Is all of that correct?

  2. When I try to add a NotificationConfiguration to an existing S3 bucket with a CFT, it says that I can't. Is there any way to do this?

解决方案

Unfortunately, the official AWS::CloudFormation template only allows you to control Amazon S3 NotificationConfiguration as a NotificationConfiguration property of the parent AWS::S3::Bucket Resource, which means that you can't attach this configuration to any existing bucket, you have to apply it to a CloudFormation-managed bucket for it to work.

A workaround is to implement the PUT Bucket Notification API call directly as a Lambda-backed Custom Resource using the putBucketNotificationConfiguration JavaScript API call. However, because modifying the NotificationConfiguration on S3 buckets is restricted to the bucket's creator, you also need to add an AWS::S3::BucketPolicy Resource granting your Lambda Function access to the s3:PutBucketNotification action.

Here's a complete, self-contained CloudFormation template that demonstrates how to trigger a Lambda function whenever a file is added to an existing S3 bucket, using 2 Lambda-Backed Custom Resources (BucketConfiguration to set the bucket notification configuration, S3Object to upload an object to the bucket) and a third Lambda function (BucketWatcher to trigger the Wait Condition when an object is uploaded to the 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 (must already exist)
    Type: String
Resources:
  BucketConfiguration:
    Type: Custom::S3BucketConfiguration
    DependsOn:
    - BucketPermission
    - NotificationBucketPolicy
    Properties:
      ServiceToken: !GetAtt S3BucketConfiguration.Arn
      Bucket: !Ref BucketName
      NotificationConfiguration:
        LambdaFunctionConfigurations:
        - Events: ['s3:ObjectCreated:*']
          LambdaFunctionArn: !GetAtt BucketWatcher.Arn
  S3BucketConfiguration:
    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) {
            var respond = (e) => response.send(event, context, e ? response.FAILED : response.SUCCESS, e ? e : {});
            process.on('uncaughtException', e=>failed(e));
            var params = event.ResourceProperties;
            delete params.ServiceToken;
            if (event.RequestType === 'Delete') {
              params.NotificationConfiguration = {};
              s3.putBucketNotificationConfiguration(params).promise()
                .then((data)=>respond())
                .catch((e)=>respond());
            } else {
              s3.putBucketNotificationConfiguration(params).promise()
                .then((data)=>respond())
                .catch((e)=>respond(e));
            }
          };
      Timeout: 30
      Runtime: nodejs4.3
  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
    DependsOn: BucketConfiguration
    Properties:
      ServiceToken: !GetAtt S3ObjectFunction.Arn
      Bucket: !Ref BucketName
      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) {
            var respond = (e) => response.send(event, context, e ? response.FAILED : response.SUCCESS, e ? e : {});
            var params = event.ResourceProperties;
            delete params.ServiceToken;
            if (event.RequestType == 'Create' || event.RequestType == 'Update') {
              s3.putObject(params).promise()
                .then((data)=>respond())
                .catch((e)=>respond(e));
            } else if (event.RequestType == 'Delete') {
              delete params.Body;
              s3.deleteObject(params).promise()
                .then((data)=>respond())
                .catch((e)=>respond(e));
            } else {
              respond({Error: 'Invalid request type'});
            }
          };
      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}"
  NotificationBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref BucketName
      PolicyDocument:
        Statement:
          - Effect: "Allow"
            Action:
            - 's3:PutBucketNotification'
            Resource: !Sub "arn:aws:s3:::${BucketName}"
            Principal:
              AWS: !GetAtt LambdaExecutionRole.Arn
Outputs:
  Result:
    Value: !GetAtt Wait.Data

这篇关于使用CloudFormation在S3存储桶中创建Lambda通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆