Bloquear accesos no autorizados en Postgres usando fail2ban

Categorías:

Fail2ban es una herramienta open source que monitorea los archivos log en busca de accesos fallidos, una vez identifica un acceso fallido fail2ban dependiendo de la configuración que se le haya creado procederá a bloquear el puerto o servicio a la IP que intenta acceder de forma “sospechosa”. Fail2ban se vale del firewall del sistema operativo para realizar los respectivos bloqueos.

En algunas ocasiones nos encontramos con que tengamos en nuestros registros de log las siguientes líneas

May 26 12:03:57 centos8 postgres[6426]: [9-1] 2023-05-26 12:03:57.742 -05 {192.168.30.108} [6426] pablin@postgres FATAL:  password authentication failed for user "pablin"
May 26 12:03:39 centos8 postgres[6422]: [8-1] 2023-05-26 12:03:39.017 -05 {192.168.30.108} [6422] [unknown]@[unknown] LOG:  connection received: host=192.168.30.108 port=54454
May 26 12:03:53 centos8 postgres[6424]: [9-1] 2023-05-26 12:03:53.197 -05 {192.168.30.108} [6424] pablin@postgres FATAL:  password authentication failed for user "pablin"
May 26 12:03:53 centos8 postgres[6424]: [9-2] 2023-05-26 12:03:53.197 -05 {192.168.30.108} [6424] pablin@postgres DETAIL:  Connection matched pg_hba.conf line 86: "host #011all #011#011all #011#0110.0.0.0/0 #011#011md5"
May 26 12:03:55 centos8 postgres[6425]: [8-1] 2023-05-26 12:03:55.294 -05 {192.168.30.108} [6425] [unknown]@[unknown] LOG:  connection received: host=192.168.30.108 port=45128
May 26 12:03:55 centos8 postgres[6425]: [9-1] 2023-05-26 12:03:55.302 -05 {192.168.30.108} [6425] pablin@postgres FATAL:  password authentication failed for user "pablin"
May 26 12:03:55 centos8 postgres[6425]: [9-2] 2023-05-26 12:03:55.302 -05 {192.168.30.108} [6425] pablin@postgres DETAIL:  Connection matched pg_hba.conf line 86: "host #011all #011#011all #011#0110.0.0.0/0 #011#011md5"
May 26 12:03:57 centos8 postgres[6426]: [8-1] 2023-05-26 12:03:57.733 -05 {192.168.30.108} [6426] [unknown]@[unknown] LOG:  connection received: host=192.168.30.108 port=37390
May 26 12:03:57 centos8 postgres[6426]: [9-1] 2023-05-26 12:03:57.742 -05 {192.168.30.108} [6426] pablin@postgres FATAL:  password authentication failed for user "pablin"
May 26 12:03:57 centos8 postgres[6426]: [9-2] 2023-05-26 12:03:57.742 -05 {192.168.30.108} [6426] pablin@postgres DETAIL:  Connection matched pg_hba.conf line 86: "host #011all #011#011all #011#0110.0.0.0/0 #011#011md5"

Claramente podemos sospechar que alguien está intentando acceder a nuestra base de datos de forma ilegal.

Para estos casos es menester agregar en fail2ban una regla que permita identificar estos intentos fallidos y bloquear la dirección ip del servidor que origina esta conexión.

!!OJO!! realizar esta configuración no bloqueará la cuenta del usuario en postgres, lo que se crea aquí es una regla en firewall que bloquea toda conexión entrante desde la dirección ip “sospechosa”. Por tanto, tener en cuenta que si desde una IP origen se conectan varios usuarios a un servidor de base de datos, todos los usuarios que se intenten conectar desde esta ip serán bloqueados.

Teniendo en cuenta lo anterior, proceda con cautela.

Debemos configurar postgresql para que genere logs de acceso fallido. Esto lo hacemos editando el archivo postgresql.conf que generalmente podemos encontrarlo en /var/lib/pgsql/VERSION/data d

log_destination = 'stderr,syslog'
logging_collector = on
log_connections = on
log_line_prefix = '%m {%h} [%p] %q%u@%d ' log_statement = 'all' log_timezone = 'America/Bogota'

En el caso del log_line_prefix hemos definido una serie de directivas que indican respectivamente el timestamp en milisegundos, el servidor remoto, el número de proceso, el nombre de usuario y el nombre de la base de datos.

Un ejemplo sería la siguiente línea

May 26 16:25:57 centos8 postgres[1742]: [9-1] 2023-05-26 16:25:57.779 -05 {192.168.30.130} [1742] pablin@postgres LOG:  connection authorized: user=pablin database=postgres application_name=psql

Una vez editado el archivo postgresql.con, reiniciamos el servicio de postgres, un ejemplo sería el siguiente…

[root@centos8 ~]# systemctl restart  postgresql-13.service 
[root@centos8 ~]#

Verificamos el estado del servicio

[root@centos8 ~]# systemctl status postgresql-13.service 
● postgresql-13.service - PostgreSQL 13 database server
   Loaded: loaded (/usr/lib/systemd/system/postgresql-13.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2023-05-26 17:51:30 -05; 2s ago
     Docs: https://www.postgresql.org/docs/13/static/
  Process: 1990 ExecStartPre=/usr/pgsql-13/bin/postgresql-13-check-db-dir ${PGDATA} (code=exited, status=0/SUCCESS)
 Main PID: 1995 (postmaster)
    Tasks: 8 (limit: 24860)
   Memory: 17.0M
   CGroup: /system.slice/postgresql-13.service
           ├─1995 /usr/pgsql-13/bin/postmaster -D /var/lib/pgsql/13/data/
           ├─1998 postgres: logger 
           ├─2000 postgres: checkpointer 
           ├─2001 postgres: background writer 
           ├─2002 postgres: walwriter 
           ├─2003 postgres: autovacuum launcher 
           ├─2004 postgres: stats collector 
           └─2005 postgres: logical replication launcher 

May 26 17:51:30 centos8.5.unixpad.local postmaster[1995]: 2023-05-26 17:51:30.199 -05 {} [1995] HINT:  Future log output will appear in directory "log".
May 26 17:51:30 centos8.5.unixpad.local postgres[1995]: [1-2] 2023-05-26 17:51:30.199 -05 {} [1995] HINT:  Future log output will appear in directory "log".
May 26 17:51:30 centos8.5.unixpad.local postgres[1995]: [2-1] 2023-05-26 17:51:30.199 -05 {} [1995] LOG:  starting PostgreSQL 13.11 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red>
May 26 17:51:30 centos8.5.unixpad.local postgres[1995]: [3-1] 2023-05-26 17:51:30.199 -05 {} [1995] LOG:  listening on IPv4 address "0.0.0.0", port 5432
May 26 17:51:30 centos8.5.unixpad.local postgres[1995]: [4-1] 2023-05-26 17:51:30.199 -05 {} [1995] LOG:  listening on IPv6 address "::", port 5432
May 26 17:51:30 centos8.5.unixpad.local postgres[1995]: [5-1] 2023-05-26 17:51:30.238 -05 {} [1995] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
May 26 17:51:30 centos8.5.unixpad.local postgres[1995]: [6-1] 2023-05-26 17:51:30.303 -05 {} [1995] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"
May 26 17:51:30 centos8.5.unixpad.local postgres[1999]: [7-1] 2023-05-26 17:51:30.345 -05 {} [1999] LOG:  database system was shut down at 2023-05-26 17:51:30 -05
May 26 17:51:30 centos8.5.unixpad.local postgres[1995]: [7-1] 2023-05-26 17:51:30.380 -05 {} [1995] LOG:  database system is ready to accept connections
May 26 17:51:30 centos8.5.unixpad.local systemd[1]: Started PostgreSQL 13 database server.
[root@centos8 ~]#

Con los cambios realizados, procedemos a configurar los archivos correspondientes a fail2ban. Ellos son dos
/etc/fail2ban/jail.d/postgresql.conf

[root@centos8 fail2ban]# cat jail.d/postgresql.conf 
[postgresql]
enabled = true
filter = postgresql
logpath = /var/log/messages
maxretry = 3
bantime = 20
port = 5432
[root@centos8 fail2ban]# 

/etc/fail2ban/filter.d/postgresql.conf

[root@centos8 fail2ban]# cat  /etc/fail2ban/filter.d/postgresql.conf 
[Definition]
failregex = \{<HOST>\} .+? FATAL:  password authentication failed for user .+$
[root@centos8 fail2ban]#

Una vez tengamos estos dos archivos configurados, podemos reiniciar el servicio de fail2ban

[root@centos8 fail2ban]# systemctl restart  fail2ban
[root@centos8 fail2ban]#

Y verificamos el estado del servicio

[root@centos8 fail2ban]# systemctl status  fail2ban
● fail2ban.service - Fail2Ban Service
   Loaded: loaded (/usr/lib/systemd/system/fail2ban.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2023-05-26 18:00:12 -05; 5s ago
     Docs: man:fail2ban(1)
  Process: 2051 ExecStop=/usr/bin/fail2ban-client stop (code=exited, status=0/SUCCESS)
  Process: 2053 ExecStartPre=/bin/mkdir -p /run/fail2ban (code=exited, status=0/SUCCESS)
 Main PID: 2055 (fail2ban-server)
    Tasks: 5 (limit: 24860)
   Memory: 13.2M
   CGroup: /system.slice/fail2ban.service
           └─2055 /usr/bin/python3.6 -s /usr/bin/fail2ban-server -xf start

May 26 18:00:12 centos8.5.unixpad.local systemd[1]: fail2ban.service: Succeeded.
May 26 18:00:12 centos8.5.unixpad.local systemd[1]: Stopped Fail2Ban Service.
May 26 18:00:12 centos8.5.unixpad.local systemd[1]: Starting Fail2Ban Service...
May 26 18:00:12 centos8.5.unixpad.local systemd[1]: Started Fail2Ban Service.
May 26 18:00:12 centos8.5.unixpad.local fail2ban-server[2055]: Server ready
[root@centos8 fail2ban]#

Luego de ello podemos revisar el archivo /var/log/messages con el fin de acceder de forma fallida para probar el funcionamiento de fail2ban

May 26 18:02:58 centos8 postgres[2085]: [8-1] 2023-05-26 18:02:58.940 -05 {192.168.30.108} [2085] [unknown]@[unknown] LOG:  connection received: host=192.168.30.108 port=60408
May 26 18:02:58 centos8 postgres[2085]: [9-1] 2023-05-26 18:02:58.960 -05 {192.168.30.108} [2085] postgres@postgres FATAL:  password authentication failed for user "postgres"
May 26 18:02:58 centos8 postgres[2085]: [9-2] 2023-05-26 18:02:58.960 -05 {192.168.30.108} [2085] postgres@postgres DETAIL:  Connection matched pg_hba.conf line 86: "host #011all #011#011all #011#0110.0.0.0/0 #011#011md5"
May 26 18:03:13 centos8 postgres[2088]: [8-1] 2023-05-26 18:03:13.206 -05 {192.168.30.108} [2088] [unknown]@[unknown] LOG:  connection received: host=192.168.30.108 port=60652
May 26 18:03:13 centos8 postgres[2088]: [9-1] 2023-05-26 18:03:13.221 -05 {192.168.30.108} [2088] postgres@postgres FATAL:  password authentication failed for user "postgres"
May 26 18:03:13 centos8 postgres[2088]: [9-2] 2023-05-26 18:03:13.221 -05 {192.168.30.108} [2088] postgres@postgres DETAIL:  Connection matched pg_hba.conf line 86: "host #011all #011#011all #011#0110.0.0.0/0 #011#011md5"
May 26 18:03:14 centos8 postgres[2089]: [8-1] 2023-05-26 18:03:14.815 -05 {192.168.30.108} [2089] [unknown]@[unknown] LOG:  connection received: host=192.168.30.108 port=60668
May 26 18:03:14 centos8 postgres[2089]: [9-1] 2023-05-26 18:03:14.827 -05 {192.168.30.108} [2089] postgres@postgres FATAL:  password authentication failed for user "postgres"
May 26 18:03:14 centos8 postgres[2089]: [9-2] 2023-05-26 18:03:14.827 -05 {192.168.30.108} [2089] postgres@postgres DETAIL:  Connection matched pg_hba.conf line 86: "host #011all #011#011all #011#0110.0.0.0/0 #011#011md5"
[root@centos8 fail2ban]#

El sistema ha registrado los intentos fallidos, procedemos entonces a verificar el archivo /var/log/fail2ban.log

2023-05-26 18:03:00,168 fail2ban.filter         [2055]: INFO    [postgresql] Found 192.168.30.108 - 2023-05-26 18:02:58
2023-05-26 18:03:14,187 fail2ban.filter         [2055]: INFO    [postgresql] Found 192.168.30.108 - 2023-05-26 18:03:13
2023-05-26 18:03:15,389 fail2ban.filter         [2055]: INFO    [postgresql] Found 192.168.30.108 - 2023-05-26 18:03:14
2023-05-26 18:03:15,691 fail2ban.actions        [2055]: NOTICE  [postgresql] Ban 192.168.30.108

Nos damos cuenta que el sistema a bloqueado el acceso a la IP por la palabra Ban

El tiempo del bloqueo podemos determinarlo en la configuración que definimos, en este caso el parámetro quedó configurado a 20 segundos, podemos definir que el tiempo sea de 10 meses o más o menos, depende de las necesidades que se tengan.

Saludos.