

# Create custom provisioning logic with custom resources
<a name="template-custom-resources"></a>

Custom resources provide a way for you to write custom provisioning logic into your CloudFormation templates and have CloudFormation run it anytime you create, update (if you changed the custom resource), or delete a stack. This can be useful when your provisioning requirements involve complex logic or workflows that can't be expressed with CloudFormation's built-in resource types.

For example, you might want to include resources that aren't available as CloudFormation resource types. You can include those resources by using custom resources. That way, you can still manage all your related resources in a single stack.

To define a custom resource in your CloudFormation template, you use the `AWS::CloudFormation::CustomResource` or `Custom::MyCustomResourceTypeName` resource type. Custom resources require one property, the service token, which specifies where CloudFormation sends requests to, such as an Amazon SNS topic or a Lambda function.

The following topics provide information on how to use custom resources.

**Topics**
+ [How custom resources work](#how-custom-resources-work)
+ [Response timeout](#response-timeout)
+ [CloudFormation custom resource request and response reference](crpg-ref.md)
+ [Amazon SNS-backed custom resources](template-custom-resources-sns.md)
+ [Lambda-backed custom resources](template-custom-resources-lambda.md)

**Note**  
The CloudFormation registry and custom resources each offer their own benefits. Custom resources offer the following benefits:  
You don't need to register the resource.
You can include an entire resource as part of a template without registering.
Supports the `Create`, `Update`, and `Delete` operations
Advantages that registry based resources offer include the following:  
Supports the modeling, provisioning, and managing of third-party application resources
Supports the `Create`, `Read`, `Update`, `Delete`, and `List` (`CRUDL`) operations
Supports drift detection on private and third-party resource types
Unlike custom resources, registry based resources won't need to associate an Amazon SNS topic or a Lambda function to perform `CRUDL` operations. For more information, see [Managing extensions with the CloudFormation registry](registry.md).

## How custom resources work
<a name="how-custom-resources-work"></a>

The general process for setting up a new custom resource includes the following steps. These steps involve two roles: the *custom resource provider* who owns the custom resource and the *template developer* who creates a template that includes a custom resource type. This can be the same person, but if not, the custom resource provider should work with the template developer.

1. The custom resource provider writes logic that determines how to handle requests from CloudFormation and perform actions on the custom resource. 

1. The custom resource provider creates the Amazon SNS topic or Lambda function where CloudFormation can send requests to. The Amazon SNS topic or Lambda function must be in the same Region where the stack will be created.

1. The custom resource provider gives the Amazon SNS topic ARN or Lambda function ARN to the template developer.

1. The template developer defines the custom resource in their CloudFormation template. This includes a service token and any input data parameters. The service token and the structure of the input data are defined by the custom resource provider. The service token specifies the Amazon SNS topic ARN or Lambda function ARN and is always required, but the input data is optional depending on the custom resource.

Now, whenever anyone uses the template to create, update, or delete the custom resource, CloudFormation sends a request to the specified service token, and then waits for a response before proceeding with the stack operation. 

The following summarizes the flow for creating a stack from the template: 

1. CloudFormation sends a request to the specified service token. The request includes information such as the request type and a pre-signed Amazon S3 bucket URL, where the custom resource sends responses to. For more information about what's included in the request, see [CloudFormation custom resource request and response reference](crpg-ref.md).

   The following sample data shows what CloudFormation includes in a `Create` request. In this example, `ResourceProperties` allows CloudFormation to create a custom payload to send to the Lambda function.

   ```
   {
      "RequestType" : "Create",
      "RequestId" : "unique id for this create request",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::TestResource",
      "LogicalResourceId" : "MyTestResource",
      "ResourceProperties" : {
         "Name" : "Value",
         "List" : [ "1", "2", "3" ]
      }
   }
   ```

1. The custom resource provider processes the CloudFormation request and returns a response of `SUCCESS` or `FAILED` to the pre-signed URL. The custom resource provider provides the response in a JSON-formatted file and uploads it to the pre-signed S3 URL. For more information, see [Uploading objects with presigned URLs](https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html) in the *Amazon Simple Storage Service User Guide*.

   In the response, the custom resource provider can also include name-value pairs that the template developer can access. For example, the response can include output data if the request succeeded or an error message if the request failed. For more information about responses, see [CloudFormation custom resource request and response reference](crpg-ref.md).
**Important**  
If the name-value pairs contain sensitive information, you should use the `NoEcho` field to mask the output of the custom resource. Otherwise, the values are visible through APIs that surface property values (such as `DescribeStackEvents`).  
For more information about using `NoEcho` to mask sensitive information, see the [Do not embed credentials in your templates](security-best-practices.md#creds) best practice.

   The custom resource provider is responsible for listening and responding to the request. For example, for Amazon SNS notifications, the custom resource provider must listen and respond to notifications that are sent to a specific topic ARN. CloudFormation waits and listens for a response in the pre-signed URL location.

   The following sample data shows what a custom resource might include in a response:

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique id for this create request",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MyTestResource",
      "PhysicalResourceId" : "TestResource1",
      "Data" : {
         "OutputName1" : "Value1",
         "OutputName2" : "Value2",
      }
   }
   ```

1. After getting a `SUCCESS` response, CloudFormation proceeds with the stack operation. If a `FAILED` response or no response is returned, the operation fails. Any output data from the custom resource is stored in the pre-signed URL location. The template developer can retrieve that data by using the [Fn::GetAtt](resources-section-structure.md#resource-properties-getatt) function.

**Note**  
If you use AWS PrivateLink, custom resources in the VPC must have access to CloudFormation-specific S3 buckets. Custom resources must send responses to a pre-signed Amazon S3 URL. If they can't send responses to Amazon S3, CloudFormation won't receive a response and the stack operation fails. For more information, see [Access CloudFormation using an interface endpoint (AWS PrivateLink)](vpc-interface-endpoints.md).

## Response timeout
<a name="response-timeout"></a>

The default timeout for your custom resource is 3600 seconds (1 hour). If no response is received during this time, the stack operation fails.

You can adjust the timeout value based on how long you expect the response from the custom resource will take. For example, when provisioning a custom resource that invokes a Lambda function that's expected to respond within five minutes, you can set a timeout of five minutes in the stack template by specifying the `ServiceTimeout` property. For more information, see [CloudFormation custom resource request and response reference](crpg-ref.md). This way, if there's an error in the Lambda function that causes it to get stuck, CloudFormation will fail the stack operation after five minutes instead of waiting the full hour. 

However, be careful not to set the timeout value too low. To avoid unexpected timeouts, make sure that your custom resource has enough time to perform the necessary actions and return a response.

# CloudFormation custom resource request and response reference
<a name="crpg-ref"></a>

CloudFormation manages custom resources through a request-response protocol that communicates with your custom resource provider. Each request includes a request type (`Create`, `Update`, or `Delete`) and follows this high-level workflow:

1. A template developer defines a custom resource with a `ServiceToken` and `ServiceTimeout` in the template and initiates a stack operation.

1. CloudFormation sends a JSON request to the custom resource provider through SNS or Lambda.

1. The custom resource provider processes the request and returns a JSON response to a presigned Amazon S3 bucket URL before the timeout period expires.

1. CloudFormation reads the response and proceeds with the stack operation. If no response is received before the timeout period ends, the request is considered unsuccessful, and the stack operation fails.

For more information, see [How custom resources work](template-custom-resources.md#how-custom-resources-work).

This section describes the structure, parameters, and expected responses for each request type.

**Note**  
The total size of the response body can't exceed 4096 bytes.

## Template setup
<a name="crpg-ref-template-setup"></a>

When defining a custom resource in a template, the template developer uses [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html) with the following properties:

`ServiceToken`  
An Amazon SNS topic ARN or Lambda function ARN from the same Region as the stack.  
*Required*: Yes  
*Type*: String

`ServiceTimeout`  
The maximum time, in seconds, before a custom resource operation times out. It must be a value between 1 and 3600. Default: 3600 seconds (1 hour).  
*Required*: No  
*Type*: String

Additional resource properties are supported. Resource properties will be included as `ResourceProperties` in the request. The custom resource provider must determine which properties are valid and their acceptable values.

## Request object
<a name="crpg-ref-requesttypes"></a>

------
#### [ Create ]

When the template developer creates a stack containing a custom resource, CloudFormation sends a request with `RequestType` set to `Create`.

Create requests contain the following fields:

`RequestType`  
`Create`.  
*Required*: Yes  
*Type*: String

`RequestId`  
A unique ID for the request.  
Combining the `StackId` with the `RequestId` forms a value that you can use to uniquely identify a request on a particular custom resource.  
*Required*: Yes  
*Type*: String

`StackId`  
The Amazon Resource Name (ARN) that identifies the stack that contains the custom resource.  
Combining the `StackId` with the `RequestId` forms a value that you can use to uniquely identify a request on a particular custom resource.  
*Required*: Yes  
*Type*: String

`ResponseURL`  
The response URL identifies a presigned S3 bucket that receives responses from the custom resource provider to CloudFormation.  
*Required*: Yes  
*Type*: String

`ResourceType`  
The template developer-chosen resource type of the custom resource in the CloudFormation template. Custom resource type names can be up to 60 characters long and can include alphanumeric and the following characters: `_@-`.  
*Required*: Yes  
*Type*: String

`LogicalResourceId`  
The template developer-chosen name (logical ID) of the custom resource in the CloudFormation template.  
*Required*: Yes  
*Type*: String

`ResourceProperties`  
This field contains the contents of the `Properties` object sent by the template developer. Its contents are defined by the custom resource provider.  
*Required*: No  
*Type*: JSON object

*Example*

```
{
   "RequestType" : "Create",
   "RequestId" : "unique-request-id",
   "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/id",
   "ResponseURL" : "pre-signed-url-for-create-response",
   "ResourceType" : "Custom::MyCustomResourceType",
   "LogicalResourceId" : "resource-logical-id",
   "ResourceProperties" : {
      "key1" : "string",
      "key2" : [ "list" ],
      "key3" : { "key4" : "map" }
   }
}
```

------
#### [ Update ]

When the template developer makes changes to the properties of a custom resource within the template and updates the stack, CloudFormation sends a request to the custom resource provider with `RequestType` set to `Update`. This means that your custom resource code doesn't have to detect changes in resources because it knows that its properties have changed when the request type is `Update`.

Update requests contain the following fields:

`RequestType`  
`Update`.  
*Required*: Yes  
*Type*: String

`RequestId`  
A unique ID for the request.  
Combining the `StackId` with the `RequestId` forms a value that you can use to uniquely identify a request on a particular custom resource.  
*Required*: Yes  
*Type*: String

`StackId`  
The Amazon Resource Name (ARN) that identifies the stack that contains the custom resource.  
Combining the `StackId` with the `RequestId` forms a value that you can use to uniquely identify a request on a particular custom resource.  
*Required*: Yes  
*Type*: String

`ResponseURL`  
The response URL identifies a presigned S3 bucket that receives responses from the custom resource provider to CloudFormation.  
*Required*: Yes  
*Type*: String

`ResourceType`  
The template developer-chosen resource type of the custom resource in the CloudFormation template. Custom resource type names can be up to 60 characters long and can include alphanumeric and the following characters: `_@-`. You can't change the type during an update.  
*Required*: Yes  
*Type*: String

`LogicalResourceId`  
The template developer-chosen name (logical ID) of the custom resource in the CloudFormation template.  
*Required*: Yes  
*Type*: String

`PhysicalResourceId`  
A custom resource provider-defined physical ID that is unique for that provider.  
*Required*: Yes  
*Type*: String

`ResourceProperties`  
This field contains the contents of the `Properties` object sent by the template developer. Its contents are defined by the custom resource provider.  
*Required*: No  
*Type*: JSON object

`OldResourceProperties`  
Used only for `Update` requests. The resource property values that were previously declared by the template developer in the CloudFormation template.  
*Required*: Yes  
*Type*: JSON object

*Example*

```
{
   "RequestType" : "Update",
   "RequestId" : "unique-request-id",
   "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/id",
   "ResponseURL" : "pre-signed-url-for-update-response",
   "ResourceType" : "Custom::MyCustomResourceType",
   "LogicalResourceId" : "resource-logical-id",
   "PhysicalResourceId" : "provider-defined-physical-id",
   "ResourceProperties" : {
      "key1" : "new-string",
      "key2" : [ "new-list" ],
      "key3" : { "key4" : "new-map" }
   },
   "OldResourceProperties" : {
      "key1" : "string",
      "key2" : [ "list" ],
      "key3" : { "key4" : "map" }
   }
}
```

------
#### [ Delete ]

When the template developer deletes the stack or removes the custom resource from the template and then updates the stack, CloudFormation sends a request with `RequestType` set to `Delete`.

Delete requests contain the following fields:

`RequestType`  
`Delete`.  
*Required*: Yes  
*Type*: String

`RequestId`  
A unique ID for the request.  
*Required*: Yes  
*Type*: String

`StackId`  
The Amazon Resource Name (ARN) that identifies the stack that contains the custom resource.  
*Required*: Yes  
*Type*: String

`ResponseURL`  
The response URL identifies a presigned S3 bucket that receives responses from the custom resource provider to CloudFormation.  
*Required*: Yes  
*Type*: String

`ResourceType`  
The template developer-chosen resource type of the custom resource in the CloudFormation template. Custom resource type names can be up to 60 characters long and can include alphanumeric and the following characters: `_@-`.  
*Required*: Yes  
*Type*: String

`LogicalResourceId`  
The template developer-chosen name (logical ID) of the custom resource in the CloudFormation template.  
*Required*: Yes  
*Type*: String

`PhysicalResourceId`  
A custom resource provider-defined physical ID that is unique for that provider.  
*Required*: Yes  
*Type*: String

`ResourceProperties`  
This field contains the contents of the `Properties` object sent by the template developer. Its contents are defined by the custom resource provider.  
*Required*: No  
*Type*: JSON object

*Example*

```
{
   "RequestType" : "Delete",
   "RequestId" : "unique-request-id",
   "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/id",
   "ResponseURL" : "pre-signed-url-for-delete-response",
   "ResourceType" : "Custom::MyCustomResourceType",
   "LogicalResourceId" : "resource-logical-id",
   "PhysicalResourceId" : "provider-defined-physical-id",
   "ResourceProperties" : {
      "key1" : "string",
      "key2" : [ "list" ],
      "key3" : { "key4" : "map" }
   }
}
```

------

## Response object
<a name="crpg-ref-responses"></a>

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.

The response must be a JSON object with the following fields:

`Status`  
Must be either `SUCCESS` or `FAILED`.  
*Required*: Yes  
*Type*: String

`RequestId`  
A unique ID for the request. Copy this value exactly as it appears in the request.  
*Required*: Yes  
*Type*: String

`StackId`  
The Amazon Resource Name (ARN) that identifies the stack that contains the custom resource. Copy this value exactly as it appears in the request.  
*Required*: Yes  
*Type*: String

`LogicalResourceId`  
The template developer-chosen name (logical ID) of the custom resource in the CloudFormation template. Copy this value exactly as it appears in the request.  
*Required*: Yes  
*Type*: String

`PhysicalResourceId`  
This value should be an identifier unique to the custom resource vendor, and can be up to 1 KB in size. The value must be a non-empty string and must be identical for all responses for the same resource.  
When updating custom resources, the value returned for `PhysicalResourceId` determines the update behavior. If the value remains the same, CloudFormation considers it a normal update. If the value changes, CloudFormation interprets the update as a replacement and sends a delete request to the old resource. For more information, see [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html).  
*Required*: Yes  
*Type*: String

`Reason`  
Describes the reason for a failure response.  
Required if `Status` is `FAILED`. It's optional otherwise.  
*Required*: Conditional  
*Type*: String

`NoEcho`  
Indicates whether to mask the output of the custom resource when retrieved by using the `Fn::GetAtt` function. If set to `true`, all returned values are masked with asterisks (\$1\$1\$1\$1\$1), *except for those stored in the `Metadata` section of the template*. CloudFormation does not transform, modify, or redact any information you include in the `Metadata` section. The default value is `false`.  
For more information about using `NoEcho` to mask sensitive information, see the [Do not embed credentials in your templates](security-best-practices.md#creds) best practice.  
Available for `Create` and `Update` responses only. Not supported for `Delete` responses.  
*Required*: No  
*Type*: Boolean

`Data`  
The custom resource provider-defined name-value pairs to send with the response. You can access the values provided here by name in the template with `Fn::GetAtt`.  
Available for `Create` and `Update` responses only. Not supported for `Delete` responses.  
If the name-value pairs contain sensitive information, you should use the `NoEcho` field to mask the output of the custom resource. Otherwise, the values are visible through APIs that surface property values (such as `DescribeStackEvents`).
*Required*: No  
*Type*: JSON object

### Success Response Examples
<a name="crpg-ref-success-response-examples"></a>

#### `Create` and `Update` Response
<a name="crpg-ref-success-response-example-1"></a>

```
{
   "Status": "SUCCESS",
   "RequestId": "unique-request-id",
   "StackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/name/id",
   "LogicalResourceId": "resource-logical-id", 
   "PhysicalResourceId": "provider-defined-physical-id",
   "NoEcho": true,
   "Data": {
      "key1": "value1",
      "key2": "value2"
   }
}
```

#### `Delete` Response
<a name="crpg-ref-success-response-example-2"></a>

```
{
   "Status": "SUCCESS",
   "RequestId": "unique-request-id",
   "StackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/name/id",
   "LogicalResourceId": "resource-logical-id", 
   "PhysicalResourceId": "provider-defined-physical-id"
}
```

### Failed Response Example
<a name="crpg-ref-failed-response-example"></a>

```
{
   "Status": "FAILED",
   "RequestId": "unique-request-id",
   "StackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/name/id",
   "LogicalResourceId": "resource-logical-id",
   "PhysicalResourceId": "provider-defined-physical-id",
   "Reason": "Required failure reason string"
}
```

# Amazon SNS-backed custom resources
<a name="template-custom-resources-sns"></a>

The following topic shows you how to configure a custom resource with a service token that specifies the Amazon SNS topic that CloudFormation sends requests to. You also learn the sequence of events and messages sent and received as a result of custom resource stack creation, updates, and deletion.

With custom resources and Amazon SNS, you can enable scenarios such as adding new resources to a stack and injecting dynamic data into a stack. For example, when you create a stack, CloudFormation can send a `Create` request to a topic that's monitored by an application that's running on an Amazon EC2 instance. The Amazon SNS notification triggers the application to carry out additional provisioning tasks, such as retrieve a pool of allow-listed Elastic IP addresses. After it's done, the application sends a response (and any output data) that notifies CloudFormation to proceed with the stack operation.

When you specify an Amazon SNS topic as the target of a custom resource, CloudFormation sends messages to the specified SNS topic during stack operations involving the custom resource. To process these messages and perform the necessary actions, you must have a supported endpoint subscribed to the SNS topic.

For an introduction to custom resources and how they work, see [How custom resources work](template-custom-resources.md#how-custom-resources-work). For information about Amazon SNS and how it works, see the [Amazon Simple Notification Service Developer Guide](https://docs.aws.amazon.com/sns/latest/dg/).

## Using Amazon SNS to create custom resources
<a name="walkthrough-custom-resources-sns-adding-nonaws-resource"></a>

**Topics**
+ [Step 1: Stack creation](#crpg-walkthrough-stack-creation)
+ [Step 2: Stack updates](#crpg-walkthrough-stack-updates)
+ [Step 3: Stack deletion](#crpg-walkthrough-stack-deletion)

### Step 1: Stack creation
<a name="crpg-walkthrough-stack-creation"></a>

1. <a name="crpg-walkthrough-stack-creation-customer-template"></a>The template developer creates a CloudFormation stack that contains a custom resource. 

   In the template example below, we use the custom resource type name `Custom::SeleniumTester` for the custom resource with logical ID `MySeleniumTest`. Custom resource type names must be alphanumeric and can have a maximum length of 60 characters. 

   The custom resource type is declared with a service token, optional provider-specific properties, and optional [Fn::GetAtt](resources-section-structure.md#resource-properties-getatt) attributes that are defined by the custom resource provider. These properties and attributes can be used to pass information from the template developer to the custom resource provider and vice-versa. The service token specifies an Amazon SNS topic that the resource provider has configured.

   ```
   {
      "AWSTemplateFormatVersion" : "2010-09-09",
      "Resources" : {
         "MySeleniumTest" : {
            "Type": "Custom::SeleniumTester",
            "Version" : "1.0",
            "Properties" : {
               "ServiceToken": "arn:aws:sns:us-west-2:123456789012:CRTest",
               "seleniumTester" : "SeleniumTest()",
               "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
               "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
            }
         }
      },
      "Outputs" : {
         "topItem" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
         },
         "numRespondents" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
         }
      }
   }
   ```
**Note**  
The names and values of the data accessed with `Fn::GetAtt` are returned by the custom resource provider during the provider's response to CloudFormation. If the custom resource provider is a third-party, then the template developer must obtain the names of these return values from the custom resource provider.

1. <a name="crpg-walkthrough-stack-creation-provider-request"></a>CloudFormation sends an Amazon SNS notification to the resource provider with a `"RequestType" : "Create"` that contains information about the stack, the custom resource properties from the stack template, and an S3 URL for the response.

   The SNS topic that's used to send the notification is embedded in the template in the `ServiceToken` property. To avoid using a hardcoded value, a template developer can use a template parameter so that the value is entered at the time the stack is launched.

   The following example shows a custom resource `Create` request which includes a custom resource type name, `Custom::SeleniumTester`, created with a `LogicalResourceId` of `MySeleniumTester`:

   ```
   {
      "RequestType" : "Create",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
      }
   }
   ```

   For detailed information about the request object for `Create` requests, see the [Request and response reference](crpg-ref.md) topic.

1. <a name="crpg-walkthrough-stack-creation-provider-response"></a>The custom resource provider processes the data sent by the template developer and determines whether the `Create` request was successful. The resource provider then uses the S3 URL sent by CloudFormation to send a response of either `SUCCESS` or `FAILED`.

   Depending on the response type, different response fields will be expected by CloudFormation. For information about the response fields for a particular request type, see the documentation for that request type in the [Request and response reference](crpg-ref.md) section.

   In response to a create or update request, the custom resource provider can return data elements in the `Data` field of the response. These are name value pairs, and the *names* correspond to the `Fn::GetAtt` attributes used with the custom resource in the stack template. The *values* are the data that's returned when the template developer calls `Fn::GetAtt` on the resource with the attribute name.

   The following is an example of a custom resource response:

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "Data" : {
         "resultsPage" : "http://www.myexampledomain/test-results/guid",
         "lastUpdate" : "2012-11-14T03:30Z"
      }
   }
   ```

   For detailed information about the response object for `Create` requests, see the [Request and response reference](crpg-ref.md) topic.

   The `StackId`, `RequestId`, and `LogicalResourceId` fields must be copied verbatim from the request.

1. <a name="crpg-walkthrough-stack-creation-stack-status"></a> CloudFormation declares the stack status as `CREATE_COMPLETE` or `CREATE_FAILED`. If the stack was successfully created, the template developer can use the output values of the created custom resource by accessing them with [Fn::GetAtt](resources-section-structure.md#resource-properties-getatt).

   For example, the custom resource template used for illustration used `Fn::GetAtt` to copy resource outputs into the stack outputs:

   ```
   "Outputs" : {
      "topItem" : {
         "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
      },
      "numRespondents" : {
         "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
      }
   }
   ```

### Step 2: Stack updates
<a name="crpg-walkthrough-stack-updates"></a>

To update an existing stack, you must submit a template that specifies updates for the properties of resources in the stack, as shown in the example below. CloudFormation updates only the resources that have changes specified in the template. For more information, see [Understand update behaviors of stack resources](using-cfn-updating-stacks-update-behaviors.md).

You can update custom resources that require a replacement of the underlying physical resource. When you update a custom resource in a CloudFormation template, CloudFormation sends an update request to that custom resource. If a custom resource requires a replacement, the new custom resource must send a response with the new physical ID. When CloudFormation receives the response, it compares the `PhysicalResourceId` between the old and new custom resources. If they're different, CloudFormation recognizes the update as a replacement and sends a delete request to the old resource, as shown in [Step 3: Stack deletion](#crpg-walkthrough-stack-deletion).

**Note**  
If you didn't make changes to the custom resource, CloudFormation won't send requests to it during a stack update.

1. <a name="crpg-walkthrough-stack-updates-customer-template"></a>The template developer initiates an update to the stack that contains a custom resource. During an update, the template developer can specify new Properties in the stack template.

   The following is an example of an `Update` to the stack template using a custom resource type:

   ```
   {
      "AWSTemplateFormatVersion" : "2010-09-09",
      "Resources" : {
         "MySeleniumTest" : {
            "Type": "Custom::SeleniumTester",
            "Version" : "1.0",
            "Properties" : {
               "ServiceToken": "arn:aws:sns:us-west-2:123456789012:CRTest",
               "seleniumTester" : "SeleniumTest()",
               "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
                  "http://mynewsite.com" ],
               "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
            }
         }
      },
      "Outputs" : {
         "topItem" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
         },
         "numRespondents" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
         }
      }
   }
   ```

1. <a name="crpg-walkthrough-stack-updates-provider-request"></a>CloudFormation sends an Amazon SNS notification to the resource provider with a `"RequestType" : "Update"` that contains similar information to the `Create` call, except that the `OldResourceProperties` field contains the old resource properties, and ResourceProperties contains the updated (if any) resource properties.

   The following is an example of an `Update` request:

   ```
   {
      "RequestType" : "Update",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
            "http://mynewsite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
      },
      "OldResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
      }
   }
   ```

   For detailed information about the request object for `Update` requests, see the [Request and response reference](crpg-ref.md) topic.

1. <a name="crpg-walkthrough-stack-updates-provider-response"></a>The custom resource provider processes the data sent by CloudFormation. The custom resource performs the update and sends a response of either `SUCCESS` or `FAILED` to the S3 URL. CloudFormation then compares the `PhysicalResourceIDs` of old and new custom resources. If they're different, CloudFormation recognizes that the update requires a replacement and sends a delete request to the old resource. The following example demonstrates the custom resource provider response to an `Update` request.

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester2"
   }
   ```

   For detailed information about the response object for `Update` requests, see the [Request and response reference](crpg-ref.md) topic.

   The `StackId`, `RequestId`, and `LogicalResourceId` fields must be copied verbatim from the request.

1. <a name="crpg-walkthrough-stack-updates-stack-status"></a>CloudFormation declares the stack status as `UPDATE_COMPLETE` or `UPDATE_FAILED`. If the update fails, the stack rolls back. If the stack was successfully updated, the template developer can access any new output values of the created custom resource with `Fn::GetAtt`.

### Step 3: Stack deletion
<a name="crpg-walkthrough-stack-deletion"></a>

1. <a name="crpg-walkthrough-stack-deletion-customer-template"></a>The template developer deletes a stack that contains a custom resource. CloudFormation gets the current properties specified in the stack template along with the SNS topic, and prepares to make a request to the custom resource provider.

1. <a name="crpg-walkthrough-stack-deletion-provider-request"></a>CloudFormation sends an Amazon SNS notification to the resource provider with a `"RequestType" : "Delete"` that contains current information about the stack, the custom resource properties from the stack template, and an S3 URL for the response.

   Whenever you delete a stack or make an update that removes or replaces the custom resource, CloudFormation compares the `PhysicalResourceId` between the old and new custom resources. If they're different, CloudFormation recognizes the update as a replacement and sends a delete request for the old resource (`OldPhysicalResource`), as shown in the following example of a `Delete` request.

   ```
   {
      "RequestType" : "Delete",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
            "http://mynewsite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
      }
   }
   ```

   For detailed information about the request object for `Delete` requests, see the [Request and response reference](crpg-ref.md) topic.

   `DescribeStackResource`, `DescribeStackResources`, and `ListStackResources` display the user-defined name if it has been specified.

1. <a name="crpg-walkthrough-stack-deletion-provider-response"></a>The custom resource provider processes the data sent by CloudFormation and determines whether the `Delete` request was successful. The resource provider then uses the S3 URL sent by CloudFormation to send a response of either `SUCCESS` or `FAILED`. To successfully delete a stack with a custom resource, the custom resource provider must respond successfully to a delete request.

   The following is an example of a custom resource provider response to a `Delete` request:

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1"
   }
   ```

   For detailed information about the response object for `Delete` requests, see the [Request and response reference](crpg-ref.md) topic.

   The `StackId`, `RequestId`, and `LogicalResourceId` fields must be copied verbatim from the request.

1. <a name="crpg-walkthrough-stack-updates-stack-status-delete"></a>CloudFormation declares the stack status as `DELETE_COMPLETE` or `DELETE_FAILED`.

# Lambda-backed custom resources
<a name="template-custom-resources-lambda"></a>

When you associate a Lambda function with a custom resource, the function is invoked whenever the custom resource is created, updated, or deleted. CloudFormation calls a Lambda API to invoke the function and to pass all the request data (such as the request type and resource properties) to the function. The power and customizability of Lambda functions in combination with CloudFormation enable a wide range of scenarios, such as dynamically looking up AMI IDs during stack creation, or implementing and using utility functions, such as string reversal functions.

For an introduction to custom resources and how they work, see [How custom resources work](template-custom-resources.md#how-custom-resources-work).

**Topics**
+ [Walkthrough: Create a delay mechanism with a Lambda-backed custom resource](walkthrough-lambda-backed-custom-resources.md)
+ [`cfn-response` module](cfn-lambda-function-code-cfnresponsemodule.md)

# Walkthrough: Create a delay mechanism with a Lambda-backed custom resource
<a name="walkthrough-lambda-backed-custom-resources"></a>

This walkthrough shows you how to configure and launch a Lambda-backed custom resource using a sample CloudFormation template. This template creates a delay mechanism that pauses stack deployments for a specified time. This can be useful when you need to introduce deliberate delays during resource provisioning, such as when waiting for resources to stabilize before dependent resources are created.

**Note**  
While Lambda-backed custom resources were previously recommended for retrieving AMI IDs, we now recommend using AWS Systems Manager parameters. This approach makes your templates more reusable and easier to maintain. For more information, see [Get a plaintext value from Systems Manager Parameter Store](dynamic-references-ssm.md). 

**Topics**
+ [Overview](#walkthrough-lambda-backed-custom-resources-overview)
+ [Sample template](#walkthrough-lambda-backed-custom-resources-sample-template)
+ [Sample template walkthrough](#walkthrough-lambda-backed-custom-resources-sample-template-walkthrough)
+ [Prerequisites](#walkthrough-lambda-backed-custom-resources-prerequisites)
+ [Launching the stack](#walkthrough-lambda-backed-custom-resources-createfunction-createstack)
+ [Cleaning up resources](#walkthrough-lambda-backed-custom-resources-createfunction-cleanup)
+ [Related information](#w2aac11c45b9c24b9c23)

## Overview
<a name="walkthrough-lambda-backed-custom-resources-overview"></a>

The sample stack template used in this walkthrough creates a Lambda-backed custom resource. This custom resource introduces a configurable delay (60 seconds by default) during stack creation. The delay occurs during stack updates only when the custom resource's properties are modified.

The template provisions the following resources:
+ a custom resource,
+ a Lambda function, and
+ an IAM role that enables Lambda to write logs to CloudWatch.

It also defines two outputs:
+ The actual time the function waited.
+ A unique identifier generated during each execution of the Lambda function.



**Note**  
CloudFormation is a free service but Lambda charges based on the number of requests for your functions and the time your code executes. For more information about Lambda pricing, see [AWS Lambda pricing](https://aws.amazon.com/lambda/pricing/).

## Sample template
<a name="walkthrough-lambda-backed-custom-resources-sample-template"></a>

You can see the Lambda-backed custom resource sample template with the delay mechanism below:

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "LambdaExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [{
            "Effect": "Allow",
            "Principal": { "Service": ["lambda.amazonaws.com"] },
            "Action": ["sts:AssumeRole"]
          }]
        },
        "Path": "/",
        "Policies": [{
          "PolicyName": "AllowLogs",
          "PolicyDocument": {
            "Statement": [{
              "Effect": "Allow",
              "Action": ["logs:*"],
              "Resource": "*"
            }]
          }
        }]
      }
    },
    "CFNWaiter": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Handler": "index.handler",
        "Runtime": "python3.9",
        "Timeout": 900,
        "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] },
        "Code": {
          "ZipFile": { "Fn::Join": ["\n", [
            "from time import sleep",
            "import json",
            "import cfnresponse",
            "import uuid",
            "",
            "def handler(event, context):",
            "  wait_seconds = 0",
            "  id = str(uuid.uuid1())",
            "  if event[\"RequestType\"] in [\"Create\", \"Update\"]:",
            "    wait_seconds = int(event[\"ResourceProperties\"].get(\"ServiceTimeout\", 0))",
            "    sleep(wait_seconds)",
            "  response = {",
            "    \"TimeWaited\": wait_seconds,",
            "    \"Id\": id ",
            "  }",
            "  cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)"
          ]]}
        }
      }
    },
    "CFNWaiterCustomResource": {
      "Type": "AWS::CloudFormation::CustomResource",
      "Properties": {
        "ServiceToken": { "Fn::GetAtt": ["CFNWaiter", "Arn"] },
        "ServiceTimeout": 60
      }
    }
  },
  "Outputs": {
    "TimeWaited": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "TimeWaited"] },
      "Export": { "Name": "TimeWaited" }
    },
    "WaiterId": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "Id"] },
      "Export": { "Name": "WaiterId" }
    }
  }
}
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-yaml"></a>

```
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: "AllowLogs"
          PolicyDocument:
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:*"
                Resource: "*"
  CFNWaiter:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Runtime: python3.9 
      Timeout: 900
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile:
          !Sub |
          from time import sleep
          import json
          import cfnresponse
          import uuid
​
          def handler(event, context):
            wait_seconds = 0
            id = str(uuid.uuid1())
            if event["RequestType"] in ["Create", "Update"]:
              wait_seconds = int(event["ResourceProperties"].get("ServiceTimeout", 0))
              sleep(wait_seconds)
            response = {
              "TimeWaited": wait_seconds,
              "Id": id 
            }
            cfnresponse.send(event, context, cfnresponse.SUCCESS, response, "Waiter-"+id)
  CFNWaiterCustomResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt CFNWaiter.Arn
      ServiceTimeout: 60
Outputs:
  TimeWaited:
    Value: !GetAtt CFNWaiterCustomResource.TimeWaited
    Export:
      Name: TimeWaited
  WaiterId:
    Value: !GetAtt CFNWaiterCustomResource.Id
    Export:
      Name: WaiterId
```

## Sample template walkthrough
<a name="walkthrough-lambda-backed-custom-resources-sample-template-walkthrough"></a>

The following snippets explain relevant parts of the sample template to help you understand how the Lambda function is associated with a custom resource and understand the output.

[AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html) resource `CFNWaiter`  
The `AWS::Lambda::Function` resource specifies the function's source code, handler name, runtime environment, and execution role Amazon Resource Name (ARN).  
The `Handler` property is set to `index.handler` since it uses a Python source code. For more information on accepted handler identifiers when using inline function source codes, see [ AWS::Lambda::Function Code](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-zipfile).  
The `Runtime` is specified as `python3.9` since the source file is a Python code.  
The `Timeout` is set to 900 seconds.  
The `Role` property uses the `Fn::GetAtt` function to get the ARN of the `LambdaExecutionRole` execution role that's declared in the `AWS::IAM::Role` resource in the template.  
The `Code` property defines the function code inline using a Python function. The Python function in the sample template does the following:  
+ Create a unique ID using the UUID
+ Check if the request is a create or update request
+ Sleep for the duration specified for `ServiceTimeout` during `Create` or `Update` requests
+ Return the wait time and unique ID

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-lambda-resource-json"></a>

```
...
    "CFNWaiter": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Handler": "index.handler",
        "Runtime": "python3.9",
        "Timeout": 900,
        "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] },
        "Code": {
          "ZipFile": { "Fn::Join": ["\n", [
            "from time import sleep",
            "import json",
            "import cfnresponse",
            "import uuid",
            "",
            "def handler(event, context):",
            "  wait_seconds = 0",
            "  id = str(uuid.uuid1())",
            "  if event[\"RequestType\"] in [\"Create\", \"Update\"]:",
            "    wait_seconds = int(event[\"ResourceProperties\"].get(\"ServiceTimeout\", 0))",
            "    sleep(wait_seconds)",
            "  response = {",
            "    \"TimeWaited\": wait_seconds,",
            "    \"Id\": id ",
            "  }",
            "  cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)"
          ]]}
        }
      }
    },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-lambda-resource-yaml"></a>

```
...
  CFNWaiter:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Runtime: python3.9 
      Timeout: 900
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile:
          !Sub |
          from time import sleep
          import json
          import cfnresponse
          import uuid
​
          def handler(event, context):
            wait_seconds = 0
            id = str(uuid.uuid1())
            if event["RequestType"] in ["Create", "Update"]:
              wait_seconds = int(event["ResourceProperties"].get("ServiceTimeout", 0))
              sleep(wait_seconds)
            response = {
              "TimeWaited": wait_seconds,
              "Id": id 
            }
            cfnresponse.send(event, context, cfnresponse.SUCCESS, response, "Waiter-"+id)
...
```

[AWS::IAM::Role](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html) resource `LambdaExecutionRole`  
The `AWS::IAM:Role` resource creates an execution role for the Lambda function, which includes an assume role policy which allows Lambda to use it. It also contains a policy allowing CloudWatch Logs access.

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-iam-role-json"></a>

```
...
    "LambdaExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [{
            "Effect": "Allow",
            "Principal": { "Service": ["lambda.amazonaws.com"] },
            "Action": ["sts:AssumeRole"]
          }]
        },
        "Path": "/",
        "Policies": [{
          "PolicyName": "AllowLogs",
          "PolicyDocument": {
            "Statement": [{
              "Effect": "Allow",
              "Action": ["logs:*"],
              "Resource": "*"
            }]
          }
        }]
      }
    },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-iam-role-yaml"></a>

```
...
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: "AllowLogs"
          PolicyDocument:
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:*"
                Resource: "*"
...
```

[AWS::CloudFormation::CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-customresource.html) resource `CFNWaiterCustomResource`  
The custom resource links to the Lambda function with its ARN using `!GetAtt CFNWaiter.Arn`. It will implement a 60 second wait time for create and update operations, as set in `ServiceTimeout`. The resource will only be invoked for an update operation if the properties are modified.

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-custom-resource-json"></a>

```
...
    "CFNWaiterCustomResource": {
      "Type": "AWS::CloudFormation::CustomResource",
      "Properties": {
        "ServiceToken": { "Fn::GetAtt": ["CFNWaiter", "Arn"] },
        "ServiceTimeout": 60
      }
    }
  },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-custom-resource-yaml"></a>

```
...
  CFNWaiterCustomResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt CFNWaiter.Arn
      ServiceTimeout: 60
...
```

`Outputs`  
The `Outputs` of this template are the `TimeWaited` and the `WaiterId`. The `TimeWaited` value uses a `Fn::GetAtt` function to provide the amount of time the waiter resource actually waited. The `WaiterId` uses a `Fn::GetAtt` function to provide the unique ID that was generated and associated with the execution.

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-output-json"></a>

```
...
  "Outputs": {
    "TimeWaited": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "TimeWaited"] },
      "Export": { "Name": "TimeWaited" }
    },
    "WaiterId": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "Id"] },
      "Export": { "Name": "WaiterId" }
    }
  }
}
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-output-yaml"></a>

```
...
Outputs:
  TimeWaited:
    Value: !GetAtt CFNWaiterCustomResource.TimeWaited
    Export:
      Name: TimeWaited
  WaiterId:
    Value: !GetAtt CFNWaiterCustomResource.Id
    Export:
      Name: WaiterId
...
```

## Prerequisites
<a name="walkthrough-lambda-backed-custom-resources-prerequisites"></a>

You must have IAM permissions to use all the corresponding services, such as Lambda and CloudFormation.

## Launching the stack
<a name="walkthrough-lambda-backed-custom-resources-createfunction-createstack"></a>

**To create the stack**

1. Find the template of your preference (YAML or JSON) from the [Sample template](#walkthrough-lambda-backed-custom-resources-sample-template) section and save it to your machine with the name `samplelambdabackedcustomresource.template`.

1. Open the CloudFormation console at [https://console.aws.amazon.com/cloudformation/](https://console.aws.amazon.com/cloudformation/).

1. From the **Stacks** page, choose **Create stack** at top right, and then choose **With new resources (standard)**.

1. For **Prerequisite - Prepare template**, choose **Choose an existing template**.

1. For **Specify template**, choose **Upload a template file**, and then choose **Choose file**.

1. Select the `samplelambdabackedcustomresource.template` template file you saved earlier.

1. Choose **Next**.

1. For **Stack name**, type **SampleCustomResourceStack** and choose **Next**.

1. For this walkthrough, you don't need to add tags or specify advanced settings, so choose **Next**.

1. Ensure that the stack name looks correct, and then choose **Create**.

It might take several minutes for CloudFormation to create your stack. To monitor progress, view the stack events. For more information, see [View stack information from the CloudFormation console](cfn-console-view-stack-data-resources.md).

If stack creation succeeds, all resources in the stack, such as the Lambda function and custom resource, were created. You have successfully used a Lambda function and custom resource.

If the Lambda function returns an error, view the function's logs in the CloudWatch Logs [console](https://console.aws.amazon.com/cloudwatch/home#logs:). The name of the log stream is the physical ID of the custom resource, which you can find by viewing the stack's resources. For more information, see [View log data](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#ViewingLogData) in the *Amazon CloudWatch User Guide*.

## Cleaning up resources
<a name="walkthrough-lambda-backed-custom-resources-createfunction-cleanup"></a>

Delete the stack to clean up all the stack resources that you created so that you aren't charged for unnecessary resources.

**To delete the stack**

1. From the CloudFormation console, choose the **SampleCustomResourceStack** stack.

1. Choose **Actions** and then **Delete Stack**.

1. In the confirmation message, choose **Yes, Delete**.

All the resources that you created are deleted.

Now that you understand how to create and use Lambda-backed custom resource, you can use the sample template and code from this walkthrough to build and experiment with other stacks and functions.

## Related information
<a name="w2aac11c45b9c24b9c23"></a>
+ [CloudFormation Custom Resource Reference](crpg-ref.md)
+ [AWS::CloudFormation::CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-customresource.html)

# `cfn-response` module
<a name="cfn-lambda-function-code-cfnresponsemodule"></a>

In your CloudFormation template, you can specify a Lambda function as the target of a custom resource. When you use the `ZipFile` property to specify your [function's](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html) source code, you can load the `cfn-response` module to send responses from your Lambda function to a custom resource. The `cfn-response` module is a library that simplifies sending responses to the custom resource that invoked your Lambda function. The module has a `send` method that sends a [response object](crpg-ref.md#crpg-ref-responses) to a custom resource by way of an Amazon S3 presigned URL (the `ResponseURL`).

The `cfn-response` module is available only when you use the `ZipFile` property to write your source code. It isn't available for source code that's stored in Amazon S3 buckets. For code in buckets, you must write your own functions to send responses.

**Note**  
After executing the `send` method, the Lambda function terminates, so anything you write after that method is ignored.

## Loading the `cfn-response` module
<a name="cfn-lambda-function-code-cfnresponsemodule-loading"></a>

For Node.js functions, use the `require()` function to load the `cfn-response` module. For example, the following code example creates a `cfn-response` object with the name `response`:

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

For Python, use the `import` statement to load the `cfnresponse` module, as shown in the following example:

**Note**  
Use this exact import statement. If you use other variants of the import statement, CloudFormation doesn't include the response module.

```
import cfnresponse
```

## `send` method parameters
<a name="cfn-lambda-function-code-cfnresponsemodule-send-parameters"></a>

You can use the following parameters with the `send` method.

`event`  
The fields in a [custom resource request](crpg-ref.md#crpg-ref-requesttypes).

`context`  
An object, specific to Lambda functions, that you can use to specify when the function and any callbacks have completed execution, or to access information from within the Lambda execution environment. For more information, see [Building Lambda functions with Node.js](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html) in the *AWS Lambda Developer Guide*.

`responseStatus`  
Whether the function successfully completed. Use the `cfnresponse` module constants to specify the status: `SUCCESS` for successful executions and `FAILED` for failed executions.

`responseData`  
The `Data` field of a custom resource [response object](crpg-ref.md#crpg-ref-responses). The data is a list of name-value pairs.

`physicalResourceId`  
Optional. The unique identifier of the custom resource that invoked the function. By default, the module uses the name of the Amazon CloudWatch Logs log stream that's associated with the Lambda function.  
The value returned for a `PhysicalResourceId` can change custom resource update operations. If the value returned is the same, it's considered a normal update. If the value returned is different, CloudFormation recognizes the update as a replacement and sends a delete request to the old resource. For more information, see [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html).

`noEcho`  
Optional. Indicates whether to mask the output of the custom resource when it's retrieved by using the `Fn::GetAtt` function. If set to `true`, all returned values are masked with asterisks (\$1\$1\$1\$1\$1), except for information stored in the locations specified below. By default, this value is `false`.  
Using the `NoEcho` attribute does not mask any information stored in the following:  
+ The `Metadata` template section. CloudFormation does not transform, modify, or redact any information you include in the `Metadata` section. For more information, see [Metadata](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html).
+ The `Outputs` template section. For more information, see [Outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html).
+ The `Metadata` attribute of a resource definition. For more information, see [`Metadata` attribute](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html).
We strongly recommend you do not use these mechanisms to include sensitive information, such as passwords or secrets.
For more information about using `NoEcho` to mask sensitive information, see the [Do not embed credentials in your templates](security-best-practices.md#creds) best practice.

## Examples
<a name="cfn-lambda-function-code-cfnresponsemodule-examples"></a>

### Node.js
<a name="cfn-lambda-function-code-zipfile-examplenodejs"></a>

In the following Node.js example, the inline Lambda function takes an input value and multiplies it by 5. Inline functions are especially useful for smaller functions because they allow you to specify the source code directly in the template, instead of creating a package and uploading it to an Amazon S3 bucket. The function uses the `cfn-response` `send` method to send the result back to the custom resource that invoked it.

#### JSON
<a name="cfn-lambda-function-code-zipfile-examplenodejs.json"></a>

```
"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
<a name="cfn-lambda-function-code-zipfile-examplenodejs-yaml"></a>

```
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
<a name="cfn-lambda-function-code-zipfile-examplepython"></a>

In the following Python example, the inline Lambda function takes an integer value and multiplies it by 5.

#### JSON
<a name="cfn-lambda-function-code-zipfile-examplepython.json"></a>

```
"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
<a name="cfn-lambda-function-code-zipfile-examplepython.yaml"></a>

```
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")
```

## Module source code
<a name="cfn-lambda-function-code-cfnresponsemodule-source"></a>

**Topics**
+ [Asynchronous Node.js source code](#cfn-lambda-function-code-cfnresponsemodule-source-nodejs-async)
+ [Node.js source code](#cfn-lambda-function-code-cfnresponsemodule-source-nodejs)
+ [Python source code](#cfn-lambda-function-code-cfnresponsemodule-source-python)

### Asynchronous Node.js source code
<a name="cfn-lambda-function-code-cfnresponsemodule-source-nodejs-async"></a>

The following is the response module source code for the Node.js functions if the handler is asynchronous. Review it to understand what the module does and for help with implementing your own response functions.

```
// 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) {

    return new Promise((resolve, reject) => {
        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: " + parseInt(response.statusCode));
            resolve(context.done());
        });

        request.on("error", function(error) {
            console.log("send(..) failed executing https.request(..): " + maskCredentialsAndSignature(error));
            reject(context.done(error));
        });

        request.write(responseBody);
        request.end();
    })
}
 
function maskCredentialsAndSignature(message) {
    return message.replace(/X-Amz-Credential=[^&\s]+/i, 'X-Amz-Credential=*****')
        .replace(/X-Amz-Signature=[^&\s]+/i, 'X-Amz-Signature=*****');
}
```

### Node.js source code
<a name="cfn-lambda-function-code-cfnresponsemodule-source-nodejs"></a>

The following is the response module source code for the Node.js functions if the handler is not asynchronous. Review it to understand what the module does and for help with implementing your own response functions.

```
// 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: " + parseInt(response.statusCode));
        context.done();
    });

    request.on("error", function(error) {
        console.log("send(..) failed executing https.request(..): " + maskCredentialsAndSignature(error));
        context.done();
    });

    request.write(responseBody);
    request.end();
}
```

### Python source code
<a name="cfn-lambda-function-code-cfnresponsemodule-source-python"></a>

The following is the response module source code for Python functions:

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
 
from __future__ import print_function
import urllib3
import json
import re

SUCCESS = "SUCCESS"
FAILED = "FAILED"

http = urllib3.PoolManager()


def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False, reason=None):
    responseUrl = event['ResponseURL']

    responseBody = {
        'Status' : responseStatus,
        'Reason' : reason or "See the details in CloudWatch Log Stream: {}".format(context.log_stream_name),
        'PhysicalResourceId' : physicalResourceId or context.log_stream_name,
        'StackId' : event['StackId'],
        'RequestId' : event['RequestId'],
        'LogicalResourceId' : event['LogicalResourceId'],
        'NoEcho' : noEcho,
        'Data' : responseData
    }

    json_responseBody = json.dumps(responseBody)

    print("Response body:")
    print(json_responseBody)

    headers = {
        'content-type' : '',
        'content-length' : str(len(json_responseBody))
    }

    try:
        response = http.request('PUT', responseUrl, headers=headers, body=json_responseBody)
        print("Status code:", response.status)


    except Exception as e:

        print("send(..) failed executing http.request(..):", mask_credentials_and_signature(e))
 
 
def mask_credentials_and_signature(message):
    message = re.sub(r'X-Amz-Credential=[^&\s]+', 'X-Amz-Credential=*****', message, flags=re.IGNORECASE)
    return re.sub(r'X-Amz-Signature=[^&\s]+', 'X-Amz-Signature=*****', message, flags=re.IGNORECASE)
```