aws-cdk: Subnet selection returns more than one per AZ

Note: for support questions, please first reference our documentation, then use Stackoverflow. This repository’s issues are intended for feature requests and bug reports.

  • I’m submitting a …

    • 🪲 bug report
    • 🚀 feature request
    • 📚 construct library gap
    • ☎️ security issue or vulnerability => Please see policy
    • ❓ support request => Please see note at the top of this template.
  • What is the current behavior? If the current behavior is a 🪲bug🪲: Please provide the steps to reproduce

Creation of an ALB is failing with an error that it is getting more than one subnet per AZ.

A load balancer cannot be attached to multiple subnets in the same Availability Zone (Service: AmazonElasticLoadBalancingV2; Status Code: 400; Error Code: InvalidConfigurationRequest;

code to reproduce:

      const vpcId = "vpc-xxxxxx";

      const vpc = ec2.Vpc.fromLookup(this, "Vpc", { vpcId: vpcId });

      const alb = new elbv2.ApplicationLoadBalancer(this, id + "LoadBalancer", {
        loadBalancerName: id + 'ALB',
        vpc: vpc,
        internetFacing: false,
        vpcSubnets: {subnetType: ec2.SubnetType.PRIVATE, onePerAz: true}
      });

cdk synth shows a long list of subnets.

console.log(vpc.selectSubnets({subnetType: ec2.SubnetType.PRIVATE, onePerAz: true}).availabilityZones outputs

[
  'us-east-1c', 'us-east-1d',
  'us-east-1d', 'us-east-1d',
  'us-east-1d', 'us-east-1d',
  'us-east-1d', 'us-east-1d',
  'us-east-1d', 'us-east-1d',
  'us-east-1e', 'us-east-1e',
  'us-east-1e', 'us-east-1e',
  'us-east-1e', 'us-east-1e',
  'us-east-1e', 'us-east-1e',
  'us-east-1e', 'us-east-1e',
  'us-east-1e', 'us-east-1e',
  'us-east-1e', 'us-east-1e'
]

Having looked at the implementation, it seems that all private subnets retrieved for the VPC have “Private” returned from subnetName() and the implementation of onePerAz simply filters like this:

subnets = subnets.filter(s => subnetName(s) === subnetName(subnets[0]));

so it returns all the subnets, not just one per AZ.

Selecting by subnetName does not actually seem to use the Name shown in the AWS console.

  • What is the expected behavior (or behavior of feature suggested)? onePerAz: true should return exactly one subnet per AZ.

  • What is the motivation / use case for changing the behavior or adding this feature? trying to create an ALB inside an existing VPC

  • Please tell us about your environment:

    • CDK CLI Version: 0.36.0 (build 6d38487)
    • Module Version: “@aws-cdk/aws-ec2”: “^0.36.0”
    • OS: OSX Mojave
    • Language: TypeScript
  • Other information (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. associated pull-request, stackoverflow, gitter, etc)

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 8
  • Comments: 19 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Same issue here. Creating internal ALB with imported VPC which has multiple private subnets in the same AZ, but onePerAz return all subnets. This will interrupt CDK deploy and return error as below

A load balancer cannot be attached to multiple subnets in the same Availability Zone

Here is the workaround and any suggestion will be appreciated.

    // Import Vpc
    const vpc = ec2.Vpc.fromLookup(this, 'VPC', { vpcName: 'EXISTED_VPC_NAME' });

    // Handle one subnet per AZ
    const subnets: ISubnet[] = [] as ISubnet[];
    vpc.privateSubnets.forEach(subnet => {
      if (subnets.length == 0) {
        subnets.push(subnet);
      } else if (
        subnets.length < 2 &&
        subnets.find(v => {
          if (v.availabilityZone == subnet.availabilityZone) {
            return false;
          }
          return true;
        })
      ) {
        subnets.push(subnet);
      }
    });

    // ALB
    const applicationLoadBalancer = new ApplicationLoadBalancer(tagGroup, 'applicationLoadBalancer', {
      vpc,
      internetFacing: false,
      //vpcSubnets: vpc.selectSubnets({ onePerAz: true})
      vpcSubnets: vpc.selectSubnets({ subnets })
    });

Facing the same issue with the latest CDK, onePerAz does not work as expected, in my case are subnets in a VPC that were created by a central team and thus not managed by CDK.

It turns out CDK has some assumptions on the subnets. It looks for these two tags:‘aws-cdk:subnet-type’ and ‘aws-cdk:subnet-name’ on each subnet.

The ‘aws-cdk:subnet-type’ tag is optional, as CDK will try to guess if a subnet is public if the assign public address on launch is enabled. But the guess seems not working for me, the public subnets also treated as private. As a workaround, I set this tag with value ‘Public’ just for the public subnets.

The ‘aws-cdk:subnet-name’ tag is not the name of the subnet, it’s actually a group name for the same function subnet on all AZ. For example: If you have subnet names with AZ embeded ‘app_az1’, ‘app_az2’, ‘app_az3’. Their ‘aws-cdk:subnet-name’ tag value should be ‘app’.

with all these assumptions, the code below now makes sense, because it is trying to get one for that group 😭

subnets = subnets.filter(s => subnetName(s) === subnetName(subnets[0]));

also you probably need cdk context --clear after you updated the tags, cdk cache the values in cdk.context.json

Re-opening this issue, looks like several people still hit the bug after the fix was released. Apologies to everyone that we didn’t see this sooner; visibility on closed issues is very limited. For future reference, opening a new issue is a much better way to raise that a closed bug is still occurring.

I’m hitting the same issue though tied to the codebuild resource. I’m currently using an existing VPC with ~40 subnets in it and need the onePerAz to avoid hitting limit on resources being attached.

Code used:

const vpc = ec2.Vpc.fromLookup(this, 'VPC', {
	vpcName: 'xxxxxx',
	isDefault: false
});

new codebuild.Project(this, 'ecs-ami-creator', {
	buildSpec: codebuild.BuildSpec.fromObject(yaml.safeLoad(fs.readFileSync(process.env.PWD + '/lib/buildspec.yml', 'utf8'))),
	subnetSelection: { subnetType: ec2.SubnetType.PRIVATE, onePerAz: true },
	vpc: vpc
});

Error Encountered:

Invalid vpc config: the maximum number of subnets is 16 (Service: AWSCodeBuild; Status Code: 400; Error Code: InvalidInputException; Request ID: xxxx)

Environment:

  • CDK CLI Version: 0.37.0 (build c4bdb54)
  • Module Version: @aws-cdk/aws-ec2@0.36.2
  • OS: OSX Mojave
  • Language: TypeScript

Other Info: I’ve also hit the need to be able to filter by Name, but after digging around at different issues saw that filtering is using aws-cdk:subnet-name.

Questions:

  • Is it possible to extend the name tag to also use Name?
  • Is it possible to support creating a subnetSelection with custom filtering that has access to the resources tags and allow for manual filtering rules?