Protecting Your RDS: Configure Your First VPC

Luke Miller
12 min readMar 20, 2020

As we all quarantine ourselves during this COVID-19 pandemic, I figured it would be a good time to discuss how to provide “social distancing” for an RDS and Lambdas. To protect your RDS from others we’ll place it in a VPC along with a Lambda that accesses it.

Who this is for: someone who has never set up a custom VPC.

Overview of what we’re going to do:

1- Create a new VPC and three subnets

2- Configure the subnet route tables

3- Create an RDS instance

4- Configure two Security Groups

5- Create a Lambda that connects to your RDS

Create a New VPC

Your AWS account was given a default VPC, but we want to create a custom VPC for this application. Also, technically all Lambdas you have are deployed inside a VPC, but if you’re not deploying them within your account’s VPC, either default or custom, then it lives inside of AWS’s Lambda-Service VPC. That’s not too important, but it’s nice to know things.

Head over to your AWS Management Console and select the VPC service. Click the VPC option from the navigation items on the left side. Now let’s create your custom VPC. First, be sure you’re in the AWS region you want the VPC in because whatever region you complete these steps in is where your VPC, RDS, and Lambdas will live.

1- Click Create VPC
a) Enter a name for your VPC (ie: web-vpc)
b) Enter an IPv4 CIDR block (ie: 172.16.0.0/18)
c) Select No IPv6 CIDR Block for this example
b) Leave Tenancy as Default

Great! Now, after you Close the confirmation that your VPC was created, you should be on the VPC Dashboard.

Enable DNS Resolution and DNS Hostnames

Real quick, go ahead and click the box next to your custom VPC in the VPCs list.

1) Click the Actions dropdown box.

2) There are two options, “Edit DNS resolution” and “Edit DNS hostnames”. You’ll need to click both and click the Enable box for them.

This is a required configuration for deploying an RDS in a VPC. Without these enabled, your VPC won’t be able to route the traffic correctly to the RDS.

We now need to add subnets to your VPC. Subnets are partitions of your VPC and what resources (ie: RDS and Lambdas) will reside in. While a VPC spans the whole AWS region, the subnets are confined to a single availability zone in the region.

We’re going to create three subnets, one in each availability zone. Why three? Well, Lambdas need to be deployed in private subnets, and it’s recommended to deploy each Lambda to a minimum of two AZs. RDS instances need to be in a public subnet if we want to be able to access them from a database tool like MySQL Workbench. What makes a subnet public or private? We’ll come back to that later.

Create Subnets:

1- Click on the Subnets navigation item in the VPC Dashboard
You’ll see three subnets that were already created by AWS for your account’s default VPC
2- Click on the Create Subnet button
a) Name your subnet following a common convention, like “<vpc-name>-<public/private> — <az>” (ie: web-pub-east2a)
b) Select which the custom VPC we just made
c) Select the availability zone you want this subnet in, and match it with your name tag in step one
d) Enter a valid CIDR block of your VPC CIDR (ie: 172.16.0.0/20)
2- Repeat steps 2–5 twice more, labeling them so that in the end you have two private subnets and one public subnet (if you’re unfamiliar with CIDR blocks, it’d be good to do some research, but here are two quick CIDR blocks you can use for your final two subnets if you selected the same CIDR Block as mine when you created your VPC: 172.16.32.0/20 and 172.16.16.0.20)

Way to go! You’ve now created your custom VPC with three subnets, two private and one public.

Now, technically even though those subnets are named public and private they’re all private at the moment. What makes a subnet public is if it has a route on its Route Table that connects to an Internet Gateway. Let’s look into VPC Routing.

VPC Route Tables

When we created the VPC, AWS also created a Route Table for you, and by default when you added subnets they were assigned to that Route Table. The Route Table directs traffic from your subnets to designated targets. The default configuration is to direct all traffic within the local IP address range of your VPC’s CIDR block to stay local within the VPC. This includes the addresses in your subnets. To see your default Route Table on your custom VPC, click on Your VPCs in the dashboard, then select your custom VPC. On the bottom half of your screen, you should see a “Routes table” link, click it to see your Route Table.

Red box showing you the link for your VPC’s Route Table

If you select the Routes tab, you’ll see all the routes for this Route Table. Currently, there is only one, which instructs all traffic bound for any IP Address in the VPC CIDR block to stay local to this VPC. That means any resource inside the VPC can talk to another resource inside the VPC, regardless of what subnet the resources are in. Since this is the only route, that means your VPC and its subnets have no access to the internet outside of the cozy confines of your VPC. Let’s change that and then add a route to allow traffic outside of the VPC.

You might be wondering, “why would we go to the trouble of setting up a VPC to protect a resource, but then go and open the subnet to the internet?” It’s a great question. We aren’t going to open the doors wide open to our public subnet, but if I want to be able to access my RDS from X location, then I need that RDS to have public access so I can connect to it. A more advanced approach is setting up a VPN, but that’s not the purpose of this introduction to VPC configuration.

Internet Gateway

Adding an Internet Gateway gives your VPC the capability to route traffic out and connect to the internet.

Add Internet Gateway to VPC

1- Click the Internet Gateway navigation link on the left in the VPC Dashboard.
Notice you have one already, it’s for your default VPC
2- Click Create Internet Gateway.
a) Give it a name
b) Click Create
c) Select your new Internet Gateway, then select the Actions dropdown
d) Click on Attach to VPC from the dropdown
e) Select your custom VPC
f) Click Attach

Now with this Internet Gateway attached subnets in our VPC can communicate to the outside world…if we add a route to the Route Table. You should begin to see the role the Route Table has in directing and allowing traffic out of your subnets.

Add Route to Route Table

Click the Route Tables navigation link on the left in the VPC Dashboard and highlight your VPC’s Route Table (you can tell because the Summary tab will tell you which VPC is associated with the Route Table)

  1. Click the Routes tab
  2. Click Edit Routes
    a) Click Add Route
    b) The Destination is a drop-down, but type 0.0.0.0/0 (which means “direct any IP address not previously mentioned in the Route Table to the target we’ll select next)
    c) In the Target drop-down, select Internet Gateway. You should then see the ID for your Internet Gateway for this VPC, click it.
    d) Click Save routes
This is what the Routes in your Route Table should look like now

Nice work!

Now, if you go back to your subnets, and click through them, you’ll see that they all have this Route Table associated with them, and in it, a route allowing them access to the outside world. There’s a problem though. Remember we labeled two subnets as private, and one as public? Well, what makes any subnet public is if it has a route in its Route Table that specifically uses an internet gateway as a target. Well, our two “private” subnets have that in their Route Table so they are currently public, so to make them private we need to assign them a new Route Table that does not have that internet gateway as a target.

Let’s move our two private subnets off this route table so they are truly private.

Create Private Route Table

1- Click Route Tables on the VPC Dashboard
2- Click Create Route Table
a) Give your table a name (ie: <vpc-name>-private)
b) Select your custom VPC
c) Click Create
3- Highlight your newly created route table in the dashboard, and select the Subnet Associations tab

4- Click Edit Subnet Associations
a) Select your two private subnets

Great, now we’ve got the private subnets truly private. The private Route Table only has a route for allowing IP addresses internal to the VPC, so nothing in these two subnets could reach out to the internet.

Now it’s time to add the Lambdas and RDS. We’ll place the RDS in the public subnet and the Lambdas in the private subnets.

Create RDS

1- Go to RDS AWS Service dashboard

2- Click Create RDS Database
a) Select Standard Create
b) Choose your engine option, I chose MySQL
c) Select your template, I chose Free Tier
d) Enter an identifier (ie: web-vpc-rds)
e) Enter a master username/password (write them down!)
f) Jump down to Connectivity and choose your custom VPC
g) Expand the Additional connectivity configuration
h) Select Yes for Publicly Accessible
i) Click Create New for VPC security group
j) Enter a security group name (ie: web-vpc-rds)
k) Select the Availability Zone where you public subnet is (double-check that you chose the correct one before continuing)
l) Create the database

It’ll take a few minutes for the RDS to be created and ready for use.

The red box shows you where you can access your RDS’s security group

If you click on the Security Group link for your RDS you’ll find the Inbound and Outbound rules. While Route Tables determine routing for subnets, Security Groups determine inbound/outbound rules for RDSs, EC2 instances, and Lambdas. If you select your RDS’s Security Group, make sure there is an inbound rule allowing you to connect from your computer’s public IP address. If there is not a rule, add that rule.

Test your DB Connection

Before moving forward, use whatever database tool you have (I use MySQL Workbench) and connect to the database from your computer. If you cannot, likely, you didn’t select the correct availability zone when creating the RDS. Remember, it needs to be in a public subnet. Once you can connect, go ahead and add some data that can be pulled later by the Lambda.

Allow Lambda to Inbound to RDS

We are going to edit the RDS Security Group so that the Lambdas in our VPC have inbound access. To do this, we will make a Security Group for our Lambdas.

Create Lambda Security Group

1- In the EC2 Dashboard (or in the VPC Dashboard) select Security Groups in the left navigation.

2- Click Create Security Group

3- Enter a name (ie: vpc-lambdas)
a) Enter a description
b) Select your custom VPC
c) Add an Inbound Rule for All Traffic and Source is Anywhere (this will allow services, like API Gateway, to trigger your Lambda)
d) Click Create

In the dashboard, find your new Security Group and copy its Group Id (ie: sg-xxxxx). We’ll need this for reference later.

Great, now the Lambdas, which we haven’t made yet, have a Security Group. We need to jump back over to your RDS’ Security Group and add an inbound rule that allows this Lambda Security Group access to TCP traffic on port 3306. A Security Group can accept either an IP Address or another Security Group for the inbound source.

Adjust RDS Security Group

1- In the EC2 Dashboard (or in the VPC Dashboard) select Security Groups in the left navigation.
2- Select the Security Group for your RDS (if you’re unsure, go back to your RDS dashboard and in the details and you’ll find a link to your Security Group)
3- Click Edit Inbound Rules
a) Click Add Rule
b) Change the Type to MYSQL/Aurora (if your db is a MySQL or Aurora db)
c) In Source, select Custom in the drop-down and then enter your sg-xxx identifier for your Lambda Security Group (the Group Id you copied down from earlier)
d) Enter the name of your VPC in the Description
e) Click Save Rules

Your RDS security group allowing your Lambda security group TCP traffic to port 3306

Now we have our VPC, subnets, RDS, and security groups all set up. If you haven’t entered some data into your database do so now.

Create Lambda

1- In the AWS Management Console, select the Lambda service.
2- Click the Create Function button to get started making your Lambda.
a) Select Author From Scratch
b) Enter a name
c) Select a runtime
d) Click Create Function

Depending on your runtime, language, and libraries of choice your Lambda will look differently, but here’s mine with a Node runtime using the MySQL npm package to connect to my database.

Example Lambda to access MySQL RDS

Be sure to enter your Environment Variables for accessing the RDS below the code editor.

If you tried testing this Lambda, it will fail. Why? Well because, even though the Environment Variables are right and the code is correct, our RDS is protected by a Security Group that will only allow inbound traffic from the Lambda Security Group we created. So, we need to assign this Lambda to that Security Group.

Assign Lambda to Lambda Security Group

  1. Scroll down in the Lambda’s Configuration to the VPC section and click Edit
    a) Click Custom VPC
    b) Select your new VPC
    c) Select your two private subnets
    d) Select your Lambda Security Group
    e) Save

Now, scroll to the top of your Lambda, make sure it’s been saved, and test it. You should receive the database response, and if you did, then you just successfully deployed a Lambda and RDS behind your very own custom VPC.

If it worked, then great you just configured your first VPC. Your RDS is only accessible by your Lambdas and your personal computer. Social distancing achieved! Now, this is only an introduction, designed to help you get acquainted with configuring a VPC. There are plenty of security best practices to add to this, as well as other approaches that could have been taken.

As you further your learning on VPCs you’ll come across VPC maps like the one below. Initially, they may seem confusing, but hopefully, after having configured your VPC with an RDS in a public subnet and a Lamba deployed in two private subnets, you can understand the map below without any help.

Common Mistakes:

We configured A LOT, so it’s not uncommon that your Lambda isn’t connecting to your database. When you become more familiar with all of these configurations then the setup of future VPCs, subnets, RDS instances, Security Groups, and Lambdas becomes a breeze, but the first few times it’s easy to misconfigure something. If you’re not connecting to your database, here are a few common reasons why:

1- Your Lambdas or RDS aren’t assigned to a subnet in the same VPC

Resolution: in the Lambda Designer view, scroll down to the VPC and Security and select the correct VPC and subnets; also, go to your RDS’s details and if it’s not in the correct VPC then Modify the RDS instance so that it’s in your custom VPC and the public subnet.

2- Your RDS’s security group is not allowing access to the RDS

Resolution: go to the RDS dashboard, select your RDS, then click the link to the security group and add your Lambda Security Group to the Inbound Rules for MYSQL/AURORA traffic.

3- You didn’t add the proper environment variables to your Lambda to access your RDS

Resolution: in the Lambda Designer view, scroll under your function code to add environment variables.

4- Your Lambda code is incorrect

Resolution: debug your code

5- Can’t connect to your RDS at all

Resolution: make sure you deployed the RDS in the public subnet, that the public subnet has a route targeting the Internet Gateway, and that the VPC has DNS Resolution and DNS Hostnames enabled

Adding Functionality to Lambdas

If you need your Lambdas to access the internet, including accessing AWS apis or using the AWS SDK, then you’ll need to configure those two private subnets to access the internet. Since Lambdas can only be deployed in private subnets, they won’t have a route on their route table to the internet gateway, but they will need a route to a NAT Gateway, which provides the Lambdas a public IP address and routing to the Internet Gateway to access the outside world. We’re not going to run through that set up in this tutorial since this was all about how to connect Lambdas to an RDS inside a VPC.

This is just the start of your learning of VPCs, but I hope you’re satisfied with your accomplishment.

Please let me know if you have any questions or comments.

Thanks!

--

--

Luke Miller

Working towards master-status for all things front-end web development