SSL connection, with wildcard domain and direct IP through A DNS field

Hi!

I’m currently using pgo to access a production Postgres Database hosted on Render. That database should be accessed using SSL. I tried multiple configurations, but can’t get it to work.

With more details, pgo allows to configure the SSL options to pass to the SSL client, and will try to establish a secured connection with the DB. On Render, the database has an address looking like [database-id].frankfurt-postgres.render.com, with a correct SSL certificate, issued for *.frankfurt-postgres.render.com. I understand it’s a wildcard, so in my setup, I used the following SSL options: [{verify, verify_peer}, {cacerts, public_key:cacerts_get()}, {customize_hostname_check, [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}]}], thinking it would solve my problem.
Unfortunately, that doesn’t work, because I’m in a case not handled by pkix_verify_hostname_match_fun, because that function match specifically for {dns_id, _}, {dNSName, _} — and when digging for [database-id].frankfurt-postgres.render.com, the DNS returns a A field, pointing directly to an IP.
To make sure I was looking in the correct direction, I tried to add some logging, by writing something like this:

{customize_hostname_check, [{match_fun,
  fun(ReferenceId, PresentedId) ->
       erlang:display(ReferenceId),
       erlang:display(PresentedId),
       default
  end}]}

And I got something like (added newlines to improve readability):

{ip,{W,X,Y,Z}}
{dNSName,"*.aws-eu-central-1-1-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"*.frankfurt-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"*.replica-cyan.aws-eu-central-1-1-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"*.replica-cyan.frankfurt-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"aws-eu-central-1-1-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"frankfurt-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"*.aws-eu-central-1-1-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"*.frankfurt-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"*.replica-cyan.aws-eu-central-1-1-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"*.replica-cyan.frankfurt-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"aws-eu-central-1-1-postgres.render.com"}

{ip,{W,X,Y,Z}}
{dNSName,"frankfurt-postgres.render.com"}

My hypothesis is that I’ll have to write a custom matcher for a specific case like this? Or am I missing something? Is there any simple way to check the validity of the certificate (which is valid) in a simple way?

2 Likes

The Postgres wire protocol starts out as a TCP connection that gets upgraded to use TLS after some initial plaintext exchange. This means the handshake is started by passing the open TCP socket to the ssl module, instead of the destination host and port. The only thing the ssl module knows about the peer at this point is their IP address.

If you were to add the server_name_indication option to the ssl options and pass the hostname you are connecting to, ssl will use that name when looking for a match in the server’s certificate.

Not sure why pgo doesn’t add this parameter automatically, based on the hostname it was asked to connect to in the first place. Perhaps if you specify custom options you take responsibility for all of them and pgo won’t touch them.

3 Likes

Thanks a lot! Everything is working with the option! There’s an open issue with pgo to have better SSL defaults. I suppose this will be a solved problem in the future. :slightly_smiling_face: