Так уж сложилось что в бесплатной версии PostgreSQL нет возможности блокировать пользователя после достижения определенного количества неудачных попыток аутентификации. Поэтому приходится использовать что-то другое для решения этой задачи.
Fail2ban
При использовании Fail2ban банить именно пользователя в PostgreSQL не получится, если только не использовать скрипты PostgreSQL для блокировки пользователя. Но тут встаёт вопрос с подключением к бд, и хранению пароля.
В моём же случае было достаточно просто блокировать подключения к PostgreSQL с IP-адреса, от которого были множественные неудачные подключения.
Создаём jail
Jail включает в себя набор правил и фильтров, по которым и происходим блокировка.
Для создания выполняем следующее:
sudo vim /etc/fail2ban/jail.d/postgres.conf
[postgres-iplock]
enabled = true
#filter name
filter = postgres-iplock
#filter action
action = iptables-postgres
#path to logs
logpath = /var/lib/pgsql/12/data/log/postgresql-*.log
maxretry = 3
bantime = 380
usedns = raw
Создаём фильтр
Используя фильтр Fail2ban будет искать вхождение в лог файлах, путь к которым указан в переменной logpath
.
sudo vim /etc/fail2ban/filter.d/postgres-iplock.conf
[Definition]
failregex = ^.*@<F-ID/> FATAL: password authentication failed .*
Внимание ваш pattern для фильтра может отличатся, так как в PostgreSQL можно изменить стиль вывода логов, используя переменную log_line_prefix
, в файле postgresql.conf. В моём случае значение переменной '%m [%p] %q%u@%d@%h '
.
Создаём правило
Собственно, правило и определяет то что будет происходить, когда значения по фильтру найдены и в сумме равны максимальному порогу, который задаётся в переменной maxretry.
Я же выбрал стандартный iptables только подредактировал под порт 5432.
sudo cp /etc/fail2ban/action.d/iptables.conf /etc/fail2ban/action.d/iptables-postgres.conf
sudo vim /etc/fail2ban/action.d/iptables-postgres.conf
[INCLUDES]
before = iptables-common.conf
[Definition]
actionstart = <iptables> -N f2b-<name>
<iptables> -A f2b-<name> -j <returntype>
<iptables> -I <chain> -p tcp --dport 5432 -j f2b-<name>
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
[Init]
Тестируем
Теперь, когда всё готово перезапускаем сервис fail2ban и смотрим логи на предмет срабатывания. Если сервис после перезапуска не стартовал возможно придётся немного поработать с selinux.
sudo systemctl restart fail2ban
Пытаемся неудачно залогинится на сервер PostgreSQL как минимум 3 раза. Если всё сделано правильно, то после 3 раза у нас просто будет недоступен порт 5432.
psql -U admin -d postgres
В файле логов находим следующие записи:
2022-10-07 16:41:31,773 fail2ban.filter [1109]: INFO [postgres-lockuser] Found 192.168.0.11 - 2022-10-07 16:41:31
2022-10-07 16:41:34,613 fail2ban.filter [1109]: INFO [postgres-lockuser] Found 192.168.0.11 - 2022-10-07 16:41:34
2022-10-07 16:41:37,023 fail2ban.filter [1109]: INFO [postgres-lockuser] Found 192.168.0.11 - 2022-10-07 16:41:36
2022-10-07 16:41:37,073 fail2ban.actions [1109]: NOTICE [postgres-lockuser] Ban 192.168.0.11
2022-10-07 16:47:56,173 fail2ban.actions [1109]: NOTICE [postgres-lockuser] Unban 192.168.0.11
Время, через которое IP-адрес будет разбанен задаётся в переменной bantime
.
Итог
Да это конечно не бан конкретного пользователя, но и тут есть свои преимущества. Как минимум даже если злоумышленник узнает ваши логины без паролей, он не сможет их заблокировать. Да, есть и такой метод атаки.
В общем решение всегда за вами подходит вам такой метод или нет.
Еще один минус в том, что fail2ban не умеет работать с ротацией логов. Т.е. если активный файл с логами создастся после запуска сервиса fail2ban он не поймёт, что логи в новом файле. Во избежание такой ситуации все активные логи надо писать в один файл и к нему применять какой-нибудь logrotate.
Комментарии