Stacktape
Stacktape


Custom Resources



Custom resources allow you to create resources with custom provisioning logic. This enables you to define the logic for creating, updating, and deleting resources, giving you the ability to provision any type of resource that is not natively supported by Stacktape or Cloudformation. This way, you can manage all your related resources in a single stack.

A common use case for custom resources is provisioning non-AWS resources. While AWS offers a vast array of services, a third-party solution may better fit your needs (e.g., using Auth0 instead of Cognito, or Algolia instead of OpenSearch).

If you are not provisioning a custom resource but are looking for a way to execute custom logic during the deployment process, see the deployment scripts documentation.

How to use custom resources

In Stacktape, a custom resource consists of two parts:

  1. Definition: A special type of Lambda function that contains the custom logic for creating, updating, and deleting the resource.
  2. Instance: An instantiation of a custom resource definition.

The following example shows a custom resource that seeds a MongoDB cluster.

resources:
myMongoCluster:
type: mongo-db-atlas-cluster
properties:
clusterTier: M10
mongoSeeder:
type: custom-resource-definition
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: seed-the-mongo-cluster.ts
connectTo:
- myMongoCluster
seedMongoCluster:
type: custom-resource-instance
properties:
definitionName: mongoSeeder
resourceProperties:
mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')

Custom resource definition

A custom resource definition is similar to a function definition, as it uses a Lambda function to execute the custom logic.

CustomResourceDefinition  API reference
type
Required
properties.packaging
Required
properties.environment
properties.runtime
properties.timeout
Default: 10
properties.memory
properties.connectTo
properties.iamRoleStatements
overrides
resources:
myMongoCluster:
type: mongo-db-atlas-cluster
properties:
clusterTier: M10
mongoSeeder:
type: custom-resource-definition
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: seed-the-mongo-cluster.ts
connectTo:
- myMongoCluster
seedMongoCluster:
type: custom-resource-instance
properties:
definitionName: mongoSeeder
resourceProperties:
mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')

Code of custom resource

The packaging property allows you to specify the path to your code and other packaging-related properties. The code is packaged and executed as a Lambda function. For more information, see the packaging documentation.

resources:
myMongoCluster:
type: mongo-db-atlas-cluster
properties:
clusterTier: M10
mongoSeeder:
type: custom-resource-definition
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: seed-the-mongo-cluster.ts
connectTo:
- myMongoCluster
seedMongoCluster:
type: custom-resource-instance
properties:
definitionName: mongoSeeder
resourceProperties:
mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')

Code example

The following example shows the code for the MongoDB seeding custom resource. For more information on the types of requests (events) a custom resource receives and the response objects you should return, see the AWS documentation.

import mongoose from 'mongoose';
import { SUCCESS, FAILED, send } from 'cfn-response-promise';
// incoming event is in following form
// {
// "RequestType" : "Create" || "Update" || "Delete",
// "RequestId" : "9db53695-b0a0-47d6-908a-ea2d8a3ab5d7",
// "ResponseURL" : "https://...",
// "ResourceType" : "AWS::Cloudformation::CustomResource",
// "LogicalResourceId" : "...",
// "StackId" : "arn:aws:cloudformation:...",
// "ResourceProperties" : {
// ... properties of custom-resource-instance
// }
// }
export default async (event, context) => {
// custom resource definition code
let success = true;
let dataToReturn = {};
try {
// we are only seeding database if the operation is Create
if (event.RequestType === 'Create') {
// we are using the "mongoConnectionString" property passed by custom-resource-instance to create connection
const connection = await mongoose.connect(event.ResourceProperties.mongoConnectionString, {
authMechanism: 'MONGODB-AWS',
authSource: '$external',
useNewUrlParser: true,
useUnifiedTopology: true,
dbName: 'my-test-database'
});
// code with seeding the database ...
// ...
}
} catch (err) {
success = false;
}
await send(event, context, success ? SUCCESS : FAILED, dataToReturn, 'customresourceid');
};
// function must respond to "ResponseURL" with response in following form
// we are using "cfn-response-promise" library which formats response for us
// {
// "Status" : "SUCCESS" || "FAILED",
// "RequestId" : "9db53695-b0a0-47d6-908a-ea2d8a3ab5d7",
// "LogicalResourceId" : "...",
// "StackId" : "arn:aws:cloudformation:...",
// "PhysicalResourceId" : "...",
// "Data" : {
// ... attributes which can be queried in template using $Param
// }
// }

Accessing other resources

By default, resource-to-resource communication is not allowed in AWS. Access must be explicitly granted using IAM permissions. Stacktape automatically handles IAM permissions for the underlying AWS services it creates.

If your custom resource needs to communicate with other infrastructure components, you must grant the necessary permissions manually. You can do this in two ways:

connectTo

The connectTo property is a list of resource names or AWS services that the custom resource will be able to access. Stacktape will automatically grant the basic IAM permissions required for communication. This is useful if you do not want to manage IAM permissions yourself.

When you use the connectTo property, Stacktape also automatically injects information about the connected resource as environment variables into your custom resource's runtime.

Configures access to other resources in your stack and AWS services. By specifying resources here, Stacktape automatically:

  • Configures IAM role permissions.
  • Sets up security group rules to allow network traffic.
  • Injects environment variables with connection details into the compute resource.

Environment variables are named STP_[RESOURCE_NAME]_[VARIABLE_NAME] (e.g., STP_MY_DATABASE_CONNECTION_STRING).

In this example, we grant access to a MongoDB cluster. This will inject the necessary credentials into the custom resource's runtime, which are then used in the code example.

resources:
myMongoCluster:
type: mongo-db-atlas-cluster
properties:
clusterTier: M10
mongoSeeder:
type: custom-resource-definition
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: seed-the-mongo-cluster.ts
connectTo:
- myMongoCluster
seedMongoCluster:
type: custom-resource-instance
properties:
definitionName: mongoSeeder
resourceProperties:
mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')
Resource
Required
Sid
Effect
Default: Allow
Action
Condition

Environment variables

You can use environment variables to inject information that the resource needs during execution.

EnvironmentVar  API reference
name
Required
value
Required

Custom resource instance

A custom resource instance creates an instance of a specified custom resource definition. Depending on the action being performed on the stack (create, update, or delete), the instance receives an event and executes the corresponding logic in the custom resource definition.

resources:
myMongoCluster:
type: mongo-db-atlas-cluster
properties:
clusterTier: M10
mongoSeeder:
type: custom-resource-definition
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: seed-the-mongo-cluster.ts
connectTo:
- myMongoCluster
seedMongoCluster:
type: custom-resource-instance
properties:
definitionName: mongoSeeder
resourceProperties:
mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')
CustomResourceInstance  API reference
type
Required
properties.definitionName
Required
properties.resourceProperties
Required
overrides

Contents