CDKのAwsCustomResourceでAWSのAPIを呼ぶ
awsCDKでリソース作成後にしか取得できない値を渡す必要があるとき Describe API を呼びたいことがある。通常、このような CloudFormation の管理外のことを行うには自前のLambdaを用意して CustomResource を作成することになるが、AWS の API を呼ぶだけだったら 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"),
})
}
}
これをデプロイすると次のような Role が作成され onCreate の eks.describeCluster の値が Output に出力される。
カスタムリソースの置き換え判定に用いられる physicalResourceId は重複してもエラーにならなかった。
その後 timeout などの値を変えても同じ出力になったが、Lambda に渡される parameters の値を変えてデプロイすると onUpdate の sts.getCallerIndentity が呼ばれ Output の getResponseField() で対象フィールドがなく失敗するようになった。また onUpdate を消して再度デプロイしても同様のエラーが発生した。
onCreate のデフォルト値は onUpdate なので Describe のようにリソースを作成しない API の場合は onUpdate だけ渡し、リソースを作成する場合は後片付けのために onDelete も渡すと良いように思う。