TLS setup on Postgres 15 – Common Practice

Enterprise PostgreSQL Solutions

Comments are off

TLS setup on Postgres 15 – Common Practice

1.0 Introduction

TLS is one of the most commonly used security protocol in most applications but also least understood. In this blog, I will briefly explain the concept of TLS and how it can be configured to Postgres version 15 compiled with compatible OpenSSL library.

2.0 PostgreSQL Server Side Settings

These are the TLS settings available in postgresql.conf related to TLS. Note that these parameters start with prefix SSL, which is a term used interchangeably with TLS (which is a newer term). Both refer to the same thing.

#ssl = off
#ssl_ca_file = ''
#ssl_cert_file = 'server.crt'
#ssl_crl_file = ''
#ssl_crl_dir = ''
#ssl_key_file = 'server.key'
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
#ssl_min_protocol_version = 'TLSv1.2'
#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
#ssl_passphrase_command = ''
#ssl_passphrase_command_supports_reload = off

Most of the time, you just need to fill in ssl, ssl_ca_file, ssl_cert_file, ssl_key_file and possibly ssl_passphrase_command. For example:

ssl = on
ssl_ca_file = '/home/user/cert/cacert.pem'
ssl_cert_file = '/home/user/cert/server.pem'
ssl_key_file = '/home/user/cert/server.key'
ssl_passphrase_command = 'echo passphrase'

These basic TLS parameters tell Postgres that you would like to enable TLS on your server and provide paths to Certificate Authority (CA) certificate file, entity certificate file and a private key file. These 3 files are normally referred as X509 certificates and are mainly used to guarantee trust between a client and a server.

the CA certificate file (ssl_ca_file) is the root of trust and you can use openssl to generate one for your organization and use it to create and sign other entity certificates for your application to use.

the entity certificate (ssl_cert_file) and private key (ssl_key_file) form a pair, in a sense that the certificate itself contains a public key while the private key file contains the private key. These keys are used for asynchronous authentication during TLS handshake. The entity certificate is normally signed with the same CA certificate file configured in ssl_ca_file such that it can be trusted. Both the private key and entity certificate files can also be generated and signed using openssl

ssl_passphrase_command is used to get a passphrase to decrypt the ssl_key_file if it is encryped when generated.

Refer to this blog post here about how to use openssl to create and sign these certificate files and also a short explaination on the rest of TLS related parameters that are left default mostly.

3.0 PostgreSQL Server Side pg_hba Settings

In addition to the main settings above, you also need to configure pg_hba.conf to restrict which connection requires TLS and which does not. These settings are normally more complicated to setup for most people. With TLS enabled, there are potentially 2 authentications involved; one is involved within TLS handshake (to verify the trust between client and server), the other is involved within PG to check if a connectiing user is authrorized.

Consider this example:

hostssl   mydatabase myuser       192.168.1.0/24     trust
hostssl   mydatabase myuser2      192.168.1.0/24     trust clientcert=verify-ca
hostssl   mydatabase myuser3      192.168.1.0/24     password clientcert=verify-ca
hostssl   mydatabase myuser4      192.168.1.0/24     cert clientcert=verify-ca
hostnossl mydatabase myuser5      127.0.0.1/32       trust
hostssl mydatabase myuser 192.168.1.0/24 trust

means as long as myuser uses TLS to connect within 192.168.1.0 network, myuser will be given access to mydatabase right away

hostssl mydatabase myuser2 192.168.1.0/24 trust clientcert=verify-ca

means that if myuser2 uses TLS to connect within 192.168.1.0 network, myuser2 is required to provide its own X509 certificate and the server will verify client certificate using the CA certificate configured in ssl_ca_file. If the certificate can be trusted, then myuser2 will be given access to mydatabase

hostssl mydatabase myuser3 192.168.1.0/24 password clientcert=verify-ca

means that if myuser3 uses TLS to connect within 192.168.1.0 network, myuser3 is required to provide its own X509 certificate and the server will verify client certificate using the CA certificate configured in ssl_ca_file. If the certificate can be trusted, then myuser3 will be prompted for a password. If the password matches then myuser3 will be given access to mydatabase

hostssl mydatabase myuser4 192.168.1.0/24 cert clientcert=verify-ca

means that if myuser4 uses TLS to connect within 192.168.1.0 network, myuser4 is required to provide its own X509 certificate and the server will verify client certificate using the CA certificate configured in ssl_ca_file. If the certificate can be trusted, then PG will read the Common Name (CN) field in the client-provided certificate and check if it matches the connecting user’s username, if it matches, then user4 will be given access to mydatabase

hostnossl mydatabase myuser5 127.0.0.1/32 trust

means that if myuser5 does not use TLS connect within 127.0.0.1 localhost, myuser5 will simply be given access to mydatabase

4.0 PostgreSQL Client Side TLS Options

Most of the time, when a psql client connects to a Postgres server with TLS enabled, it is the psql client who will verify the entity certificate sent by Postgres server (configured in ssl_cert_file in postgresql.conf). In otherwords, the client verifies the server. Of course, the psql client also need to have a copy of the CA certificate (or a sub CA certificate signed by a common root CA) that the client can use to verify the server’s certificate during handshake.

This is similar to a user connecting to a https website on a browser. The web server, for example, google.ca will send its server certificate to your browser during handshake, the browser will verify this certificate using many of the built-in CA certificates that come with your browser. If the certificate can be trusted, it allows you to connect. If not, it will give you a warning page saying “Your connection is not private” and you have a choice to proceed or not proceed.

With psql client, you can specify a certificate to send to the server and a CA certificate to use to verify server’s certificate.

psql -U myuser2 -h 192.168.1.123 -d "sslmode=verify-ca dbname=mydatabase sslrootcert=/home/user/cert/cacert.pem sslcert=/home/user/cert/client.pem sslkey=/home/user/cert/client.key"

This means that psql client will verify server’s certificate using its CA certificate specified in sslrootcert. Since the server also requires the client to provide a certificate (because of clientcert=verify-ca in pg_hba.conf), the client will send the certificate specified in sslcert to the server for mutual authentication.