Skip to content

Commit 1e3d41e

Browse files
authored
fix(autoscaling): verify public subnets for associatePublicIpAddress (#2077)
The AutoScalingGroup construct allows setting associatePublicIpAddress, but that is pointless when you're not in a Public subnet because your shiny public IP address will still not be routable. Adding the check get rids of another sharp edge around EC2 networking that people need to be aware of. Also change the 'isPublicSubnet()' method on VPC to work with subnet IDs instead of objects, to align better with the 'subnetIds()' function. BREAKING CHANGE: `VpcNetwork.isPublicSubnet()` has been renamed to `VpcNetwork.isPublicSubnetIds()`.
1 parent 6699fed commit 1e3d41e

File tree

4 files changed

+31
-14
lines changed

4 files changed

+31
-14
lines changed

Diff for: packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts

+3
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup
292292
}
293293

294294
asgProps.vpcZoneIdentifier = props.vpc.subnetIds(props.vpcSubnets);
295+
if (!props.vpc.isPublicSubnets(asgProps.vpcZoneIdentifier) && props.associatePublicIpAddress) {
296+
throw new Error("To set 'associatePublicIpAddress: true' you must select Public subnets (vpcSubnets: { subnetType: SubnetType.Public })");
297+
}
295298

296299
this.autoScalingGroup = new CfnAutoScalingGroup(this, 'ASG', asgProps);
297300
this.osType = machineImage.os.type;

Diff for: packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts

+21
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,8 @@ export = {
418418
minCapacity: 0,
419419
maxCapacity: 0,
420420
desiredCapacity: 0,
421+
422+
vpcSubnets: { subnetType: ec2.SubnetType.Public },
421423
associatePublicIpAddress: true,
422424
});
423425

@@ -428,6 +430,25 @@ export = {
428430
));
429431
test.done();
430432
},
433+
'association of public IP address requires public subnet'(test: Test) {
434+
// GIVEN
435+
const stack = new cdk.Stack();
436+
const vpc = mockVpc(stack);
437+
438+
// WHEN
439+
test.throws(() => {
440+
new autoscaling.AutoScalingGroup(stack, 'MyStack', {
441+
instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.M4, ec2.InstanceSize.Micro),
442+
machineImage: new ec2.AmazonLinuxImage(),
443+
vpc,
444+
minCapacity: 0,
445+
maxCapacity: 0,
446+
desiredCapacity: 0,
447+
associatePublicIpAddress: true,
448+
});
449+
});
450+
test.done();
451+
},
431452
'allows disassociation of public IP address'(test: Test) {
432453
// GIVEN
433454
const stack = new cdk.Stack();

Diff for: packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts

+6-13
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,9 @@ export interface IVpcNetwork extends IConstruct {
7777
subnetInternetDependencies(selection?: SubnetSelection): IDependable;
7878

7979
/**
80-
* Return whether the given subnet is one of this VPC's public subnets.
81-
*
82-
* The subnet must literally be one of the subnet object obtained from
83-
* this VPC. A subnet that merely represents the same subnet will
84-
* never return true.
80+
* Return whether all of the given subnets are from the VPC's public subnets.
8581
*/
86-
isPublicSubnet(subnet: IVpcSubnet): boolean;
82+
isPublicSubnets(subnetIds: string[]): boolean;
8783

8884
/**
8985
* Adds a new VPN connection to this VPC
@@ -253,14 +249,11 @@ export abstract class VpcNetworkBase extends Construct implements IVpcNetwork {
253249
public abstract export(): VpcNetworkImportProps;
254250

255251
/**
256-
* Return whether the given subnet is one of this VPC's public subnets.
257-
*
258-
* The subnet must literally be one of the subnet object obtained from
259-
* this VPC. A subnet that merely represents the same subnet will
260-
* never return true.
252+
* Return whether all of the given subnets are from the VPC's public subnets.
261253
*/
262-
public isPublicSubnet(subnet: IVpcSubnet) {
263-
return this.publicSubnets.indexOf(subnet) > -1;
254+
public isPublicSubnets(subnetIds: string[]): boolean {
255+
const pubIds = new Set(this.publicSubnets.map(n => n.subnetId));
256+
return subnetIds.every(pubIds.has.bind(pubIds));
264257
}
265258

266259
/**

Diff for: packages/@aws-cdk/aws-ec2/lib/vpc.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ export class VpcNetwork extends VpcNetworkBase {
456456
if (placement) {
457457
const subnets = this.subnets(placement);
458458
for (const sub of subnets) {
459-
if (!this.isPublicSubnet(sub)) {
459+
if (this.publicSubnets.indexOf(sub) === -1) {
460460
throw new Error(`natGatewayPlacement ${placement} contains non public subnet ${sub}`);
461461
}
462462
}

0 commit comments

Comments
 (0)