I’m using a PostgreSQL database running on Amazon RDS for a new product I’m working on. The web service that will be connecting to the database is written in Java, using Ratpack. Since my web service is not running on EC2, I had to ensure that the Postgres instance had a public IP address, and that it only accepted SSL connections.

It took a bit of fiddling to figure out what the right setup was, so I figured I’d write it up.

Configure RDS

The RDS documentation is pretty clear on how to set up the Postgres instance to only accept SSL connections.

First, create a parameter group:

Give it a name:

Note that “Group Name” can’t have spaces in it.

Now select the group you just created, and click on “Edit Parameters”:

Now search for “rds.force_ssl”, and modify the value of the parameter to 1.

Now navigate to the instances tab, select your instances, click on the “Instance Actions” button, and then select “Modify”.

Next, in the “Database Options” section, select the “DB Parameter Group” you just created. Then continue and modify your instance.

You now need to reboot your instance:

You’re now done configuring your RDS instance to only accept SSL connections.

Certificate

Now to connect to your database from the JVM, you’ll have to first add RDS’ certificate to your keystore.

To do this, first download the certificate from Amazon. Once you’ve got it downloaded, you need to convert it into a format that can be imported by your keystore.

To do that, run: openssl x509 -outform der -in rds-combined-ca-bundle.pem -out rds-combined-ca-bundle.der.

Once that’s done, you can import it into your keystore.

On macOS, run sudo keytool -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre/lib/security/cacerts -alias rds_postgres -import -file rds-combined-ca-bundle.der.

On Ubuntu, run: sudo keytool -keystore /usr/lib/jvm/java-8-oracle/jre/lib/security/cacerts -alias rds_postgresql -import -file rds-combined-ca-bundle.der.

You’ll be prompted for a keystore password. Enter changeit.

Note that your path to JDK may be different - modify it as necessary.

JDBC

The final step is configuring JDBC to use SSL. Here’s how I’m doing that:

    @NotNull
    private static final PGPoolingDataSource dataSource;

    static {
        dataSource = new PGPoolingDataSource();
        dataSource.setDataSourceName("<data source name>");
        dataSource.setDatabaseName(DBConfiguration.Name);
        dataSource.setServerName(DBConfiguration.HostName);
        dataSource.setPortNumber(DBConfiguration.PortNumber);
        dataSource.setUser(DBConfiguration.UserName);
        dataSource.setPassword(DBConfiguration.Password);
        dataSource.setInitialConnections(DBConfiguration.NumConnections);
        dataSource.setMaxConnections(DBConfiguration.NumConnections);
        dataSource.setSsl(true);
    }

    @NotNull
    public static Connection getConnection() throws DBException {
        try {
            return dataSource.getConnection();
        } catch (final SQLException e) {
            throw new DBException(e);
        }
    }

Note the call to dataSource.setSSL(true).

Et voilà, you’re all set!