2016-08-03 8 views
7

CloudFormationテンプレートでラムダ関数のS3トリガを作成しようとしています。 S3バケットは既に存在し、ラムダ関数が作成されています。CloudFormationでS3バケットにラムダ通知を作成

Thisは、既存のインフラストラクチャ(この場合はS3)をCFTで変更することはできませんが、thisはバケットがあらかじめ存在していなければならないと言います。

  1. 「... AWS ::ラムダ」トリガがCFTタイプを使用して作成することができないようだと、ソース・サービスは、トリガーを作成する必要があること。私の場合、それはs3バケットのNotificationConfiguration-LambdaConfigurationです。すべて正しいのですか?

  2. CFTで既存のS3バケットにNotificationConfigurationを追加しようとすると、私はできないと言います。これを行う方法はありますか?

+0

私はバケットが存在している必要がありながら、それはテンプレートの作成前に存在している必要はないことをかなり確信しています。同じテンプレート内の通知設定とラムダ関数と一緒にバケットを作成すると、ユースケースに合っていますか?もしそうなら、この方法は既存のインフラストラクチャを変更するよりずっと簡単に手助けすることができます。いずれにしても解決策はありますが、それははるかにきれいです –

+0

「S3バケットは既に存在します」と言うと、バケットがCloudFormation外で作成されたことを意味していますか? – Aditya

答えて

4

残念ながら、公式AWS::CloudFormationテンプレートは唯一、あなたが任意の既存のバケットにこの構成を添付できないことを意味し、親AWS::S3::BucketリソースのNotificationConfiguration propertyとしてAmazon S3 NotificationConfigurationを制御することができます、あなたはそれを適用する必要がありそれが動作するためのCloudFormation管理のバケット

putBucketNotificationConfiguration JavaScript API呼び出しを使用して、として直接PUT Bucket Notification API呼び出しを実装することで回避できます。ただし、S3バケットのNotificationConfigurationの変更はバケットの作成者に制限されているため、s3:PutBucketNotificationアクションへのラムダファンクションアクセスを許可するリソースをAWS::S3::BucketPolicyリソースに追加する必要があります。

ここでは、ファイルはバケット通知設定を設定する(BucketConfigurationを2ラムダ担保カスタムリソースを使用して、既存 S3バケットに追加されるたびにラムダ関数をトリガする方法を示し、完全な、自己完結型のCloudFormationテンプレートですオブジェクトをバケットにアップロードするためのS3Object)と、オブジェクトがバケットにアップロードされたときの待機条件をトリガーするための第3のラムダ関数(BucketWatcher)があります。

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 (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 
関連する問題