Cómo activar SSL para conexiones PostgreSQL

Por defecto, todas las conexiones PostgreSQL son inseguras, lo que puede causar problemas de seguridad cuando se ejecutan en entornos de producción de alto tráfico. El cifrado SSL garantiza que los datos transferidos no sean interceptados por nadie en medio de una conexión.

Este tutorial te enseñará a habilitar SSL/TLS para las conexiones PostgreSQL.

Requisitos previos

  • Un servidor Linux. Para nuestro tutorial, estamos ejecutando un servidor Ubuntu 22.04.
  • Un usuario sudo no root.
  • Un nombre de dominio completo (FQDN) como postgresql.example.com.
  • Asegúrate de que todo está actualizado.
    $ sudo apt update
    $ sudo apt upgrade
    
  • Pocos paquetes que necesite tu sistema.
    $ sudo apt install curl nano software-properties-common apt-transport-https ca-certificates lsb-release ubuntu-keyring -y
    

    Puede que algunos de estos paquetes ya estén instalados en tu sistema.

Paso 1 – Configurar el Cortafuegos

Antes de instalar ningún paquete, el primer paso es configurar el cortafuegos para que abra puertos para HTTP, HTTPS y PostgreSQL.

Comprueba el estado del cortafuegos.

$ sudo ufw status

Deberías ver algo como lo siguiente

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

Abre los puertos HTTP, HTTPS y PostgreSQL en el cortafuegos.

$ sudo ufw allow 5432
$ sudo ufw allow http
$ sudo ufw allow https

Comprueba de nuevo el estado para confirmarlo.

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
80/tcp                     ALLOW       Anywhere                  
443                        ALLOW       Anywhere                  
5432                       ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
80/tcp (v6)                ALLOW       Anywhere (v6)             
443 (v6)                   ALLOW       Anywhere (v6)
5432 (v6)                  ALLOW       Anywhere (v6)             

Paso 2 – Instala PostgreSQL 14

Ubuntu 22.04 incluye PostgreSQL 14 por defecto. Para instalarlo, ejecuta el siguiente comando.

$ sudo apt install postgresql postgresql-contrib

El paquete postgresql-contrib contiene algunas utilidades adicionales.

También puedes utilizar el repositorio oficial APT de PostgreSQL para realizar la instalación. Ejecuta el siguiente comando para añadir la clave GPG de PostgreSQL.

$ curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | sudo tee /usr/share/keyrings/postgresql-key.gpg >/dev/null

Añade el repositorio APT a tu lista de fuentes.

$ sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/postgresql-key.gpg arch=amd64] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'

Actualiza el repositorio del sistema.

$ sudo apt update

Ahora, puedes instalar PostgreSQL utilizando el comando mencionado anteriormente.

Comprueba el estado del servicio PostgreSQL.

$ sudo systemctl status postgresql
? postgresql.service - PostgreSQL RDBMS
     Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor preset: enabled)
     Active: active (exited) since Mon 2022-12-12 00:01:06 UTC; 19s ago
   Main PID: 3497 (code=exited, status=0/SUCCESS)
        CPU: 1ms

Dec 12 00:01:06 postgresql systemd[1]: Starting PostgreSQL RDBMS...
Dec 12 00:01:06 postgresql systemd[1]: Finished PostgreSQL RDBMS.

Puedes ver que el servicio está habilitado y funcionando por defecto.

Establece la contraseña de la cuenta postgres.

$ sudo -i -u postgres psql -c "ALTER USER postgres PASSWORD '<new_password>';"

Paso 3 – Instalar SSL

Para instalar un certificado SSL utilizando Let’s Encrypt, necesitamos descargar la herramienta Certbot. Para ello utilizaremos el instalador de paquetes Snapd. Ubuntu 22.04 viene preinstalado con Snap.

Asegúrate de que tu versión de Snapd está actualizada.

$ sudo snap install core 
$ sudo snap refresh core

Instala Certbot.

$ sudo snap install --classic certbot

Utiliza el siguiente comando para asegurarte de que se ejecuta el comando Certbot, creando un enlace simbólico al directorio /usr/bin.

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Genera un certificado SSL.

$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d postgresql.example.com

El comando anterior descargará un certificado en el directorio /etc/letsencrypt/live/postgresql.example.com de tu servidor.

Genera un certificado de grupo Diffie-Hellman.

$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096

Paso 4 – Configurar la renovación de Certbot para PostgreSQL

PostgreSQL no tiene permiso para acceder a los certificados de la carpeta Let’s Encrypt, por lo que no podemos decirle que utilice directamente los certificados de la carpeta. La alternativa es copiar los certificados en el directorio PostgreSQL, pero esto sólo funciona temporalmente, ya que caducarán y tendrás que volver a copiarlos manualmente.

El mejor método es utilizar un gancho de renovación que se ejecute automáticamente en cada renovación y realice las operaciones de copia.

Busca el directorio de datos PostgreSQL.

$ sudo -i -u postgres psql -U postgres -c 'SHOW data_directory'

Crea el archivo del gancho de renovación y ábrelo para editarlo.

$ sudo nano /etc/letsencrypt/renewal-hooks/deploy/postgresql.sh

Pega en él el siguiente código.

#!/bin/bash
umask 0177
DOMAIN=postgresql.example.com
DATA_DIR=/var/lib/postgresql/15/main
cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem $DATA_DIR/server.crt
cp /etc/letsencrypt/live/$DOMAIN/privkey.pem $DATA_DIR/server.key
chown postgres:postgres $DATA_DIR/server.crt $DATA_DIR/server.key
# only for SELinux - CentOS, Red Hat
# chcon -t postgresql_db_t $DATA_DIR/server.crt $DATA_DIR/server.key

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.

Haz que el archivo sea ejecutable.

$ sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/postgresql.sh

Paso 5 – Configurar PostgreSQL

Busca la ruta del archivo de configuración de PostgreSQL.

$ sudo -i -u postgres psql -U postgres -c 'SHOW config_file'

Abre el archivo para editarlo.

$ sudo nano /etc/postgresql/15/main/postgresql.conf

Localiza la sección Configuración de la conexión y descomenta la variable listen_address y cambia su valor a *. Asegúrate de que tiene el siguiente aspecto.

listen_address = '*'		# what IP address(es) to listen on;

Localiza la sección SSL y edita el archivo para que coincida con los siguientes valores.

ssl = on  
ssl_cert_file = 'server.crt'  
ssl_key_file = 'server.key'  
ssl_prefer_server_ciphers = on
ssl_dh_params_file = '/etc/ssl/certs/dhparam.pem'

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.

Paso 6 – Configurar la conexión PostgreSQL

Abre el archivo /etc/postgresql/15/main/pg_hba.conf para editarlo.

$ sudo nano /etc/postgresql/15/main/pg_hba.conf

Añade la siguiente línea para activar SSL para PostgreSQL.

hostssl all  all  0.0.0.0/0  scram-sha-256

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.

Paso 7 – Renovar Certificado

Ejecuta el siguiente comando para realizar una renovación forzada. Esto activará el script de despliegue que copia los certificados en la ubicación correcta para que PostgreSQL los utilice.

$ sudo certbot renew --force-renewal

Comprueba que los certificados se copian en el directorio de datos de PostgreSQL.

$ sudo ls /var/lib/postgresql/15/main/

Verás la siguiente salida que te mostrará los certificados.

base          pg_dynshmem   pg_notify    pg_snapshots  pg_subtrans  PG_VERSION  postgresql.auto.conf  server.crt
global        pg_logical    pg_replslot  pg_stat       pg_tblspc    pg_wal      postmaster.opts       server.key
pg_commit_ts  pg_multixact  pg_serial    pg_stat_tmp   pg_twophase  pg_xact     postmaster.pid

Reinicia PostgreSQL para aplicar los cambios.

$ sudo systemctl restart postgresql

Paso 8 – Prueba la conexión

Conéctate a la base de datos desde otra máquina con el cliente PostgreSQL instalado.

$ psql -d "dbname=postgres sslmode=require" -h postgresql.example.com -U postgres

Deberías ver el siguiente prompt de PostgreSQL. Estamos utilizando un cliente con PostgreSQL 14 por lo tanto, verás una advertencia sobre versiones incompatibles.

Password for user postgres:
psql (14.5 (Ubuntu 14.5-0ubuntu0.22.04.1), server 15.1 (Ubuntu 15.1-1.pgdg22.04+1))
WARNING: psql major version 14, server major version 15.
         Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=#

Esto confirma que la conexión SSL se ha realizado correctamente.

Sal del intérprete de comandos.

postgres=# \q

Si tu aplicación utiliza una cadena de conexión, utilízala con el siguiente formato para una conexión SSL.

postgres://user:[email protected]:5432/database_name?sslmode=require

Puedes cambiar el modo SSL a verify-full o verify-ca si tienes el certificado raíz de Let’s encrypt disponible en la ubicación /var/lib/postgresql/.postgresql en el lado del cliente.

Crea el directorio /var/lib/postgresql/.postgresql.

$ sudo mkdir -p /var/lib/postgresql/.postgresql

El certificado raíz de Let’s Encrypt es ISRG Root X1 que se encuentra en el servidor en la ubicación /usr/share/ca-certificates/mozilla/ISRG_Root_X1.crt.

Copia el certificado raíz en el directorio /var/lib/postgresql/.postgresql.

$ sudo cp /usr/share/ca-certificates/mozilla/ISRG_Root_X1.crt /var/lib/postgresql/.postgresql/root.crt

Prueba la conexión utilizando el modo verify-full o verify-ca y deberías ver una conexión correcta.

Paso 9 – Comprueba los Clientes

Accede al shell PostgreSQL del servidor.

$ sudo -i -u postgres psql

Ejecuta el siguiente comando SQL para comprobar los clientes conectados.

SELECT ssl.pid, usename, datname, ssl, ssl.version, ssl.cipher, ssl.bits, client_addr
FROM pg_catalog.pg_stat_ssl ssl, pg_catalog.pg_stat_activity activity
WHERE ssl.pid = activity.pid;

Deberías ver una salida similar.

 pid  | usename  | datname  | ssl | version |         cipher         | bits |  client_addr
------+----------+----------+-----+---------+------------------------+------+----------------
 5126 | postgres | postgres | t   | TLSv1.3 | TLS_AES_256_GCM_SHA384 |  256 | 122.161.84.220
 5154 | postgres | postgres | f   |         |                        |      |
(2 rows)

Esto confirma la conexión del cliente desde el lado del servidor.

Conclusión

Con esto concluye el tutorial sobre la activación de SSL en las conexiones PostgreSQL. Si tienes alguna pregunta, publícala en los comentarios a continuación.

Scroll al inicio