Many people are not satisfied with the out of the box VPC experience we provide.
They have slightly different IP layout needs, or AZ selection or subnet layout or routing table, or don't like the hierarchy/naming used. The current VPC is not flexible enough.
Provide a compatible Vpc construct that can be configured to users' heart's content.
Creating this issue to link all others to.
This is a :rocket: Feature Request
It seems that by default there is no way to add an additional CIDR to the VPC. This is a blocker for larger infrastructures: in my case, I cannot use the CDK to create the VPC for any large EKS clusters.
CDK should follow the cloud-formation interface! Do not tie our hands, let us build. If you want to add a "convenience" wrapper, do so, but do not force this on us. CDK is a tool not a prescription for how to build.
I agree that this is an issue. Base VPC construct has way too many assumptions. For example it tries to create 3x public and 3x private subnets even if optional subnet_configuration
is not specified.
Should we be using CfnVpc
construct instead?
We're finding the same. We use Cfn
classes for 90% of the stuff we do in CDK because of the highly opinionated nature of the higher-level constructs. I wish AWS would find a better way to strike a balance between abastraction and opinionated-ness.
It also needs to be much easier to use the two (Constructs and Cfn) in unison. Right now if you use Cfn your essentially forced to use it all over, since constructs often can't reference Cfn resources.
I LOVE the idea behind CDK, but the current implementation and direction just isn't right. In the meantime, we'll use Cfn
resources pretty much exclusively.
would like for ability to blacklist/whitelist AZ by name/zone id
usecase:
us-east-1
. use1-az3
is an available AZ and unfortunately its mapped to us-east-1a
which means that the VPC construct always selects this. this az does not have new instances (eg. no t3.* family) which forces us to use CfnVpc
to select newer azs. proposed addition to Vpc options:
// list of availability zones that won't be used when creating a vpc
+blacklistAzs?: string[]
happy to put in a pull request if we feel good about this change. this would also completely address this issue
Hi all, I submitted a PR #7720 implementing more control over the subnet. Would be glad if you can reivew and submit feedback. Thanks
Is this something that needs an RFC?
Hello. Is there any update or ETA on when the Subnet CIDR (example, 10.0.1.0/24) can be explicitly specified when using a Builder construct?
I want fo follow some VPC design guides from AWS:
Practical VPC Design : it divides VPC into AZs first then into tiers.
Building a Modular and Scalable Virtual Network Architecture with Amazon VPC: it divides VPC into tiers and then into AZs.
I already have a poorly designed subnets. I need to work around them first and plan for refactoring. However current ec2.Vpc
doesn't let me to do that.
It would be better if I can list subnet CIDR and AZ specifications to ec2.Vpc
.
@foriequal0 Hello. You might want to look into the cfn* constructs.
https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.CfnNatGateway.html
@catalyst0 Thanks! I ended up with using cfn* constructs. But I wish there is a better way than wiring manually cfn* constructs. ec2.Vpc
provides some default routings for such as IGW, NAT. However, cfn* constructs force me to wiring them from bottom to top by myself since L2 constructs doesn't play well with L1 constructs. It was much easier if I could import existing resources to L1 or L2, or converting L1 to L2.
@catalyst0 Thanks! I ended up with using cfn* constructs. But I wish there is a better way than wiring manually cfn* constructs.
ec2.Vpc
provides some default routings for such as IGW, NAT. However, cfn* constructs force me to wiring them from bottom to top by myself since L2 constructs doesn't play well with L1 constructs. It was much easier if I could import existing resources to L1 or L2, or converting L1 to L2.
@foriequal0 You are welcome. Yes, the HL constructs are definitely lacking when it comes to more granular control over how you want to deploy your IaC. Another option is to generate your own HL classes from typical patterns that suit your needs where you can have your own classes referencing the Cfn* classes to do things. For example. a class called MakeSNPrivate that accepts a subnet object and creates a route table for it and also creates a route to the NGW supplied.
I've subclassed ec2.Vpc
this way, and I found that this is more flexible than before.
export class Vpc extends ec2.Vpc {
private internetGateway?: CfnInternetGateway;
private _myInternetConnectivityEstablished = new ConcreteDependable();
constructor(scope: Construct, id: string, props: Omit<ec2.VpcProps, "subnetConfiguration">) {
super(scope, id, { ...props, subnetConfiguration: [] });
// @ts-ignore
this.internetGatewayId = Lazy.stringValue({
produce: (_context: IResolveContext): string | undefined => {
return this.internetGateway?.ref;
},
});
// @ts-ignore
this.internetConnectivityEstablished = this._internetConnectivityEstablished;
}
private getInternetGateway(): [CfnInternetGateway, IDependable] {
if (this.internetGateway === undefined) {
const igw = new ec2.CfnInternetGateway(this, "IGW", {});
const att = new ec2.CfnVPCGatewayAttachment(this, "VPCGW", {
vpcId: this.vpcId,
internetGatewayId: igw.ref,
});
this.internetGateway = igw;
this._myInternetConnectivityEstablished.add(att);
}
return [this.internetGateway, this.internetConnectivityEstablished];
}
public addPublicSubnet(props: Omit<PublicSubnetProps, "vpcId">): PublicSubnet {
assert(this.availabilityZones.indexOf(props.availabilityZone) !== -1);
const subnetId = this.publicSubnets.length + 1;
const [igw, att] = this.getInternetGateway();
const pub = new ec2.PublicSubnet(this, `PublicSubnet${subnetId}`, {
availabilityZone: props.availabilityZone,
vpcId: this.vpcId,
cidrBlock: props.cidrBlock,
mapPublicIpOnLaunch: props.mapPublicIpOnLaunch ?? true,
});
pub.addDefaultInternetRoute(igw.ref, att);
this.publicSubnets.push(pub);
return pub;
}
public addPrivateSubnet(props: Omit<PrivateSubnetProps, "vpcId">): PrivateSubnet {
assert(this.availabilityZones.indexOf(props.availabilityZone) !== -1);
const subnetId = this.privateSubnets.length + 1;
const priv = new ec2.PrivateSubnet(this, `PrivateSubnet${subnetId}`, {
availabilityZone: props.availabilityZone,
vpcId: this.vpcId,
cidrBlock: props.cidrBlock,
mapPublicIpOnLaunch: props.mapPublicIpOnLaunch ?? false,
});
this.privateSubnets.push(priv);
return priv;
}
}
Then I can design my subnet as I want.
const vpc = new Vpc(...);
const networkBuilder = new NetworkBuilder(props.cidrBlock);
for(const availabilityZone of this.availabilityZones) {
const nb = new NetworkBuilder(networkBuilder.addSubnet(18));
const priv = vpc.addPrivateSubnet({
availabilityZone,
cidrBlock: nb.addSubnet(19),
});
const pub = vpc.addPublicSubnet({
availabilityZone,
cidrBlock: nb.addSubnet(20),
});
const nat = pub.addNatGateway();
priv.addDefaultNatRoute(nat.ref);
}
Also it solves some issues with CfnVpc (https://github.com/aws/aws-cdk/issues/11406)
Most helpful comment
CDK should follow the cloud-formation interface! Do not tie our hands, let us build. If you want to add a "convenience" wrapper, do so, but do not force this on us. CDK is a tool not a prescription for how to build.