Programming Infrastructure with the Amazon CDK
In this blog post we will explore how the AWS CDK can be used to deploy a VPC, security groups and EC2 instances. In Part 1, we created a VPC with a public and private subnet using the AWS Console
. In Part 2, we created Security Groups and Network ACLs. Now we will define the infrastructure in code using the AWS CDK
.
Below is the infrastructure that we will deploy to AWS. We will not be installing the software for the web server and database server in order to keep this example simple.
The code shown in this blog can be found on my github repository.
Introduction
It’s important to realize that the code that we write using the AWS CDK will be converted into a CloudFormation template. The difference is that we use modern programming languages such as TypeScript, JavaScript, Python, Java, and C#/.Net to define cloud resources.
In order to build and deploy the project, you will need to first install the following components.
- Node.js
- Typescript
- AWS CLI
- AWS CDK
Directions on how to install the above prerequisites can be found here.
Exploring The Project
After installing the prerequisites, run the following commands to build and deploy the project.
# Install dependencies
npm install
# Build the project
npm run build
# Deploy using CLI
cdk deploy
After successful deployment, we can see the CloudFormation
stack in the AWS Console.
Let’s now walk through the code to see how resources are defined using the AWS CDK.
Main Entry Point
The entry point to our project is bin/aws-cdk-vpc-example.ts
. This is a very basic file that just instantiates the AwsCdkVpcExampleStack
class from ../lib/aws-cdk-vpc-example-stack
.
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import * from '../lib/aws-cdk-vpc-example-stack';
const app = new cdk.App();
new AwsCdkVpcExampleStack(app, 'AwsCdkVpcExampleStack');
The Main Stack
The main file that defines our AWS infrastructure is lib\aws-cdk-vpc-example-stack.ts
. The stack includes the following:
- VPC (public & private subnets, NAT Gateway, Internet Gateway)
- Security Groups (web server & database server security groups)
- EC2 instances (web server & database instances)
VPC
Below is the code snippet in lib\aws-cdk-vpc-example-stack.ts
that defines the VPC. We define a VPC with a 192.168.0.0/16 CIDR block along with a public and private subnet.
const vpc = new ec2.Vpc(this, 'Demo CDK VPC', {
// 192.168.0.0/16 CIDR block for our VPC
cidr: '192.168.0.0/16',
// For this example, we'll only use 1 availability zone
maxAzs: 1,
// Set up a Public and a Private subnet in the single availability zone
subnetConfiguration: [
{
name: 'Public Subnet',
subnetType: ec2.SubnetType.PUBLIC,
cidrMask: 24
},
{
name: 'Private Subnet',
subnetType: ec2.SubnetType.PRIVATE,
cidrMask: 24
}
]
});
From the AWS console, you can see the the VPC and subnets provisioned by the code above.
You may be asking the question about NAT and Internet gateways. According to the documentation, both the NAT and Internet Gateways are created by default.
Web Server Security Group
Security groups act as a virtual firewall that control the flow of traffic between instances in your VPC. You can read more about securing the VPC in my previous blog Amazon Virtual Private Cloud (Amazon VPC) Fundamentals (Part 2). Below is the code that creates a Security Group within our VPC. This Security Group allows connections to port 80 from any IPv4 address through an ingress rule.
const webSecurityGroup = new ec2.SecurityGroup(this,
"Web Server Instances",
{
vpc: vpc
}
);
webSecurityGroup.addIngressRule(ec2.Peer.anyIpv4(),
ec2.Port.tcp(80),
'allow web access from the world'
);
Web Server EC2 Instance
Now that we have our Security Group defined, it’s now time to attach it to our web server EC2 instance.
const webServer = new ec2.Instance(this, "Web Server", {
vpc: vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO),
machineImage: ec2.MachineImage.latestAmazonLinux(),
vpcSubnets: {
subnets: vpc.publicSubnets
},
securityGroup: webSecurityGroup
});
Database Security Group
The Database Security Group allows connections to port 5432. Notice that we are allowing incoming connections from the Web Server Security Group
.
const rdsSecurityGroup = new ec2.SecurityGroup(this,
"RDS Instances",
{
vpc: vpc
}
);
rdsSecurityGroup.addIngressRule(webSecurityGroup,
ec2.Port.tcp(5432),
'allow postgreSQL access from the web server security group'
);
Database EC2 Instance
Just like we did for the web server EC2 instance, we are going to attach the RDS Security Group
to the database server EC2 instance.
const databaseServer = new ec2.Instance(this, "Database Server", {
vpc: vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO),
machineImage: ec2.MachineImage.latestAmazonLinux(),
vpcSubnets: {
subnets: vpc.privateSubnets
},
securityGroup: rdsSecurityGroup
});
Summary
The AWS CDK is a great way to deploy AWS resources using modern programming languages. There are other methods to define Infrastructure as Code (IaC) like CloudFormation and Terraform using JSON and YAML. The choice comes down to preference.