CDK: How to Get the Ids of a list of subnet created from ForEach, for VPC endpoint?

I have struggled for a long time, I can see how it works with regular terraform, but don’t know how to do it with CDK. I would be grateful if I can get some help here.

so far, I have code:

        var zoneIterator = TerraformIterator.FromList(availabilityZones.Names);

        var subnets = new Subnet(this,
            $"private-subnets", new SubnetConfig()
            {
                ForEach = zoneIterator,
                AvailabilityZone = Token.AsString(zoneIterator.Value),
                CidrBlock = FnGenerated.Cidrsubnet(defaultVpc.CidrBlock, 4,
                    startNetNum +
                    Token.AsNumber(FnGenerated.Index(availabilityZones.Names, Token.AsString(zoneIterator.Value)))),
                VpcId = defaultVpc.Id,
                Tags = config.Tags
            });

        var subnetsIds = TerraformIterator.FromResources(subnets);
        
        var endpoint = new VpcEndpoint(this, "app-runner-endpoint", new VpcEndpointConfig()
        {
            VpcId = defaultVpc.Id,
            ServiceName = $"com.amazonaws.{config.EnvironmentVariables.AwsRegion}.apprunner.requests",
            SubnetIds = Token.AsList(subnetsIds.PluckProperty("id"))
        });

With this code, I got error when validating the stack with ShouldBeValidTerraform test:
“Could not infer JSII type for .NET type ‘_Proxy’ (Parameter ‘type’)”

The problem bit is: SubnetIds = subnetsIds.GetList(“id”), commenting out the line passes the test.

Thank you!

Rex

The error message you’re seeing, “Could not infer JSII type for .NET type ‘_Proxy’ (Parameter ‘type’)”, indicates that the CDKTF’s .NET binding is having difficulty understanding the type returned by TerraformIterator.FromResources(subnets) . This is because CDKTF, which leverages JSII for cross-language support, may not always seamlessly translate complex types or operations from TypeScript (its native implementation language) to .NET.

To resolve this issue, you need to directly access the subnet IDs in a manner that is compatible with .NET. Since the direct approach you’ve tried is causing type inference issues, consider a more explicit handling of subnet ID extraction.

Thank you very much @rtwolfe. The question is how.

Since the cdk is implemented natively in Typescript, I will switch to Typescript to avoid translation issues like this.

Rex

[AWS RAG Assisted]

ative support and extensive examples in TypeScript. When working with cdktf to create a list of subnet IDs for use with a VPC endpoint, the key is to correctly manage the iteration and collection of subnet IDs after their creation.

Below is a step-by-step guide on how to dynamically create subnets and then use their IDs for a VPC endpoint configuration in TypeScript:

1.	Define Your VPC and Availability Zones: First, ensure you have your VPC and availability zones defined. You might already have this if you are migrating your C# code.
2.	Create Subnets Dynamically: Use the availability zones to create subnets dynamically. You’ll loop through the availability zones, creating a subnet for each, and collect their IDs.
3.	Collect Subnet IDs: As you create each subnet, collect their IDs into an array. This array will be used to set the subnetIds for the VPC endpoint.
4.	Configure VPC Endpoint with Subnet IDs: Use the collected subnet IDs when configuring your VPC endpoint.

Here is how you can implement it in TypeScript:

import { Construct } from ‘constructs’;
import { App, TerraformStack } from ‘cdktf’;
import { AwsProvider, vpc } from ‘@cdktf/provider-aws’;

class MyStack extends TerraformStack {
constructor(scope: Construct, name: string) {
super(scope, name);

new AwsProvider(this, 'AWS', {
  region: 'us-west-2',
});

// Example: Creating a VPC (assuming you have this part)
const myVpc = new vpc.Vpc(this, 'MyVPC', {
  cidrBlock: '10.0.0.0/16',
  // other VPC configurations as needed
});

// Example availability zones
const availabilityZones = ['us-west-2a', 'us-west-2b', 'us-west-2c'];

// Dynamically create subnets and collect their IDs
const subnetIds = availabilityZones.map((zone, index) => {
  const subnet = new vpc.Subnet(this, `Subnet-${index}`, {
    vpcId: myVpc.id,
    cidrBlock: `10.0.${index}.0/24`,
    availabilityZone: zone,
    // other subnet configurations as needed
  });
  return subnet.id;
});

// Configure VPC Endpoint using collected subnet IDs
new vpc.VpcEndpoint(this, 'MyVPCEndpoint', {
  vpcId: myVpc.id,
  serviceName: 'com.amazonaws.us-west-2.s3',
  subnetIds: subnetIds,
  // other VPC endpoint configurations as needed
});

}
}

const app = new App();
new MyStack(app, ‘my-stack’);
app.synth();

This code defines a stack that includes a VPC, dynamically creates subnets based on the specified availability zones, collects their IDs, and finally uses these IDs to configure a VPC endpoint. Adjust the CIDR blocks, region, service names, and any other specific configurations according to your requirements.

This approach should help you overcome the issues related to dynamic resource creation and referencing in cdktf, particularly when working with TypeScript.