Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(autoscaling): require public subnets for associatePublicIpAddress #2077

Merged
merged 1 commit into from
Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup
}

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

this.autoScalingGroup = new CfnAutoScalingGroup(this, 'ASG', asgProps);
this.osType = machineImage.os.type;
Expand Down
21 changes: 21 additions & 0 deletions packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ export = {
minCapacity: 0,
maxCapacity: 0,
desiredCapacity: 0,

vpcSubnets: { subnetType: ec2.SubnetType.Public },
associatePublicIpAddress: true,
});

Expand All @@ -428,6 +430,25 @@ export = {
));
test.done();
},
'association of public IP address requires public subnet'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const vpc = mockVpc(stack);

// WHEN
test.throws(() => {
new autoscaling.AutoScalingGroup(stack, 'MyStack', {
instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.M4, ec2.InstanceSize.Micro),
machineImage: new ec2.AmazonLinuxImage(),
vpc,
minCapacity: 0,
maxCapacity: 0,
desiredCapacity: 0,
associatePublicIpAddress: true,
});
});
test.done();
},
'allows disassociation of public IP address'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
Expand Down
19 changes: 6 additions & 13 deletions packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,9 @@ export interface IVpcNetwork extends IConstruct {
subnetInternetDependencies(selection?: SubnetSelection): IDependable;

/**
* Return whether the given subnet is one of this VPC's public subnets.
*
* The subnet must literally be one of the subnet object obtained from
* this VPC. A subnet that merely represents the same subnet will
* never return true.
* Return whether all of the given subnets are from the VPC's public subnets.
*/
isPublicSubnet(subnet: IVpcSubnet): boolean;
isPublicSubnets(subnetIds: string[]): boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if idiomatic, but arePublicSubnets would be grammatically correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I know. But isXxx() is such a standard, didn't want to deviate from it.

How strongly do you feel about this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strongly at all.


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

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

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-ec2/lib/vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ export class VpcNetwork extends VpcNetworkBase {
if (placement) {
const subnets = this.subnets(placement);
for (const sub of subnets) {
if (!this.isPublicSubnet(sub)) {
if (this.publicSubnets.indexOf(sub) === -1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the function you created?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it feels silly to convert all subnet objects to IDs just to match on IDs.

I just realized it's a miracle this works at all, btw, because the subnet IDs are Tokens of course :).

throw new Error(`natGatewayPlacement ${placement} contains non public subnet ${sub}`);
}
}
Expand Down