AWS Lambda VPC Networking

Let’s face it, AWS networking isn’t exactly the most exciting thing in the world. Often, I’ve had a Lambda function that needs to connect to a database inside my VPC while still allowing connections to the internet. To put it kindly, configuring AWS networking to handle this common situation is quite involved. This article is short manual to get it done.

  1. Create a public subnet
  2. Create a NAT gateway
  3. Create private subnets
  4. Configure VPC gateway endpoints
  5. Configure the Lambda function

Create a public subnet

Subnets divide the range of IP addresses available to a VPC into sub-sections, defined by CIDR blocks. For example, 172.31.0.0/16 is a CIDR block representing 65,536 addresses from 172.31.0.0 to 172.31.255.255.

A subnet can be referred to as public or private. A public subnet has its traffic routed through an internet gateway, whereas a private subnet does not. An internet gateway is a VPC component that allows communication to the internet. The default VPC, automatically created for your AWS account, comes pre-configured with a public subnet in each availability zone.

Subnets have a route table that describes how its network traffic is directed. The route table of a public subnet is shown below.

Route table of a public subnet

In this example, all traffic destined to addresses within the VPC is kept local to the VPC. All other traffic (0.0.0.0/0) is sent to an internet gateway.

To create a public subnet:

  1. Navigate to the VPC service on the AWS console.
  2. Create a route table called rt-to-igw. Add a route to direct non-local traffic to an internet gateway, as in the example above.
  3. Create a new subnet called lambda-public-subnet-1.
    • Choose the same VPC as that of the AWS resources you want to connect to.
    • Specify a CIDR block that the subnet will own, for example, 172.31.16.0/24 (256 addresses). There cannot be any overlap with the blocks owned by other subnets, so you may need to reallocate the addresses used elsewhere.
  4. After the subnet is created, change its route table to the one we created — rt-to-igw.

Create a NAT gateway

EC2 instances can be assigned a public IP address. This is what allows you to, for example, SSH into it from your development machine, and to communicate with the outside internet. However, Lambda functions cannot be directly assigned a public IP address. Instead, we can use a Network Address Translation (NAT) gateway to enable a Lambda function to communicate with the internet.

  1. Navigate to the VPC service on the AWS console and choose “NAT Gateways”.
  2. Create a new NAT gateway. Choose lambda-public-subnet-1 for its subnet and assign it an elastic IP.
  3. After the NAT gateway is created, name it lambda-nat-1.
  4. Create a new route table called rt-to-lambda-nat-1. Add a route directing all non-local traffic — 0.0.0.0/0 — to the NAT gateway lambda-nat-1.

Be aware that a NAT gateway has associated costs — an hourly rate and a cost per GB of data sent through it.

Create private subnets

The Lambda function will operate within a private subnet whose route table directs non-local traffic to the NAT gateway we created in the last section. AWS recommends that Lambda functions in a VPC be assigned to at least two subnets in different availability zones for higher availability.

Next, create two private subnets which direct external traffic to the NAT gateway:

  1. Navigate to the VPC service on the AWS console and choose “Subnets”
  2. Create two new subnets called lambda-private-subnet-1 and lambda-private-subnet-2.
    • Choose the same VPC as that of the AWS resources you want to connect to.
    • Specify a CIDR block for each subnet, for example, 172.31.17.0/24 and 172.31.18.0/24
  3. After the subnets are created, change their route tables to rt-to-lambda-nat-1, which we created in the last section.

Configure VPC gateway endpoints

This last step is optional, but recommended to reduce the NAT gateway’s data-transfer costs. The route table assigned to your private subnets should resemble the following:

Private subnet route table

It directs all external traffic to the NAT gateway, including any traffic the Lambda function sends to S3 or DynamoDB. Since the NAT gateway charges per-GB of data processed, it could be expensive to use these services with our current network configuration. However, we can use VPC Gateway Endpoints to bypass the NAT on traffic going to S3 and DynamoDB. There is no charge for data passing through these endpoints, so your AWS bill will be lower.

  1. Navigate to the VPC service on the AWS console and choose “Endpoints”.
  2. Create a new endpoint.
  3. Select the S3 service endpoint, whose name resembles com.amazonaws.<REGION>.s3.
  4. Associate this endpoint with the route table rt-to-lambda-nat-1 (the private subnets’ route table).
  5. Repeat steps 2–4 for the DynamoDB endpoint.

After completing these steps, the route table rt-to-lambda-nat-1 should resemble the following:

Route table with gateway endpoints for S3 and DynamoDB

Configure the Lambda function

Finally, configure the Lambda function to use the private subnets:

  1. Navigate to your Lambda function in the AWS console.
  2. Under the “Network” pane, choose the VPC that you have been using throughout this guide for the Lambda function.
  3. Choose the subnets lambda-private-subnet-1 and lambda-private-subnet-2.
  4. For the security group, depending on your use-case, choose one which allows access to your RDS instance, Redshift cluster or ElastiCache instance.

Conclusion

Configuring a Lambda function to access resources in a VPC while still allowing it to talk to the internet is quite involved, as you have seen. But, this guide should provide you with a working solution that can be adapted to your needs. The VPC network that we configured is depicted below.

VPC network diagram for the Lambda function

In summary, the public subnet lambda-public-subnet-1 directs traffic to an internet gateway through the route table rt-to-igw. We created a NAT gateway lambda-nat-1 inside the public subnet. The private subnets lambda-private-subnet-1 and lambda-private-subnet-2 direct their external traffic to the NAT gateway through the route table rt-to-nat-lambda-nat-1. The Lambda function is configured to live within the private subnets.

Some further resources you may find helpful: