cfn-response モジュール - AWS CloudFormation

cfn-response モジュール

ZipFile プロパティを使用して 関数の ソースコードを指定し、その関数が AWS CloudFormation カスタムリソースと通信する場合、cfn-response モジュールをロードしてこれらのリソースに応答を送信できます。このモジュールには send メソッドが含まれています。このメソッドは、Amazon S3 の署名付き URL (ResponseURL) を経由して、カスタムリソースに応答オブジェクトを送信します。

send メソッドを実行した後、Lambda 関数は終了するため、メソッドの後の記述は無視されます。

注記

cfn-response モジュールは、ZipFile プロパティを使用してソースコードを作成した場合にのみ使用できます。Amazon S3 バケットに保存されたソースコードには使用できません。バケットのコードでは、独自の関数を作成してレスポンスを送信する必要があります。

cfn-response モジュールの読み込み

Node.js 関数の場合は、require() 関数を使用して cfn-response モジュールをロードします。たとえば、次のコードでは、cfn-response という名前で response オブジェクトを作成しています。

var response = require('cfn-response');

Python の場合は、次の例に示すように、import ステートメントを使用して cfnresponse モジュールをロードします。

注記

この完全インポートステートメントを使用します。インポートステートメントの他の形式では、AWS CloudFormation では応答モジュールが含まれません。

import cfnresponse

send メソッドのパラメータ

send メソッドで次のパラメータを使用できます。

event

カスタムリソースのリクエストに含まれるフィールド。

context

関数および任意のコールバックが実行完了したとき、または Lambda 実行環境内からの情報にアクセスするときに指定できる Lambda 関数固有のオブジェクト。詳細については、『AWS Lambda Developer Guide』の「プログラミングモデル (Node.js)」を参照してください。

responseStatus

関数が正常に完了したかどうか。このステータスを指定するには、cfnresponse モジュール定数を使用します。成功に実行した場合は SUCCESS、失敗した場合は FAILED を指定します。

responseData

カスタムリソースの応答オブジェクトData フィールド。データの内容は、名前と値のペアのリストです。

physicalResourceId

オプション。関数を呼び出したカスタムリソースの一意の識別子。モジュールのデフォルトでは、Lambda 関数に関連付けられている Amazon CloudWatch Logs ログストリームの名前が使用されます。

noEcho

オプション。Fn::GetAtt 関数を使用してカスタムリソースの出力を取得したときに、それをマスクするかどうかを示します。true に設定すると、返される値はすべてアスタリスク (*****) でマスクされます。ただし、以下に指定した場所に保存されている情報は除きます。デフォルトでは、この値は false です。

重要

NoEcho 属性を使用しても、以下に保存されている情報はマスクされません。

  • Metadata テンプレートセクション。CloudFormation は、Metadata セクションに含める情報の変換、変更、または編集を行いません。詳細については、「メタデータ」を参照してください。

  • Outputs テンプレートセクション。詳細については、「出力」を参照してください。

  • リソース定義の Metadata 属性。詳細については、「メタデータ属性」を参照してください。

パスワードやシークレットなどの機密情報を含めるには、これらのメカニズムを使用しないことを強くお勧めします。

NoEcho を使用して機密情報をマスクする方法の詳細については、「テンプレートに認証情報を埋め込まない」ベストプラクティスを参照してください。

Node.js

次の Node.js の例では、インラインの Lambda 関数で入力値を受け取り、その値に 5 を乗算しています。インライン関数は、パッケージを作成して Amazon S3 バケットにアップロードするのではなく、ソースコードをテンプレート内で直接指定できるため、小さな関数の場合は特に便利です。この関数では、cfn-responsesend メソッドを使用して、呼び出たカスタムリソースに結果を返しています。

JSON

"ZipFile": { "Fn::Join": ["", [ "var response = require('cfn-response');", "exports.handler = function(event, context) {", " var input = parseInt(event.ResourceProperties.Input);", " var responseData = {Value: input * 5};", " response.send(event, context, response.SUCCESS, responseData);", "};" ]]}

YAML

ZipFile: > var response = require('cfn-response'); exports.handler = function(event, context) { var input = parseInt(event.ResourceProperties.Input); var responseData = {Value: input * 5}; response.send(event, context, response.SUCCESS, responseData); };

Python

次の Python の例では、インラインの Lambda 関数で整数値を受け取り、その値に 5 を乗算しています。

JSON

"ZipFile" : { "Fn::Join" : ["\n", [ "import json", "import cfnresponse", "def handler(event, context):", " responseValue = int(event['ResourceProperties']['Input']) * 5", " responseData = {}", " responseData['Data'] = responseValue", " cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, \"CustomResourcePhysicalID\")" ]]}

YAML

ZipFile: | import json import cfnresponse def handler(event, context): responseValue = int(event['ResourceProperties']['Input']) * 5 responseData = {} responseData['Data'] = responseValue cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")

モジュールのソースコード

Node.js 関数のレスポンスモジュールのソースコードは次のとおりです。これを確認してモジュールの動作を理解し、独自の応答関数の実装に役立ててください。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT-0 exports.SUCCESS = "SUCCESS"; exports.FAILED = "FAILED"; exports.send = function(event, context, responseStatus, responseData, physicalResourceId, noEcho) { var responseBody = JSON.stringify({ Status: responseStatus, Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName, PhysicalResourceId: physicalResourceId || context.logStreamName, StackId: event.StackId, RequestId: event.RequestId, LogicalResourceId: event.LogicalResourceId, NoEcho: noEcho || false, Data: responseData }); console.log("Response body:\n", responseBody); var https = require("https"); var url = require("url"); var parsedUrl = url.parse(event.ResponseURL); 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(); }

Python 3 関数のレスポンスモジュールのソースコードは次のとおりです。

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 import urllib3 import json http = urllib3.PoolManager() SUCCESS = "SUCCESS" FAILED = "FAILED" def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False): responseUrl = event['ResponseURL'] print(responseUrl) responseBody = {} responseBody['Status'] = responseStatus responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name responseBody['StackId'] = event['StackId'] responseBody['RequestId'] = event['RequestId'] responseBody['LogicalResourceId'] = event['LogicalResourceId'] responseBody['NoEcho'] = noEcho responseBody['Data'] = responseData json_responseBody = json.dumps(responseBody) print("Response body:\n" + json_responseBody) headers = { 'content-type' : '', 'content-length' : str(len(json_responseBody)) } try: response = http.request('PUT',responseUrl,body=json_responseBody.encode('utf-8'),headers=headers) print("Status code: " + response.reason) except Exception as e: print("send(..) failed executing requests.put(..): " + str(e))

Python 2 関数のレスポンスモジュールのソースコードは次のとおりです。

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 import urllib2 import json SUCCESS = "SUCCESS" FAILED = "FAILED" def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False): responseUrl = event['ResponseURL'] print responseUrl responseBody = {} responseBody['Status'] = responseStatus responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name responseBody['StackId'] = event['StackId'] responseBody['RequestId'] = event['RequestId'] responseBody['LogicalResourceId'] = event['LogicalResourceId'] responseBody['NoEcho'] = noEcho responseBody['Data'] = responseData json_responseBody = json.dumps(responseBody) print "Response body:\n" + json_responseBody try: opener = urllib2.build_opener(urllib2.HTTPHandler) request = urllib2.Request(responseUrl, data=json_responseBody) request.add_header('Content-Type', '') request.add_header('Content-Length', str(len(json_responseBody))) request.get_method = lambda: 'PUT' response = urllib2.urlopen(request) print "Status code: " + str(response.getcode()) except Exception as e: print "send(..) failed executing urllib2.Request(..): " + str(e)