概要
CloudFormationが標準でサポートしていないリソースや処理を、Lambda関数やSNSトピックを使って実装する仕組み
出典: Create custom provisioning logic with custom resources - AWS CloudFormation
Custom resources in AWS CloudFormation allow users to write custom provisioning logic into CloudFormation templates and manage related resources in a single stack.
ユースケース
- CloudFormationが未対応のAWSリソースの作成
- 外部APIの呼び出し
- 動的な値の計算・取得
- 既存リソースの情報取得
処理フロー
CloudFormation Lambda S3 (CFn専用バケット)
| | |
|-- 1. Lambda呼び出し -------->| |
| イベントJSON送信 | |
| - RequestType: Create | |
| - ResponseURL: | |
| https://cloudformation-custom-resource-response-<region>.s3-<region>.amazonaws.com/...
| ↑ S3の署名付きURL |
| - ResourceProperties: ... | |
| | |
| ※非同期呼び出しのため |-- 2. 処理実行 |
| 戻り値は受け取れない | |
| | |
| |-- 3. HTTP PUT ------------->|
| | ResponseURL(=S3)に対して |
| | 結果JSONを送信 |
| | - Status: SUCCESS |
| | - Data: {計算結果} |
| | |
|<-- 4. ポーリングで読み取り ----------------------------- --|
| S3に保存されたJSONを取得 |
| |
|-- 5. スタック操作続行 |
| Status=SUCCESSなら次へ |
| Status=FAILEDならロールバック |
なぜS3を経由するのか
CloudFormationはLambda関数を非同期で呼び出すため、Lambda関数の戻り値を直接受け取ることができない
出典: Using AWS Lambda with CloudFormation
CloudFormation invokes the Lambda function asynchronously with an event that includes a callback URL. The function is responsible for returning a response to the callback URL indicating success or failure.
この制約を解決するため、CloudFormationはResponseURL(S3の署名付きURL)をイベントに含めてLambda関数に渡す
Lambda関数は処理完了後、このURLにHTTP PUTで結果JSONを送信する
実際にはS3バケットにJSONファイルがアップロードされ、CloudFormationがそれを読み取る
S3バケット
レスポンス送信先のS3バケットはCloudFormationが各リージョンに用意しており、ユーザーが作成する必要はない
出典: Access CloudFormation using an interface endpoint (AWS PrivateLink)
CloudFormation has S3 buckets in each Region to monitor responses to a custom resource request
バケット名の形式は cloudformation-custom-resource-response-<region>(リージョン名からハイフンが除去される)
このバケットはCloudFormation専用のため、ユーザーが直接アクセスして中身を確認することはできない
署名付きURL
CloudFormationがLambda関数に渡すイベントに含まれる。署名付きURLには認証情報が埋め込まれているため、Lambda関数はIAM権限なしでS3にPUTできる
構造:
| 部分 | 意味 |
|---|---|
| ホスト | CloudFormation専用S3バケット |
| パス | スタックID、リソースID、リクエストIDを組み合わせたオブジェクトキー |
| X-Amz-Expires | 署名の有効期限(秒)。7200秒 = 2時間 |
| X-Amz-Signature | 署名。この署名があることでPUT操作が許可される |
出典: CloudFormation custom resource request and response reference
The response URL identifies a presigned S3 bucket that receives responses from the custom resource provider to CloudFormation.
リクエストオブジェクト
CloudFormationからLambda関数に送信されるJSONの構造
| フィールド | 説明 |
|---|---|
| RequestType | Create, Update, Deleteのいずれか |
| ResponseURL | レスポンス送信先の署名付きURL(S3) |
| StackId | スタックのARN |
| RequestId | リクエストの一意識別子 |
| ResourceProperties | テンプレートで定義したプロパティ |
レスポンスオブジェクト
Lambda関数が署名付きURLにHTTP PUTで送信するJSON
| フィールド | 説明 |
|---|---|
| Status | SUCCESSまたはFAILED。CloudFormationはこの値でスタック操作を続行するかロールバックするかを決定する |
| PhysicalResourceId | リソースの物理ID。更新時にこの値が変わるとCloudFormationはリソース置換と判断し、古いリソースの削除を試みる |
| Data | Fn::GetAttで取得可能な値。他のリソースに渡すデータをここに格納する |
出典: CloudFormation custom resource request and response reference
The custom resource provider sends a response to the pre-signed URL for all request types. If the custom resource provider doesn’t send a response, CloudFormation waits until the operation times out.
cfn-responseモジュール
Lambda関数のコードをZipFileプロパティで記述する場合、cfn-responseモジュールが自動的に利用可能になる。このモジュールは署名付きURLへのHTTP PUT送信を内部で行ってくれる
出典: cfn-response module - AWS CloudFormation
The cfn-response module is a library that simplifies sending responses to the custom resource that invoked your Lambda function.
cfn-responseを使わない場合は、urllib.request等でResponseURLにHTTP PUTを送信する必要がある
署名付きURLには認証情報が埋め込まれているため、Lambda関数のIAMロールにS3への書き込み権限は不要
タイムアウト
カスタムリソースのデフォルトタイムアウトは3600秒(1時間)。Lambda関数がレスポンスを返さない場合、CloudFormationはこの時間待機し続ける
出典: AWS::CloudFormation::CustomResource
The ServiceTimeout property sets the maximum time, in seconds, that can elapse before a custom resource operation times out. The default value is 1 hour (3600 seconds).
Lambda関数内でエラーが発生した場合でも、必ずレスポンスを返すようにエラーハンドリングを実装する必要がある
参考資料
- Create custom provisioning logic with custom resources
- CloudFormation custom resource request and response reference
- cfn-response module