Understanding the Networking Basics of Lambda to RDS Connectivity
Tags: aws, rds, lambda, network
Published: 2023-04-07 22:18:15

When it comes to connecting AWS services that are managed by the cloud service providers (e.g., Lambda, RDS, DynamoDB), we tend to think everything is connected under the hood and all we have to do is to create inbound rules on the security group or grant permissions. Generally speaking, it usually works out fine when we use the default VPC. If you're new to VPC, private/public subnets, and route table concepts, feel free to head over my other blog post here: https://dev.to/bayupw/learn-and-build-aws-vpc-networking-for-network-engineers-1fch

Being a network guy, I'm always curious about how things work on the networking side. In this blog post, I'll dive into some basics networking and relevant key concepts when connecting AWS Lambda function to RDS. By the end of this post, hopefully you'll have a good understanding on how to connect these two services and how to secure them from a network & security point of view especially if you're following the [Andrew Brown's Free AWS Cloud Project Bootcamp](https://www.linkedin.com/posts/andrew-wc-brown_welcome-to-the-free-aws-cloud-project-bootcamp-activity-7029276209087750145-ete2/). So, let's get started!

## Amazon RDS Networking
As ChatGPT said below, RDS is a managed service from AWS where we just provision a Database and the service will be accessible once provisioning is completed. ![Amazon RDS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yxglr8s4230mebw5bdbe.png) But how do we connect to it? Does it run on like a "Public Zone" of AWS or is it going to be on provisioned in a VPC? Let's take a look.

If you go ahead and provision an RDS, you'll notice that there's a 'Connectivity' section where we need to choose a VPC and supply or select other relevant parameters related to network & security.
![RDS Connectivity Section](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4y7xj3b6ghlb5zxlr28w.png) When a service need to run in a VPC, this is normally a good indicator that the service will create a network adapter - [ENI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html) in the VPC. Notice the note: "_After a database is created, you can't change its VPC._" In a case where you need to change your RDS into another VPC for whatever reason, you may need to perform a migration instead. Here are some useful links on RDS migration to a different VPC/account:
- [Migrate an Amazon RDS DB instance to another VPC or account
](https://repost.aws/knowledge-center/change-vpc-rds-db-instance)
- [How do I change the VPC for an Amazon RDS DB instance?
](https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/migrate-an-amazon-rds-db-instance-to-another-vpc-or-account.html)
- [Updating the VPC for a DB instance
](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.VPC2VPC.html)

### DB Subnet Group
After choosing a VPC, the next required parameter would normally be the subnet or subnet ID. But not quite with RDS, instead it is asking for something called [DB Subnet Group](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html). As per the name, DB Subnet Group is essentially a logical grouping of subnets in at least 2 AZs - it will throw an error if you try to create a DB Subnet Group with in 1 AZ.
![DB Subnet Group Error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/su1fw48mgjfidatrlcv4.png) When deploying a [Multi-AZ RDS Deployment] (https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html), additional IP will be created on the other AZ(s) for the standby DB instance(s). Note: while you can use IP address to connect to the DB instance, the IP might change during failover and therefore it is recommended to use the DNS name to connect to the DB.

The DB Subnet Group typically consists of private subnets which don't have a default route towards the AWS Internet Gateway as you probably don't want your RDS to be accessible from the Internet in most cases. But if you do, then you will need to have public subnets in your DB Subnet Group.

### Public Access
The next part is the 'Public access' parameter which needs to be aligned with the DB Subnet Group configuration. When set to No, the provisioned [ENI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html) will only have Private IP.
![RDS with Public access set to Yes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8pqwls0krhqicz5n9010.png) If you try to access it from the Internet, your PC or a cloud development environment such as [Gitpod](https://www.gitpod.io/) that would obviously not be accessible.
However, if you set it to Yes, the [ENI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html) will also have a Public IP and a Public hostname (DNS endpoint). This settings can be changed without the need to re-provision the RDS which is quite handy.
![RDS with Public access set to Yes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1tcnlb23mmsyzhajsbjo.png)

### VPC Security Group
Similar to an EC2 instance with ENI, access to RDS from network & security point of view can be controlled through a VPC Security Group rules. This can be an existing Security Group (e.g., default Security Group) or a [new Security Group](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Tutorials.WebServerDB.CreateVPC.html#CHAP_Tutorials.WebServerDB.CreateVPC.SecurityGroupDB). A new dedicated Security Group for RDS might be easier to manage as we would know any rules being defined will be for the RDS access.

In my case, I'll set the 'Public Access' to Yes and I'll go ahead and create a new Security Group and add inbound rules for my public IP to [Connect to PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ConnectToPostgreSQLInstance.html).
![Security Group Inbound rules](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/woj09tzd352fg83nx00r.png) As per screenshot below, I can connect to the PostgreSQL using a Database Client UI or `psql` CLI using Connection URI: `postgresql://<user>:<password>@<rds-endpoint>:<port>/<db-name>`
![Connect to PostgreSQL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fj16o1epm2wg8aa4r81o.png)

### RDS Networking Diagram
A picture says a thousand words and I love to draw everything when it comes to technical stuff. Let's take a look at all the components we've discussed so far in a technical diagram format.
![RDS Networking Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qf0zgctgos5zhlhojl5w.png)

## AWS Lambda Networking
Now that we have covered off RDS Networking, let's take a look at what we'll need to spin up a Lambda function from networking point of view so we can have it connected to RDS.
![Lambda](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rw6tpiphlcqelhykh36w.png) In this case, I will create a [Lambda function with python](https://gist.github.com/bayupw/33784908af56e4a495ecca56ee553051) to do database schema load into the PostgreSQL. Note: I'm storing connection URI on the environment variable for demo purpose. For production, you may want to use something like [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html) and Lambda dynamically fetch secrets from Secrets Manager. There's a good article in AWS blog that talks about using [AWS Lambda function to run post-database creation scripts](https://aws.amazon.com/blogs/database/automate-post-database-creation-scripts-or-steps-in-an-amazon-rds-for-oracle-database/). 

As per the [AWS Lambda docs under networking section](https://docs.aws.amazon.com/lambda/latest/dg/foundation-networking.html), Lambda function always runs inside a VPC owned by the Lambda service and by default, is not connected to a VPC in your account. There's a section in the Lambda configuration where you can edit VPC related configuration and it requires certain IAM permissions to be able to create and manage network interfaces to create the HyperPlane ENI as per the [AWS Lambda doc](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html).

I'll go ahead and choose a VPC, 2 subnets and a new dedicated Security Group for the Lambda ENI.
![Lambda VPC configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wqno0o70bss6a84f9cdm.png) The configuration will let you choose single subnet, but it will throw a warning that AWS recommends choosing 2 subnets for HA.
![Lambda subnets warning](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1q7igxcblh1822ih7q7c.png) Once the configuration is updated, you will see an ENI with a private IP. 
![Lambda ENI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9pwg0oicop5dtn764k9x.png)

## AWS Lambda and RDS Networking Diagram
With the Lambda connected to VPC, here's the updated diagram for single AZ.
![AWS Lambda and RDS Networking Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wqqjxr0z31n3ke7trnn7.png) You can use the default Security Group for both RDS and Lambda and everything will just work. But, since I use dedicated Security Groups for each of the components, I will need to add inbound rules on the RDS Security Group to allow Lambda to connect. 
![RDS Security Group rule](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2c0cb0ezf24iu52wvef.png) While technically we can use IP address as the source, we want to allow all of the Lambda ENIs and the IP address may change in the future (added/removed), so it is better to use the Security Group ID of the Lambda as per the screenshot.

## Test Lambda to RDS Connectivity
Now everything is ready, let's test this out by invoking the Lambda function. I'll do this via aws cli: `$ aws lambda invoke --function-name <function name> response.json`
![Lambda Invoke](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ad9s7fgsxwfeaqogi29.png) Let's double check the CloudWatch logs as well.
![Lambda CloudWatch logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjgrmdia5ev6cwngosxh.png)

Last thing is to check on the database itself to see if the schema has been successfully loaded by the Lambda function.
![Schema Load Check](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/53l0gckbaz4uubcnfoxy.png)

Everything looks to be working as expected! You may be wondering, will Lambda overload the RDS connectivity in this scenario? There's actually another AWS service that would be useful for this - Amazon RDS Proxy, see [Using Amazon RDS Proxy with AWS Lambda
](https://aws.amazon.com/blogs/compute/using-amazon-rds-proxy-with-aws-lambda/)

## CloudFormation Template
Want to test it out yourself? Feel free to use this [Lambda RDS Demo CloudFormation Template
](https://gist.github.com/bayupw/9d9e4af5d8317d3da27d357221f290d9) Note: this CFN template is for demo purposes only as it will output username, password, Database Connection URI which may be sensitive from security point of view.

## Conclusion and Important Key Points
As we can see, understanding cloud networking & security and their components is crucial when building cloud services, whether they're PaaS or managed. This is useful not just for planning or deployment, but also for troubleshooting, since we often need to figure out what are the building blocks and connectivity during a debug session. 

Here are some additional links that I find really useful in regards to connecting Lambda to RDS:
https://blog.thundra.io/can-lambda-and-rds-play-nicely-together
https://docs.aws.amazon.com/lambda/latest/dg/services-rds-tutorial.html.

I hope you enjoy reading this post and feel free to reach out if I have missed anything that you feel important!