How to Create a VPC with AWS CDK
A Virtual Private Cloud (VPC) is a virtual network that is isolated from other AWS customers, providing a secure environment for your resources. In this guide, I'll walk you through how to create and configure a VPC using AWS Cloud Development Kit (CDK), including default settings and important considerations.
Note: We are going to provision 1 NAT Gateway. NAT Gateways have an hourly billing rate of about $0.045 in the us-east-1 region.
Creating a VPC in AWS CDK
To create a VPC in AWS CDK, we need to instantiate and configure the Vpc class. Here’s an example:
import { Vpc, IpAddresses, SubnetType } from "aws-cdk-lib/aws-ec2"; import { Stack, StackProps, App } from "aws-cdk-lib"; export class CdkStarterStack extends Stack { constructor(scope: App, id: string, props?: StackProps) { super(scope, id, props); const vpc = new Vpc(this, "cdk-vpc", { ipAddresses: IpAddresses.cidr("10.0.0.0/16"), natGateways: 1, maxAzs: 3, subnetConfiguration: [ { name: "private-subnet-1", subnetType: SubnetType.PRIVATE_WITH_EGRESS, cidrMask: 24, }, { name: "public-subnet-1", subnetType: SubnetType.PUBLIC, cidrMask: 24, }, { name: "isolated-subnet-1", subnetType: SubnetType.PRIVATE_ISOLATED, cidrMask: 28, }, ], }); } }
Configuration
Here’s a breakdown of the configuration properties we used:
-
ipAddresses: Defines the CIDR block of the VPC. It must be between /16 (65,536 IP Addresses) and /28 (16 IP addresses). The default value is
10.0.0.0/16. -
natGateways: Specifies the number of NAT gateways to create. By default, one NAT Gateway is created per availability zone. For testing, it's wise to set this to 1 to avoid unnecessary costs.
Note: To use NAT instances instead of NAT gateways, we can set the
natGatewayProviderprop toNatProvider.instance. nat-instance-example:import { Vpc, NatProvider, SubnetType } from "aws-cdk-lib/aws-ec2"; const vpc = new Vpc(this, "cdk-vpc", { natGatewayProvider: NatProvider.instance({ instanceType: new InstanceType("t3.micro"), }), }); -
maxAzs: The maximum number of availability zones to use. By default, it uses 3 availability zones if the environment is explicitly set (
accountandregion) and 2 if it's environment-agnostic. -
subnetConfiguration: Specifies the subnets to create in each availability zone. In this example, we have 3 types:
private,public, andisolatedsubnets.
Types of Subnets
Let's dive into the different subnet types:
- PRIVATE_WITH_EGRESS: Resources in these subnets can access the internet via a NAT Gateway but cannot be accessed from the internet. Suitable for backend servers that need internet access for updates but shouldn't be exposed.
- PUBLIC: Resources here have internet access through an Internet Gateway and can be accessed from the internet if they have a public IP. Ideal for web servers.
- PRIVATE_ISOLATED: Resources here have no internet access and can't be accessed from the internet. They can only communicate with other instances in the same VPC. Often used for databases.
Deployment
To deploy the resources, run:
cdk deploy or npx aws-cdk deploy
What Gets Provisioned
After deployment, check the CloudFormation management console. You’ll see we’ve provisioned 39 resources with our VPC definition.
VPC
The naming convention includes the stack name. You can update the name by changing the tag of the VPC.
Subnets
We created 9 subnets across 3 availability zones: public, private, and isolated subnets in each zone.
Route Tables
Public Subnets: Routes traffic to the internet via an Internet Gateway.
| Destination | Target | Status | Propagated |
|---|---|---|---|
10.0.0.0/16 | local | active | No |
0.0.0.0/0 | IGW-ID | active | No |
Private Subnets: Routes traffic to the internet through a NAT Gateway.
| Destination | Target | Status | Propagated |
|---|---|---|---|
10.0.0.0/16 | local | active | No |
0.0.0.0/0 | NATGW-ID | active | No |
Isolated Subnets: Routes traffic only within the VPC.
| Destination | Target | Status | Propagated |
|---|---|---|---|
10.0.0.0/16 | local | active | No |
Internet Gateway
Provisioned for public subnets and attached to the VPC.
NAT Gateway
Provisioned with an elastic IP to route traffic from private subnets.
Network Access Control Lists (NACLs)
Default NACLs associated with all subnets allow all inbound and outbound traffic.
Security Groups
Inbound Rules: Allow all traffic from resources within the same security group.
| Type | Protocol | Port range | Source |
|---|---|---|---|
| All traffic | All | All | SG-ID |
Outbound Rules: Allow all traffic to all destinations.
| Type | Protocol | Port range | Destination |
|---|---|---|---|
| All traffic | All | All | 0.0.0.0/0 |
Note: Don't forget to destroy the stack because we provisioned a NAT Gateway which has an hourly billing rate.
cdk destroy or npx aws-cdk destroy
By following this guide, you can set up and configure a VPC using AWS CDK efficiently.
Quick Recap
How do you create a VPC with AWS CDK?
Instantiate the Vpc construct from aws-cdk-lib/aws-ec2 with a CIDR range, the number of NAT gateways, max availability zones, and a subnetConfiguration array describing each subnet type and size, then deploy with cdk deploy.
What's the difference between PRIVATE_WITH_EGRESS, PUBLIC, and PRIVATE_ISOLATED subnets?
PUBLIC subnets have direct internet access via an Internet Gateway and can be reached from the internet. PRIVATE_WITH_EGRESS subnets can reach the internet through a NAT Gateway but can't be reached from it. PRIVATE_ISOLATED subnets have no internet access at all and can only talk to other resources inside the VPC.
How many NAT Gateways does CDK create by default?
By default CDK creates one NAT Gateway per availability zone. For testing, it's common to set natGateways: 1 to limit the hourly NAT Gateway cost.
Why should you destroy a CDK VPC stack with a NAT Gateway when you're done testing?
NAT Gateways bill hourly (roughly $0.045/hour in us-east-1) even when idle, so running cdk destroy after testing avoids accumulating unnecessary charges.
Comments
Share your thoughts and questions below