Guide: Configuring r2dbc + Flyway in Spring Boot to Postgres with enforced TLS/SSL
The title’s a bit of a mouthful, but I wanted to write this quick snippet as both a reminder
to myself in case I ever need to do this again, or in case anybody else is in the same situation
and wondering how to get the Spring Boot application.yaml
config wired up to always verify the
DB server’s TLS cert on startup when using r2dbc (Spring’s reactive programming framework),
along with a database migrator like Flyway.
tl;dr: A contrived example
In this example, we’re pointing our spring boot application at a managed postgres instance running on Digital Ocean, and we’d like flyway migrations to run on startup automatically.
Raw credentials in application.yml file (for illustrative purposes only)
Don’t actually do this for production, use environment variables like in the second example, the below example here is to help illustrate the specific bare minimum required to get this all wired up properly.
Basically, the salient portion of this (and probably the reason why you’re here) looks like:
|
|
The recommended way with environment variables
|
|
Verifying the behavior
If you’d like to verify that your application actually is connecting correctly, you can run the following commands to check:
Connect to the remote DB using the CLI
1 2 3 4 5 6 7 8
# Run from the src/main/resources directory psql -h managed-db-at.digital-ocean.com \ --set=ssl=true \ --set=sslmode=verify-full \ --set=sslrootcert=db/certs/digital-ocean-2023-q1-db-cert.crt \ -p 25060 \ -U your-db-service-username-here \ -d home
Then run this command after giving the password and logging in:
1 2 3 4 5 6
SELECT * FROM pg_stat_ssl; -- Or, if you want info on the client IP as well SELECT datname, usename, client_addr, ssl, version, cipher, bits FROM pg_stat_ssl JOIN pg_stat_activity ON pg_stat_ssl.pid = pg_stat_activity.pid;
Which looks like the following after I triggered a DB read in my Spring Boot application:
That’s basically it! If you’re interested in more details of everything above, feel free to read down below.
Diving a bit deeper with an example
At the end of the day, what we’re trying to do at a very high level looks something akin to this:
However, the devil’s in the details, and if you’re operating on sensitive data, you’re probably looking to have this data be at least encrypted in transit, if not also at rest. Because of that, we now have to complicate our service diagram a bit now.
For the purposes of this post, we’ll be talking about that last arrow (step 3 in the diagram) coming from our Spring Boot services to the Postgres database.
Some definitions
r2dbc
: Spring’s newish (released ~2020 and has a lot of support) framework to work with reactive programming in the Java/Spring/Spring Boot ecosystemflyway
: A mechanism to run database migrations automatically against the database, which essentially keeps track of the “versions” of your data object model as it changes and evolves over time.TLS
orSSL
: A mechanism for two parties to communicate in a secure manner while preventing eavesdropping or man in the middle attacks through the use of public key cryptography. TLS is actually the name of the protocols in use in modern-day web applications, while SSL references to old and insecure protocols that are out of date. While it’s more accurate to say that we’re securing communication between our Spring Boot application with TLS when talking to the database, you may see references to it as SSL, such as in the jdbc parameters above (e.g. withsslmode
,ssl
, andsslrootcert
)postgres
: An open source relational database that’s in widespread use, and is time-tested, performant, and generally a pleasure to work withDigital Ocean
: A cloud offering that’s generally pretty developer-friendly, and has nice abstractions to help trade a bit of money for the sake of convenience.Supabase
: Another cloud offering
What we just did with the above snippet
If you transplant the above snippet into a new Spring Boot application that utilizes r2dbc and flyway, it should Just Work™ to force the connection to always use TLS to communicate when making calls to the postgres database.
Here, we’ll be presuming to use a managed cloud offering for postgres databases, with examples from both Digital Ocean and Supabase, however the above steps could be pretty generalizable to any other public cloud offering for managed postgres databases.
Getting the .crt file from Digital Ocean
Getting the .crt file from Supabase
Putting this all together
Finally, you’ll need to make the downloaded .crt public key(s) referencable
by both Spring Boot r2dbc configuration parameters, and the flyway jdbc
connection string. In order to do that, just move those .crt files to the
src/main/resources
directory somewhere, and you’re now good to go!