

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Lambda フックのリソースを評価する Lambda 関数を作成する
<a name="lambda-hooks-create-lambda-function"></a>

CloudFormation Lambda フックを使用すると、独自のカスタムコードに対して CloudFormation および AWS クラウドコントロール API オペレーションを評価できます。フックは、操作の進行をブロックしたり、発信者に警告を発行して操作の進行を許可したりできます。Lambda フックを作成するときに、次の CloudFormation オペレーションを傍受して評価するように設定できます。
+ リソースオペレーション
+ スタックオペレーション
+ 変更セットオペレーション

**Topics**
+ [

## Lambda フックの開発
](#lambda-hooks-create-lambda-function-develop)
+ [

## Lambda フックを使用したリソースオペレーションの評価
](#lambda-hooks-create-lambda-function-resource)
+ [

## Lambda フックを使用したスタックオペレーションの評価
](#lambda-hooks-create-lambda-function-stack)
+ [

## Lambda フックを使用した変更セットオペレーションの評価
](#lambda-hooks-create-lambda-function-change-set)

## Lambda フックの開発
<a name="lambda-hooks-create-lambda-function-develop"></a>

フックが Lambda を呼び出すと、Lambda が入力を評価するまで最大 30 秒待機します。Lambda は、フックが成功したか失敗したかを示す JSON レスポンスを返します。

**Topics**
+ [

### リクエスト入力
](#lambda-hooks-create-lambda-function-request-input)
+ [

### レスポンス入力
](#lambda-hooks-create-lambda-function-request-response)
+ [

### 例
](#lambda-hooks-create-lambda-function-request-example)

### リクエスト入力
<a name="lambda-hooks-create-lambda-function-request-input"></a>

Lambda 関数に渡される入力は、フックターゲットオペレーション (スタック、リソース、変更セットなど) によって異なります。

### レスポンス入力
<a name="lambda-hooks-create-lambda-function-request-response"></a>

リクエストが成功または失敗した場合にフックと通信するには、Lambda 関数が JSON レスポンスを返す必要があります。

以下は、フックが期待するレスポンスの形状の例です。

```
{ 
  "hookStatus": "SUCCESS" or "FAILED" or "IN_PROGRESS", 
  "errorCode": "NonCompliant" or "InternalFailure"
  "メッセージ": String, 
  "clientRequestToken": String,
  "callbackContext": None, 
  "callbackDelaySeconds": Integer,
  "annotations": [
    {
      "annotationName": String,
      "status": "PASSED" or "FAILED" or "SKIPPED",
      "statusMessage": String,
      "remediationMessage": String,
      "remediationLink": String,
      "severityLevel": "INFORMATIONAL" or "LOW" or "MEDIUM" or "HIGH" or "CRITICAL"
    }
  ]
}
```

hookStatus  <a name="lambda-hook-response-hookstatus"></a>
フックのステータス。これは必須のフィールドです。  
*有効な値*: (`SUCCESS` \$1 `FAILED` \$1 `IN_PROGRESS`)  
フックは 3 `IN_PROGRESS` 回返すことができます。結果が返されない場合、フックは失敗します。Lambda フックの場合、これは Lambda 関数を最大 3 回呼び出すことができることを意味します。

errorCode  <a name="lambda-hook-response-errorcode"></a>
オペレーションが評価されて無効であると判断された場合、またはフック内でエラーが発生し、評価が妨げられたかどうかを示します。フックが失敗した場合、このフィールドは必須です。  
*有効な値*: (`NonCompliant` \$1 `InternalFailure`)

メッセージ  <a name="lambda-hook-response-message"></a>
フックが成功または失敗した理由を示す発信者へのメッセージ。  
CloudFormation オペレーションを評価する場合、このフィールドは 4096 文字に切り捨てられます。  
Cloud Control API オペレーションを評価する場合、このフィールドは 1024 文字に切り捨てられます。

clientRequestToken  <a name="lambda-hook-response-clientrequesttoken"></a>
Hook リクエストへの入力として提供されたリクエストトークン。これは必須のフィールドです。

callbackContext  <a name="lambda-hook-response-callbackcontext"></a>
`hookStatus` が であることを示す`IN_PROGRESS`場合は、Lambda 関数が再呼び出されたときに入力として提供される追加のコンテキストを渡します。

callbackDelaySeconds  <a name="lambda-hook-response-callbackdelayseconds"></a>
フックがこのフックを再度呼び出すまで待機する時間。

annotations  <a name="lambda-hook-response-annotations"></a>
詳細と修復ガイダンスを提供する注釈オブジェクトの配列。    
annotationName  
注釈の識別子。  
ステータス  
フックの呼び出しステータス。これは、注釈が Guard ルールと同様の合格/不合格評価を持つロジックを表す場合に役立ちます。  
*有効な値*: (`PASSED` \$1 `FAILED` \$1 `SKIPPED`)  
statusMessage  
特定のステータスの説明。  
remediationMessage  
`FAILED` ステータスを修正するための提案。たとえば、リソースに暗号化がない場合、リソース設定に暗号化を追加する方法を記述できます。  
remediationLink  
追加の修復ガイダンスの HTTP URL。  
severityLevel  
このタイプの違反に関連する相対リスクを定義します。Hook 呼び出し結果に重要度レベルを割り当てる場合、意味のある重要度カテゴリを構築する方法の例として AWS Security Hub CSPM [重要度フレームワーク](https://docs.aws.amazon.com/securityhub/latest/userguide/asff-required-attributes.html#Severity)を参照できます。  
*有効な値*: (`INFORMATIONAL` \$1 `LOW` \$1 `MEDIUM` \$1 `HIGH` \$1 `CRITICAL`)

### 例
<a name="lambda-hooks-create-lambda-function-request-example"></a>

以下に、正常な応答の例を示します。

```
{ 
  "hookStatus": "SUCCESS",
  "message": "compliant",
  "clientRequestToken": "123avjdjk31"  
}
```

失敗したレスポンスの例を次に示します。

```
{ 
  "hookStatus": "FAILED",
  "errorCode": "NonCompliant",
  "message": "S3 Bucket Versioning must be enabled.",
  "clientRequestToken": "123avjdjk31"
 }
```

## Lambda フックを使用したリソースオペレーションの評価
<a name="lambda-hooks-create-lambda-function-resource"></a>

リソースを作成、更新、または削除するときはいつでも、リソースオペレーションと見なされます。例えば、新しいリソースを作成する CloudFormation スタックの更新を実行すると、リソースオペレーションが完了しました。Cloud Control API を使用してリソースを作成、更新、または削除すると、リソースオペレーションとも見なされます。フック設定で `RESOURCE`および `CLOUD_CONTROL`オペレーションをターゲットにするように CloudFormation Lambda フック`TargetOperations`を設定できます。

**注記**  
`delete` フックハンドラーは、Cloud Control API `delete-resource`または CloudFormation からオペレーショントリガーを使用してリソースが削除された場合にのみ呼び出されます`delete-stack`。

**Topics**
+ [

### Lambda Hook リソース入力構文
](#lambda-hooks-create-lambda-function-resource-input)
+ [

### Lambda Hook リソース変更入力の例
](#lambda-hooks-create-lambda-function-resource-example)
+ [

### リソースオペレーションの Lambda 関数の例
](#lambda-hooks-create-lambda-function-resource-example-function)

### Lambda Hook リソース入力構文
<a name="lambda-hooks-create-lambda-function-resource-input"></a>

Lambda がリソースオペレーションに対して呼び出されると、リソースプロパティ、提案されたプロパティ、およびフック呼び出しに関するコンテキストを含む JSON 入力を受け取ります。

JSON 入力の形状の例を次に示します。

```
{
    "awsAccountId": String,
    "stackId": String,
    "changeSetId": String,
    "hookTypeName": String,
    "hookTypeVersion": String,
    "hookModel": {
        "LambdaFunction": String
    },
    "actionInvocationPoint": "CREATE_PRE_PROVISION" or "UPDATE_PRE_PROVISION" or "DELETE_PRE_PROVISION"
    "requestData": {
        "targetName": String,
        "targetType": String,
        "targetLogicalId": String,
        "targetModel": {
            "resourceProperties": {...},
            "previousResourceProperties": {...}
        }
    },
    "requestContext": {
        "呼び出し": 1,
        "callbackContext": null
    }
}
```

`awsAccountId`  <a name="lambda-hook-resource-awsaccountid"></a>
評価対象のリソース AWS アカウント を含む の ID。

`stackId`  <a name="lambda-hook-resource-stackid"></a>
このオペレーションは CloudFormation スタックのスタック ID の一部です。発信者が Cloud Control API の場合、このフィールドは空です。

`changeSetId`  <a name="lambda-hook-resource-changesetid"></a>
フック呼び出しを開始した変更セットの ID。リソースの変更が Cloud Control API、、、`create-stack``update-stack`または `delete-stack`オペレーションによって開始された場合、この値は空です。

`hookTypeName`  <a name="lambda-hook-resource-hooktypename"></a>
実行中のフックの名前。

`hookTypeVersion`  <a name="lambda-hook-resource-hooktypeversion"></a>
実行中のフックのバージョン。

`hookModel`  <a name="lambda-hook-resource-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-resource-hookmodel-lambdafunction"></a>
フックによって呼び出される現在の Lambda ARN。

`actionInvocationPoint`  <a name="lambda-hook-resource-actioninvocationpoint"></a>
フックが実行されるプロビジョニングロジックの正確なポイント。  
*有効な値*: (`CREATE_PRE_PROVISION` \$1 `UPDATE_PRE_PROVISION` \$1 `DELETE_PRE_PROVISION`)

`requestData`  <a name="lambda-hook-resource-requestdata"></a>  
`targetName`  <a name="lambda-hook-resource-requestdata-targetname"></a>
評価されるターゲットタイプ。例: `AWS::S3::Bucket`。  
`targetType`  <a name="lambda-hook-resource-requestdata-targettype"></a>
評価対象のターゲットタイプ。例: `AWS::S3::Bucket`。Cloud Control API でプロビジョニングされたリソースの場合、この値は になります`RESOURCE`。  
`targetLogicalId`  <a name="lambda-hook-resource-requestdata-targetlogicalid"></a>
評価対象のリソースの論理 ID。フック呼び出しのオリジンが CloudFormation の場合、これは CloudFormation テンプレートで定義された論理リソース ID になります。このフック呼び出しのオリジンが Cloud Control API の場合、これは構築された値になります。  
`targetModel`  <a name="lambda-hook-resource-requestdata-targetmodel"></a>  
`resourceProperties`  <a name="lambda-hook-resource-requestdata-targetmodel-resourceproperties"></a>
変更するリソースの提案されたプロパティ。リソースが削除されている場合、この値は空になります。  
`previousResourceProperties`  <a name="lambda-hook-resource-requestdata-targetmodel-previousresourceproperties"></a>
変更中のリソースに現在関連付けられているプロパティ。リソースが作成されている場合、この値は空になります。

`requestContext`  <a name="lambda-hook-resource-requestcontext"></a>  
呼び出し  <a name="lambda-hook-resource-requestcontext-invocation"></a>
フックの現在の実行試行。  
callbackContext  <a name="lambda-hook-resource-requestcontext-callbackcontext"></a>
Hook が に設定され`IN_PROGRESS`、 `callbackContext`が返された場合、再呼び出し後にここに表示されます。

### Lambda Hook リソース変更入力の例
<a name="lambda-hooks-create-lambda-function-resource-example"></a>

次の入力例は、更新する`AWS::DynamoDB::Table`リソースの定義を受け取る Lambda フックを示しています。ここで、 `ReadCapacityUnits` の `ProvisionedThroughput`は 3 から 10 に変更されています。これは、Lambda が評価に使用できるデータです。

```
{
    "awsAccountId": "123456789012",
    "stackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "hookTypeName": "my::lambda::resourcehookfunction",
    "hookTypeVersion": "00000008",
    "hookModel": {
        "LambdaFunction": "arn:aws:lambda:us-west-2:123456789012:function:MyFunction"
    },
    "actionInvocationPoint": "UPDATE_PRE_PROVISION",
    "requestData": {
        "targetName": "AWS::DynamoDB::Table",
        "targetType": "AWS::DynamoDB::Table",
        "targetLogicalId": "DDBTable",
        "targetModel": {
            "resourceProperties": {
                "AttributeDefinitions": [
                    {
                        "AttributeType": "S",
                        "AttributeName": "Album"
                    },
                    {
                        "AttributeType": "S",
                        "AttributeName": "Artist"
                    }
                ],
                "ProvisionedThroughput": {
                    "WriteCapacityUnits": 5,
                    "ReadCapacityUnits": 10
                },
                "KeySchema": [
                    {
                        "KeyType": "HASH",
                        "AttributeName": "Album"
                    },
                    {
                        "KeyType": "RANGE",
                        "AttributeName": "Artist"
                    }
                ]
            },
            "previousResourceProperties": {
                "AttributeDefinitions": [
                    {
                        "AttributeType": "S",
                        "AttributeName": "Album"
                    },
                    {
                        "AttributeType": "S",
                        "AttributeName": "Artist"
                    }
                ],
                "ProvisionedThroughput": {
                    "WriteCapacityUnits": 5,
                    "ReadCapacityUnits": 5
                },
                "KeySchema": [
                    {
                        "KeyType": "HASH",
                        "AttributeName": "Album"
                    },
                    {
                        "KeyType": "RANGE",
                        "AttributeName": "Artist"
                    }
                ]
            }
        }
    },
    "requestContext": {
        "invocation": 1,
        "callbackContext": null
    }    
}
```

リソースタイプで使用できるすべてのプロパティを確認するには、「」を参照してください[https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-dynamodb-table.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-dynamodb-table.html)。

### リソースオペレーションの Lambda 関数の例
<a name="lambda-hooks-create-lambda-function-resource-example-function"></a>

以下は、DynamoDB へのリソース更新に失敗するシンプルな関数です。DynamoDB は、 `ReadCapacity` の `ProvisionedThroughput`を 10 より大きい値に設定しようとします。フックが成功すると、ReadCapacity が正しく設定されている」というメッセージが発信者に表示されます。リクエストの検証に失敗すると、フックはReadCapacity cannot be more than 10」というステータスで失敗します。

------
#### [ Node.js ]

```
export const handler = async (event, context) => {
    var targetModel = event?.requestData?.targetModel;
    var targetName = event?.requestData?.targetName;
    var response = {
        "hookStatus": "SUCCESS",
        "message": "ReadCapacity is correctly configured.",
        "clientRequestToken": event.clientRequestToken
    };

    if (targetName == "AWS::DynamoDB::Table") {
        var readCapacity = targetModel?.resourceProperties?.ProvisionedThroughput?.ReadCapacityUnits;
        if (readCapacity > 10) {
            response.hookStatus = "FAILED";
            response.errorCode = "NonCompliant";
            response.message = "ReadCapacity must be cannot be more than 10.";
        }
    }
    return response;
};
```

------
#### [ Python ]

```
import json
                            
def lambda_handler(event, context):
    # Using dict.get() for safe access to nested dictionary values
    request_data = event.get('requestData', {})
    target_model = request_data.get('targetModel', {})
    target_name = request_data.get('targetName', '')
    
    response = {
        "hookStatus": "SUCCESS",
        "message": "ReadCapacity is correctly configured.",
        "clientRequestToken": event.get('clientRequestToken')
    }
    
    if target_name == "AWS::DynamoDB::Table":
        # Safely navigate nested dictionary
        resource_properties = target_model.get('resourceProperties', {})
        provisioned_throughput = resource_properties.get('ProvisionedThroughput', {})
        read_capacity = provisioned_throughput.get('ReadCapacityUnits')
        
        if read_capacity and read_capacity > 10:
            response['hookStatus'] = "FAILED"
            response['errorCode'] = "NonCompliant"
            response['message'] = "ReadCapacity must be cannot be more than 10."
    
    return response
```

------

## Lambda フックを使用したスタックオペレーションの評価
<a name="lambda-hooks-create-lambda-function-stack"></a>

新しいテンプレートを使用してスタックを作成、更新、または削除するときはいつでも、新しいテンプレートを評価してスタックオペレーションの進行をブロックすることで、CloudFormation Lambda フックを開始できるように設定できます。フック設定で`STACK`オペレーションをターゲットにするように CloudFormation Lambda フック`TargetOperations`を設定できます。

**Topics**
+ [

### Lambda フックスタックの入力構文
](#lambda-hooks-create-lambda-function-stack-input)
+ [

### Lambda フックスタック変更入力の例
](#lambda-hooks-create-lambda-function-stack-example)
+ [

### スタックオペレーションの Lambda 関数の例
](#lambda-hooks-create-lambda-function-stack-example-function)

### Lambda フックスタックの入力構文
<a name="lambda-hooks-create-lambda-function-stack-input"></a>

スタックオペレーションで Lambda が呼び出されると、フック呼び出しコンテキスト、、`actionInvocationPoint`およびリクエストコンテキストを含む JSON リクエストを受け取ります。CloudFormation テンプレートのサイズと Lambda 関数で受け入れられる入力サイズが限られているため、実際のテンプレートは Amazon S3 オブジェクトに保存されます。の入力`requestData`には、現在および以前のテンプレートバージョンを含む別のオブジェクトへの Amazon S3 署名付き URL が含まれます。

JSON 入力の形状の例を次に示します。

```
{
    "clientRequesttoken": String,
    "awsAccountId": String,
    "stackID": String,
    "changeSetId": String,
    "hookTypeName": String,
    "hookTypeVersion": String,
    "hookModel": {
        "LambdaFunction":String
    },
    "actionInvocationPoint": "CREATE_PRE_PROVISION" or "UPDATE_PRE_PROVISION" or "DELETE_PRE_PROVISION"
    "requestData": {
        "targetName": "STACK",
        "targetType": "STACK",
        "targetLogicalId": String,
        "payload": String (S3 Presigned URL)
    },
    "requestContext": {
        "invocation": Integer,
        "callbackContext": String
    }
}
```

`clientRequesttoken`  <a name="lambda-hook-stack-clientrequesttoken"></a>
Hook リクエストへの入力として提供されたリクエストトークン。これは必須のフィールドです。

`awsAccountId`  <a name="lambda-hook-stack-awsaccountid"></a>
評価対象のスタック AWS アカウント を含む の ID。

`stackID`  <a name="lambda-hook-stack-stackid"></a>
CloudFormation スタックのスタック ID。

`changeSetId`  <a name="lambda-hook-stack-changesetid"></a>
フック呼び出しを開始した変更セットの ID。スタックの変更が Cloud Control API、、、`create-stack``update-stack`または `delete-stack`オペレーションによって開始された場合、この値は空です。

`hookTypeName`  <a name="lambda-hook-stack-hooktypename"></a>
実行中のフックの名前。

`hookTypeVersion`  <a name="lambda-hook-stack-hooktypeversion"></a>
実行中のフックのバージョン。

`hookModel`  <a name="lambda-hook-stack-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-stack-hookmodel-lambdafunction"></a>
フックによって呼び出される現在の Lambda ARN。

`actionInvocationPoint`  <a name="lambda-hook-stack-actioninvocationpoint"></a>
フックが実行されるプロビジョニングロジックの正確なポイント。  
*有効な値*: (`CREATE_PRE_PROVISION` \$1 `UPDATE_PRE_PROVISION` \$1 `DELETE_PRE_PROVISION`)

`requestData`  <a name="lambda-hook-stack-requestdata"></a>  
`targetName`  <a name="lambda-hook-stack-requestdata-targetname"></a>
この値は `STACK` になります。  
`targetType`  <a name="lambda-hook-stack-requestdata-targettype"></a>
この値は `STACK` になります。  
`targetLogicalId`  <a name="lambda-hook-stack-requestdata-targetlogicalid"></a>
スタック名。  
`payload`  <a name="lambda-hook-stack-requestdata-payload"></a>
現在および以前のテンプレート定義を持つ JSON オブジェクトを含む Amazon S3 署名付き URL。

`requestContext`  <a name="lambda-hook-stack-requestcontext"></a>
フックが再呼び出されている場合、このオブジェクトが設定されます。    
`invocation`  <a name="lambda-hook-stack-requestcontext-invocation"></a>
フックの現在の実行試行。  
`callbackContext`  <a name="lambda-hook-stack-requestcontext-callbackcontext"></a>
Hook が に設定`IN_PROGRESS`され、返`callbackContext`された場合、再呼び出し時にここに表示されます。

リクエストデータの `payload`プロパティは、コードが取得する必要がある URL です。URL を受信すると、次のスキーマを持つオブジェクトを取得します。

```
{
    "template": String,
    "previousTemplate": String
}
```

`template`  <a name="lambda-hook-stack-payload-template"></a>
`create-stack` または に提供された完全な CloudFormation テンプレート`update-stack`。CloudFormation に提供された内容に応じて、JSON または YAML 文字列を指定できます。  
`delete-stack` オペレーションでは、この値は空になります。

`previousTemplate`  <a name="lambda-hook-stack-payload-previoustemplate"></a>
以前の CloudFormation テンプレート。CloudFormation に提供された内容に応じて、JSON または YAML 文字列を指定できます。  
`delete-stack` オペレーションでは、この値は空になります。

### Lambda フックスタック変更入力の例
<a name="lambda-hooks-create-lambda-function-stack-example"></a>

以下は、スタック変更入力の例です。フックは、 を true `ObjectLockEnabled` に更新し、Amazon SQS キューを追加する変更を評価しています。

```
{
    "clientRequestToken": "f8da6d11-b23f-48f4-814c-0fb6a667f50e",
    "awsAccountId": "123456789012",
    "stackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "changeSetId": null,
    "hookTypeName": "my::lambda::stackhook",
    "hookTypeVersion": "00000008",
    "hookModel": {
        "LambdaFunction": "arn:aws:lambda:us-west-2:123456789012:function:MyFunction"
    },
    "actionInvocationPoint": "UPDATE_PRE_PROVISION",
    "requestData": {
        "targetName": "STACK",
        "targetType": "STACK",
        "targetLogicalId": "my-cloudformation-stack",
        "payload": "https://s3......"
    },
    "requestContext": {
        "invocation": 1,
        "callbackContext": null
    }
}
```

`payload` の例を次に示します`requestData`。

```
{
    "template": "{\"Resources\":{\"S3Bucket\":{\"Type\":\"AWS::S3::Bucket\",\"Properties\":{\"ObjectLockEnabled\":true}},\"SQSQueue\":{\"Type\":\"AWS::SQS::Queue\",\"Properties\":{\"QueueName\":\"NewQueue\"}}}}",
    "previousTemplate": "{\"Resources\":{\"S3Bucket\":{\"Type\":\"AWS::S3::Bucket\",\"Properties\":{\"ObjectLockEnabled\":false}}}}"
}
```

### スタックオペレーションの Lambda 関数の例
<a name="lambda-hooks-create-lambda-function-stack-example-function"></a>

次の例は、スタックオペレーションペイロードをダウンロードし、テンプレート JSON を解析して を返すシンプルな関数です`SUCCESS`。

------
#### [ Node.js ]

```
export const handler = async (event, context) => {
    var targetType = event?.requestData?.targetType;
    var payloadUrl = event?.requestData?.payload;
    
    var response = {
        "hookStatus": "SUCCESS",
        "message": "Stack update is compliant",
        "clientRequestToken": event.clientRequestToken
    };
    try {
        const templateHookPayloadRequest = await fetch(payloadUrl);
        const templateHookPayload = await templateHookPayloadRequest.json()
        if (templateHookPayload.template)  {
            // Do something with the template templateHookPayload.template
            // JSON or YAML
        }
        if (templateHookPayload.previousTemplate) {
            // Do something with the template templateHookPayload.previousTemplate
            // JSON or YAML        
        }        
    } catch (error) {
        console.log(error);
        response.hookStatus = "FAILED";
        response.message = "Failed to evaluate stack operation.";
        response.errorCode = "InternalFailure";
    }
    return response;
};
```

------
#### [ Python ]

Python を使用するには、`requests`ライブラリをインポートする必要があります。これを行うには、Lambda 関数を作成するときに、デプロイパッケージに ライブラリを含める必要があります。詳細については、[「 デベロッパーガイド」の「依存関係を持つ .zip デプロイパッケージ](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-create-dependencies)の作成」を参照してください。 *AWS Lambda *

```
import json
import requests

def lamnbda_handler(event, context):
    # Safely access nested dictionary values
    request_data = event.get('requestData', {})
    target_type = request_data.get('targetType')
    payload_url = request_data.get('payload')
    
    response = {
        "hookStatus": "SUCCESS",
        "message": "Stack update is compliant",
        "clientRequestToken": event.get('clientRequestToken')
    }
    
    try:
        # Fetch the payload
        template_hook_payload_request = requests.get(payload_url)
        template_hook_payload_request.raise_for_status()  # Raise an exception for bad responses
        template_hook_payload = template_hook_payload_request.json()
        
        if 'template' in template_hook_payload:
            # Do something with the template template_hook_payload['template']
            # JSON or YAML
            pass
        
        if 'previousTemplate' in template_hook_payload:
            # Do something with the template template_hook_payload['previousTemplate']
            # JSON or YAML
            pass

    except Exception as error:
        print(error)
        response['hookStatus'] = "FAILED"
        response['message'] = "Failed to evaluate stack operation."
        response['errorCode'] = "InternalFailure"
    
    return response
```

------

## Lambda フックを使用した変更セットオペレーションの評価
<a name="lambda-hooks-create-lambda-function-change-set"></a>

変更セットを作成するたびに、新しい変更セットを最初に評価し、その実行をブロックするように CloudFormation Lambda フックを設定できます。フック設定で`CHANGE_SET`オペレーションをターゲットにするように CloudFormation Lambda フック`TargetOperations`を設定できます。

**Topics**
+ [

### Lambda フック変更セットの入力構文
](#lambda-hooks-create-lambda-function-change-set-input)
+ [

### Lambda フック変更セット変更入力の例
](#lambda-hooks-create-lambda-function-change-set-example)
+ [

### 変更セットオペレーションの Lambda 関数の例
](#lambda-hooks-create-lambda-function-change-set-example-function)

### Lambda フック変更セットの入力構文
<a name="lambda-hooks-create-lambda-function-change-set-input"></a>

変更セットオペレーションの入力はスタックオペレーションに似ていますが、 のペイロードには、変更セットによって導入されたリソース変更のリスト`requestData`も含まれています。

JSON 入力の形状の例を次に示します。

```
{
    "clientRequesttoken": String,
    "awsAccountId": String,
    "stackID": String,
    "changeSetId": String,
    "hookTypeName": String,
    "hookTypeVersion": String,
    "hookModel": {
        "LambdaFunction":String
    },
    "requestData": {
        "targetName": "CHANGE_SET",
        "targetType": "CHANGE_SET",
        "targetLogicalId": String,
        "payload": String (S3 Presigned URL)
    },
    "requestContext": {
        "invocation": Integer,
        "callbackContext": String
    }
}
```

`clientRequesttoken`  <a name="lambda-hook-change-set-clientrequesttoken"></a>
Hook リクエストへの入力として提供されたリクエストトークン。これは必須のフィールドです。

`awsAccountId`  <a name="lambda-hook-change-set-awsaccountid"></a>
評価対象のスタック AWS アカウント を含む の ID。

`stackID`  <a name="lambda-hook-change-set-stackid"></a>
CloudFormation スタックのスタック ID。

`changeSetId`  <a name="lambda-hook-change-set-changesetid"></a>
フック呼び出しを開始した変更セットの ID。

`hookTypeName`  <a name="lambda-hook-change-set-hooktypename"></a>
実行中のフックの名前。

`hookTypeVersion`  <a name="lambda-hook-change-set-hooktypeversion"></a>
実行中のフックのバージョン。

`hookModel`  <a name="lambda-hook-change-set-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-change-set-hookmodel-lambdafunction"></a>
フックによって呼び出される現在の Lambda ARN。

`requestData`  <a name="lambda-hook-change-set-requestdata"></a>  
`targetName`  <a name="lambda-hook-change-set-requestdata-targetname"></a>
この値は `CHANGE_SET` になります。  
`targetType`  <a name="lambda-hook-change-set-requestdata-targettype"></a>
この値は `CHANGE_SET` になります。  
`targetLogicalId`  <a name="lambda-hook-change-set-requestdata-targetlogicalid"></a>
変更セット ARN。  
`payload`  <a name="lambda-hook-change-set-requestdata-payload"></a>
現在のテンプレートを持つ JSON オブジェクトと、この変更セットによって導入された変更のリストを含む Amazon S3 署名付き URL。

`requestContext`  <a name="lambda-hook-change-set-requestcontext"></a>
フックが再呼び出されている場合、このオブジェクトが設定されます。    
`invocation`  <a name="lambda-hook-change-set-requestcontext-invocation"></a>
フックの現在の実行試行。  
`callbackContext`  <a name="lambda-hook-change-set-requestcontext-callbackcontext"></a>
Hook が に設定`IN_PROGRESS`され、返`callbackContext`された場合、再呼び出し時にここに表示されます。

リクエストデータの `payload`プロパティは、コードが取得する必要がある URL です。URL を受信すると、次のスキーマを持つオブジェクトを取得します。

```
{
    "template": String,
    "changedResources": [
        {
            "action": String,
            "beforeContext": JSON String,
            "afterContext": JSON String,
            "lineNumber": Integer,
            "logicalResourceId": String,
            "resourceType": String
        }
    ]
}
```

`template`  <a name="lambda-hook-change-set-payload-template"></a>
`create-stack` または に提供された完全な CloudFormation テンプレート`update-stack`。CloudFormation に提供された内容に応じて、JSON または YAML 文字列を指定できます。

`changedResources`  <a name="lambda-hook-change-set-payload-changed-resources"></a>
変更されたリソースのリスト。    
`action`  <a name="lambda-hook-change-set-payload-changed-resources-action"></a>
リソースに適用される変更のタイプ。  
*有効な値*: (`CREATE` \$1 `UPDATE` \$1 `DELETE`)  
`beforeContext`  <a name="lambda-hook-change-set-payload-changed-resources-beforecontext"></a>
変更前のリソースプロパティの JSON 文字列。この値は、リソースの作成時に null になります。この JSON 文字列のすべてのブール値と数値は STRINGS です。  
`afterContext`  <a name="lambda-hook-change-set-payload-changed-resources-aftercontext"></a>
この変更セットが実行された場合のリソースプロパティの JSON 文字列。リソースが削除されている場合、この値は null です。この JSON 文字列のすべてのブール値と数値は STRINGS です。  
`lineNumber`  <a name="lambda-hook-change-set-payload-changed-resources-linenumber"></a>
この変更の原因となったテンプレートの行番号。アクションが の場合、`DELETE`この値は null になります。  
`logicalResourceId`  <a name="lambda-hook-change-set-payload-changed-resources-logicalresourceid"></a>
変更するリソースの論理リソース ID。  
`resourceType`  <a name="lambda-hook-change-set-payload-changed-resources-resourcetype"></a>
変更されるリソースタイプ。

### Lambda フック変更セット変更入力の例
<a name="lambda-hooks-create-lambda-function-change-set-example"></a>

以下は、変更セットの変更入力の例です。次の例では、変更セットによって導入された変更を確認できます。最初の変更は、 というキューの削除です`CoolQueue`。2 番目の変更は、 という新しいキューの追加です`NewCoolQueue`。最後の変更は、 の更新です`DynamoDBTable`。

```
{
    "clientRequestToken": "f8da6d11-b23f-48f4-814c-0fb6a667f50e",
    "awsAccountId": "123456789012",
    "stackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "changeSetId": "arn:aws:cloudformation:us-west-2:123456789012:changeSet/SampleChangeSet/1a2345b6-0000-00a0-a123-00abc0abc000",
    "hookTypeName": "my::lambda::changesethook",
    "hookTypeVersion": "00000008",
    "hookModel": {
        "LambdaFunction": "arn:aws:lambda:us-west-2:123456789012:function:MyFunction"
    },
    "actionInvocationPoint": "CREATE_PRE_PROVISION",
    "requestData": {
        "targetName": "CHANGE_SET",
        "targetType": "CHANGE_SET",
        "targetLogicalId": "arn:aws:cloudformation:us-west-2:123456789012:changeSet/SampleChangeSet/1a2345b6-0000-00a0-a123-00abc0abc000",
        "payload": "https://s3......"
    },
    "requestContext": {
        "invocation": 1,
        "callbackContext": null
    }
}
```

`payload` の例を次に示します`requestData.payload`。

```
{
  template: 'Resources:\n' +
    '  DynamoDBTable:\n' +
    '    Type: AWS::DynamoDB::Table\n' +
    '    Properties:\n' +
    '      AttributeDefinitions:\n' +
    '        - AttributeName: "PK"\n' +
    '          AttributeType: "S"\n' +
    '      BillingMode: "PAY_PER_REQUEST"\n' +
    '      KeySchema:\n' +
    '        - AttributeName: "PK"\n' +
    '          KeyType: "HASH"\n' +
    '      PointInTimeRecoverySpecification:\n' +
    '        PointInTimeRecoveryEnabled: false\n' +
    '  NewSQSQueue:\n' +
    '    Type: AWS::SQS::Queue\n' +
    '    Properties:\n' +
    '      QueueName: "NewCoolQueue"',
  changedResources: [
    {
      logicalResourceId: 'SQSQueue',
      resourceType: 'AWS::SQS::Queue',
      action: 'DELETE',
      lineNumber: null,
      beforeContext: '{"Properties":{"QueueName":"CoolQueue"}}',
      afterContext: null
    },
    {
      logicalResourceId: 'NewSQSQueue',
      resourceType: 'AWS::SQS::Queue',
      action: 'CREATE',
      lineNumber: 14,
      beforeContext: null,
      afterContext: '{"Properties":{"QueueName":"NewCoolQueue"}}'
    },
    {
      logicalResourceId: 'DynamoDBTable',
      resourceType: 'AWS::DynamoDB::Table',
      action: 'UPDATE',
      lineNumber: 2,
      beforeContext: '{"Properties":{"BillingMode":"PAY_PER_REQUEST","AttributeDefinitions":[{"AttributeType":"S","AttributeName":"PK"}],"KeySchema":[{"KeyType":"HASH","AttributeName":"PK"}]}}',
      afterContext: '{"Properties":{"BillingMode":"PAY_PER_REQUEST","PointInTimeRecoverySpecification":{"PointInTimeRecoveryEnabled":"false"},"AttributeDefinitions":[{"AttributeType":"S","AttributeName":"PK"}],"KeySchema":[{"KeyType":"HASH","AttributeName":"PK"}]}}'
    }
  ]
}
```

### 変更セットオペレーションの Lambda 関数の例
<a name="lambda-hooks-create-lambda-function-change-set-example-function"></a>

次の例は、変更セットオペレーションペイロードをダウンロードし、各変更をループして、 を返す前に前後のプロパティを出力するシンプルな関数です`SUCCESS`。

------
#### [ Node.js ]

```
export const handler = async (event, context) => {
    var payloadUrl = event?.requestData?.payload;    
    var response = {
        "hookStatus": "SUCCESS",
        "message": "Change set changes are compliant",
        "clientRequestToken": event.clientRequestToken
    };
    try {
        const changeSetHookPayloadRequest = await fetch(payloadUrl);
        const changeSetHookPayload = await changeSetHookPayloadRequest.json();
        const changes = changeSetHookPayload.changedResources || [];
        for(const change of changes) {
            var beforeContext = {};
            var afterContext = {};
            if(change.beforeContext) {
                beforeContext = JSON.parse(change.beforeContext);
            }
            if(change.afterContext) {
                afterContext = JSON.parse(change.afterContext);
            }
            console.log(beforeContext)
            console.log(afterContext)
            // Evaluate Change here
        }
    } catch (error) {
        console.log(error);
        response.hookStatus = "FAILED";
        response.message = "Failed to evaluate change set operation.";
        response.errorCode = "InternalFailure";
    }
    return response;
};
```

------
#### [ Python ]

Python を使用するには、`requests`ライブラリをインポートする必要があります。これを行うには、Lambda 関数を作成するときに、デプロイパッケージに ライブラリを含める必要があります。詳細については、[「 デベロッパーガイド」の「依存関係を持つ .zip デプロイパッケージ](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-create-dependencies)の作成」を参照してください。 *AWS Lambda *

```
import json
import requests

def lambda_handler(event, context):
    payload_url = event.get('requestData', {}).get('payload')
    response = {
        "hookStatus": "SUCCESS",
        "message": "Change set changes are compliant",
        "clientRequestToken": event.get('clientRequestToken')
    }

    try:
        change_set_hook_payload_request = requests.get(payload_url)
        change_set_hook_payload_request.raise_for_status()  # Raises an HTTPError for bad responses
        change_set_hook_payload = change_set_hook_payload_request.json()
        
        changes = change_set_hook_payload.get('changedResources', [])
        
        for change in changes:
            before_context = {}
            after_context = {}
            
            if change.get('beforeContext'):
                before_context = json.loads(change['beforeContext'])
            
            if change.get('afterContext'):
                after_context = json.loads(change['afterContext'])
            
            print(before_context)
            print(after_context)
            # Evaluate Change here

    except requests.RequestException as error:
        print(error)
        response['hookStatus'] = "FAILED"
        response['message'] = "Failed to evaluate change set operation."
        response['errorCode'] = "InternalFailure"
    except json.JSONDecodeError as error:
        print(error)
        response['hookStatus'] = "FAILED"
        response['message'] = "Failed to parse JSON payload."
        response['errorCode'] = "InternalFailure"

    return response
```

------