Josh Kupershmidt
Josh Kupershmidt

Reputation: 2710

Runtime detection of SSL support in the pg gem

We have some Ruby code which does something like:

require 'pg'

# Create a remote Postgres database instance, and wait
# until it's online, then try to connect:
conn = PG::Connection.new(
    ... params ...
    sslmode: 'require')

The important part is that the remote Postgres instance is configured such that SSL usage is mandatory (e.g. like this) -- the sslmode: 'require' in the client code is redundant.

This works fine on many developer machines, but some developers are noticing that they get some error like:

 FATAL:  no pg_hba.conf entry for host "...", user "...", database "...", SSL off (PG::ConnectionBad)

and the root cause seems to be that their pg gem does not actually have SSL support.

My question: is there any way to determine if the pg gem does in fact have SSL support, without actually trying to connect to a server requiring SSL? (It would be much better if we could detect the problem right away, instead of waiting until a remote Postgres instance has been created, and only then discovering the problem.)

My first thought was to check a method on the pg gem such as init_openssl, but the documentation claims:

When SSL support is not compiled in, this function is present but does nothing.

and this behavior appears to be the same whether SSL support is present or not:

2.3.1 :002 > PG.init_openssl(true, true)
 => nil 

Environment info: ruby 2.3 on recent OS X, pg gem 0.19.0, various versions of libpq

Upvotes: 1

Views: 615

Answers (1)

anothermh
anothermh

Reputation: 10526

First, make sure Ruby is compiled with OpenSSL support:

ruby -r rbconfig -e 'puts RbConfig::CONFIG["configure_args"]'
'--prefix=/Users/foo/.rvm/rubies/ruby-2.6.0-preview2' '' '--with-opt-dir=/usr/local/opt/libyaml:/usr/local/opt/readline:/usr/local/opt/libksba:/usr/local/opt/[email protected]' '--disable-install-doc' '--enable-shared' 'build_alias=' 'host_alias=' 'target_alias=' 'CC=gcc'

Make sure openssl is somewhere in the --with-opt-dir output. Alternatively, you can check with this:

ruby -r openssl -e 'puts OpenSSL::OPENSSL_LIBRARY_VERSION'
OpenSSL 1.1.1  11 Sep 2018

Next, locate your pg_ext.bundle. The location of this will vary depending on how you install Ruby and gems, but if you're using RVM it's fairly straightforward to locate in ~/.rvm/gems. For example, it is located here for me:

~/.rvm/gems/ruby-2.6.0-preview2/gems/pg-1.1.3/ext/pg_ext.bundle

Now run otool -L to find the libraries it is linked against:

otool -L /Users/foo/.rvm/gems/ruby-2.6.0-preview2/gems/pg-1.1.3/ext/pg_ext.bundle
  /Users/foo/.rvm/gems/ruby-2.6.0-preview2/gems/pg-1.1.3/ext/pg_ext.bundle:
  /Users/foo/.rvm/rubies/ruby-2.6.0-preview2/lib/libruby.2.6.dylib (compatibility version 2.6.0, current version 2.6.0)
  /usr/local/opt/postgresql/lib/libpq.5.dylib (compatibility version 5.0.0, current version 5.11.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)

Now run otool -L against the libpq dylib listed in the above output to see what it's linked against:

otool -L /usr/local/opt/postgresql/lib/libpq.5.dylib
  /usr/local/opt/postgresql/lib/libpq.5.dylib:
  /usr/local/opt/postgresql/lib/libpq.5.dylib (compatibility version 5.0.0, current version 5.11.0)
  /usr/local/opt/openssl/lib/libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
  /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
  /System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos (compatibility version 5.0.0, current version 6.0.0)
  /System/Library/Frameworks/LDAP.framework/Versions/A/LDAP (compatibility version 1.0.0, current version 2.4.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)

As long as it's linked against libssl and libcrypto, the installed pg gem should support OpenSSL as well.

Upvotes: 1

Related Questions