I’ve been using AwsCustomResource with CDK and got a bit stuck, so I’m making a note.
The official explanation is as follows:
Defines a custom resource that is materialized using specific AWS API calls. These calls are created using a singleton Lambda function. class AwsCustomResource (construct)
In short, it’s a custom resource for creating resources by calling AWS APIs.
To put it simply, CloudFormation and CDK create resources from CloudFormation, but AwsCustomResource creates resources by calling AWS APIs directly. This is similar to how Terraform creates resources directly from AWS APIs.
Since CDK is a pure AWS service, you can create most resources with CDK, and even if there isn’t a construct, you can use low-level CDK to create resources. So, basically, you don’t need to use AwsCustomResource, and you should avoid it if possible.
However, there are cases where you might use it:
When you want to manage existing resources with CDK.
For example, if you originally created resources from the AWS console and now want to manage them with CDK. This is sometimes the case with cognito
and similar services.
If you don’t want to migrate regions or accounts, you can just use the existing resources as they are.
You can write it like this:
// Get an existing UserPool
const iUserPool: IUserPool = UserPool.fromUserPoolId(
this,
"UserPool",
"<existing UserPoolId>",
);
this.userPool = iUserPool as UserPool;
With this, you can manage existing UserPools with CDK, but if you deploy, it will use the default UserPool settings.
For example, if you want to add an additional lambda trigger, you will get an error if you use the CDK class purely. This is because it’s not meant for managing existing resources, but for creating new ones. I encountered this error myself. It complained as if the resource already exists (if I remember correctly…).
So, in this case, after managing the existing resource, you can either use AwsCustomResource or lambda with AWS API for additional settings.
Well, since AwsCustomResource is easier, we will use AwsCustomResource here.
Since AwsCustomResource uses AWS APIs instead of CDK, you just need to look at the SDK and write the feature you want to add as it is.
For example, if you want to change the settings of a UserPool, like allowing only admins to create users, you can write it like this:
You determine the Service and Action by looking at the AWS SDK, and write accordingly. Then, just set the policy and physicalResourceId
, and you’re good to go.
new AwsCustomResource(this, "UpdateUserPool", {
onUpdate: {
service: "CognitoIdentityServiceProvider", // Target service
action: "UpdateUserPoolCommand", // Target API
parameters: {
UserPoolId: "existing UserPoolId",
DeletionProtection: "ACTIVE",
// Allow only admins to create users
AdminCreateUserConfig: {
AllowAdminCreateUserOnly: true,
},
},
physicalResourceId: PhysicalResourceId.of(Date.now().toString()),
},
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
As long as you have a rough idea of this approach, you can just refer to the AWS SDK, find out which API to use, and write it accordingly. If you’re someone who usually writes SDKs, you shouldn’t have any particular problems.
However, please be careful that when you’re writing AwsCustomResource, the TypeScript types do not apply. Well, you might think you can just look at the code, but still, be careful.
I personally got stuck for several hours because of this. I was wondering why the settings weren’t being applied and why there were no errors during deployment, and then I realized I had written AdminCreateUserConfig
as adminCreateUserConfig
inside parameters
. I thought it was a CDK bug and was looking at the repository, and in the end, it turned out to be a typo…
Since AwsCustomResource does not benefit from CDK’s types, even if you make some kind of mistake, you won’t get an error, so please be careful.