Call AWS API with AwsCustomResource in CDK
awsWhen you need to pass values that can be obtained only after createing resources in CDK, you may want to call Describe API. Normally, to do someting like this that is not managed by CloudFormation, you need to prepare your own lambda function and create a CustomResource, but if you just want to call AWS APIs, you can use AwsCustomResource.
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as eks from 'aws-cdk-lib/aws-eks';
import { KubectlV27Layer } from '@aws-cdk/lambda-layer-kubectl-v27';
export class CdkCallAwsApiTestStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, 'vpc', {
vpcName: 'cdk-call-aws-api-test',
ipAddresses: ec2.IpAddresses.cidr('10.18.0.0/18'),
maxAzs: 2,
ipProtocol: ec2.IpProtocol.DUAL_STACK,
})
const cluster = new eks.Cluster(this, 'cluster', {
vpc,
clusterName: 'cdk-call-aws-api-test',
version: eks.KubernetesVersion.V1_27,
kubectlLayer: new KubectlV27Layer(this, 'KubectlV27Layer'),
defaultCapacity: 1,
defaultCapacityInstance: new ec2.InstanceType('m5.large'),
ipFamily: eks.IpFamily.IP_V6,
})
const customResourceParams = ({
onCreate: {
service: 'eks',
// https://docs.aws.amazon.com/eks/latest/APIReference/API_DescribeCluster.html
action: 'describeCluster',
parameters: {
name: cluster.clusterName,
},
physicalResourceId: cdk.custom_resources.PhysicalResourceId.fromResponse("cluster.arn") // = PhysicalResourceId.of(cluster.clusterArn)
},
onUpdate: {
service: 'sts',
action: 'getCallerIdentity',
// parameters: {},
},
policy: cdk.custom_resources.AwsCustomResourcePolicy.fromSdkCalls({
resources: cdk.custom_resources.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
timeout: cdk.Duration.minutes(5),
})
const clusterInfo = new cdk.custom_resources.AwsCustomResource(this, 'EksDescribeCluster', customResourceParams);
new cdk.custom_resources.AwsCustomResource(this, 'EksDescribeCluster2', customResourceParams);
new cdk.CfnOutput(this, 'ServiceIpv6CidrOutput', {
value: clusterInfo.getResponseField("cluster.kubernetesNetworkConfig.serviceIpv6Cidr"),
})
}
}
When you deploy this, the following Role will be created and the response of eks.describeCluster in onCreate will be shown as Output.
Even if physicalResourceIds for judging whether to replace the custom resource are duplicated, no error occurs.
After that, if you change the timeout etc., the output is still the same, but if you change the parameters field passed to the lambda function, sts.getCallerIndentity in onUpdate will be called and getResponseField() in Output will fail due to the field not existing. Besides, if you remove onUpdate and deploy again, the same error will occur.
The default value of onCreate is onUpdate, so if you call an API that doesn’t create resources like Describe, I understand that you can pass only onUpdate, and if it creates resources, you should also pass onDelete for cleanup.