A Curious Tale of Rust TLS and Postgres in the Cloud

Peter Nehrer
Ecliptical Software Inc.
3 min readAug 3, 2020

How to Connect Securely to Amazon RDS for PostgreSQL using Tokio and Rustls

Recently I ran into a curious problem while working on a piece of asynchronous database code for a micro-service written in Rust — it looked something like this:

This particular module used Tokio Postgres along with Deadpool Postgres — part of my favorite Rust stack — to interact with an AWS RDS for PostgreSQL database. Of course, everything worked great when I ran it against a Postgres instance deployed in my local Docker container — the Deadpool documentation contains easy-to-follow examples that can get you going in minutes.

I knew I’d have to support connecting to the database securely in order to deploy the code to production — the deployment policy requires (as it should!) that all connections to RDS instances use TLS. By default, the Tokio Postgres crate supports plain-text connections to help you get started, but luckily also outlines steps to enable TLS.

To be honest, I was a bit crestfallen when I didn’t see Rustls listed as one of the supported methods; only (effectively) OpenSSL. After all, there are many good reasons to use Rustls, in addition to the fact that it was already part of my stack (e.g., both Reqwest and Warp support it) and would allow me to crank out statically linked binaries more easily.

Never fear — the amazing Rust community has your back! A quick search through crates.io produced the tokio-postgres-rustls crate, which was exactly what I needed; after a small addition to my configuration and database connection pool setup, I was on my way:

Reality Bites

As luck would have it, after pointing my Postgres client configuration to the RDS instance, I was met with the unpleasant surprise I had mentioned earlier — BadCertificate error! Wha… wha… whad’ya MEAN??

I must admit — in all my excitement I only skimmed through tokio-postgres-rustls documentation, and didn’t even peek at rustls, since the basic configuration example happened to compile just fine (yikes!). After a stern mental self-admonishment I carefully scanned Rustls’s Getting Started example and sure enough, I discovered that I may have missed a step:

Of course! Rustls (probably) doesn’t come with any pre-configured root certificates! That would make sense — Rust libraries tend to defer use-case-specific decisions to the user — why include files/bytes that may not even be needed?

Take Two

Ok — new dependency included, Mozilla’s trusted root certificates added. That must have been the problem! Alas, the same error:

“This means war!”, I thought to myself. Rather, it meant that I had to read the documentation more carefully — a little bit of sleuthing revealed that AWS utilized their own/separate root certificates for their RDS instances. This, it turns out, is also helpfully indicated in the database instance details in RDS console — if you know what to look for!

Certificate authority rds-ca-2019
Clipping of the Connectivity & security section

Third Time’s a Charm

After downloading the requisite root certificate and adding it to my database pool’s TLS configuration:

Success!

Conclusion

There are many great libraries that help you build modern micro-services and native cloud applications in Rust. If you ever find yourself working with PostgreSQL, use Tokio Postgres with Deadpool to build responsive, scalable applications with Rust’s powerful asynchronous constructs.

To secure your client connection, use Rustls; however, make sure it is configured properly either with Mozilla’s trusted root certificates or your service provider’s own root certificates!

To try the approach outlined in this article, check out the demo project hosted on GitHub.

--

--