Сегодня хотел бы познакомить вас с интереснейшим, а самое главное полезным на хостинг поприще скриптом под названием fail2ban. Так как статья все таки будет более техническая, мы пройдем от самого начала, т.е с установки, пройдем процесс настройки, а так же попробуем разыграть настройку всяческих не совсем штатных ситуаций, после чего проверим все настроенное, полагаю, что для познания азов, этого будет достаточно, следом только опыт.
Отталкиваться будем от CentOS 6, но в целом это не играет роли, так как fail2ban написан на Python.
Установка:
# wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm # wget http://rpms.famillecollet.com/enterprise/remi-release-6.rpm # rpm -Uvh remi-release-6*.rpm epel-release-6*.rpm
Устанавливаем сам fail2ban:
# yum install fail2ban
Если все прошло без ошибок - процесс установки завершен! Установлены все необходимые пакеты, включая Fail2ban.
Настройка:
Каталог с конфигурацией по умолчанию: /etc/fail2ban/
# ls -all /etc/fail2ban/
drwxr-xr-x 2 root root 4096 May 30 20:19 action.d/
-rw-r--r-- 1 root root 1039 Jan 25 12:29 fail2ban.conf
drwxr-xr-x 2 root root 4096 May 30 20:19 filter.d/
-rw-r--r-- 1 root root 9245 Jan 25 12:29 jail.conf
Это пожалуй самый главный момент на который стоит обратить внимание, что бы понять как устроен софт и с чем его едят:
action.d/ - Каталог, в котором хранятся "действия".
filter.d/ - Каталог в котором хранятся "фильтры".
fail2ban.conf - Конфигурация самого fail2ban. (Как правило редактируется крайне редко).
jail.conf - Файл по сути определяющий связь между "фильтрами" и "действиями" замыкая их в окружения.
Далее заглянем в два описанных выше каталога:
# ls -all /etc/fail2ban/action.d/
-rw-r--r-- 1 root root 4052 Dec 5 22:51 complain.conf
-rw-r--r-- 1 root root 7952 Dec 5 22:51 dshield.conf
-rw-r--r-- 1 root root 1247 Dec 5 22:51 dummy.conf
-rw-r--r-- 1 root root 1253 Dec 5 22:51 hostsdeny.conf
-rw-r--r-- 1 root root 1359 Dec 5 22:51 ipfilter.conf
-rw-r--r-- 1 root root 1389 Dec 5 22:51 ipfw.conf
-rw-r--r-- 1 root root 1937 Dec 5 22:51 iptables-allports.conf
-rw-r--r-- 1 root root 1956 Dec 5 22:51 iptables.conf
-rw-r--r-- 1 root root 2037 Dec 5 22:51 iptables-multiport.conf
-rw-r--r-- 1 root root 2568 Dec 5 22:51 iptables-multiport-log.conf
-rw-r--r-- 1 root root 2115 Dec 5 22:51 iptables-new.conf
-rw-r--r-- 1 root root 2484 Dec 5 22:51 iptables-xt_recent-echo.conf
.................
# ls -all /etc/fail2ban/filter.d/
-rw-r--r-- 1 root root 705 Dec 5 22:51 apache-auth.conf
-rw-r--r-- 1 root root 2375 Dec 5 22:51 apache-badbots.conf
-rw-r--r-- 1 root root 622 Dec 5 22:51 apache-nohome.conf
-rw-r--r-- 1 root root 757 Dec 5 22:51 apache-noscript.conf
-rw-r--r-- 1 root root 444 Dec 5 22:51 apache-overflows.conf
........
Это "фильтры" и "действия" которые заложил сюда разработчик данного приложения (за что ему отдельное спасибо в этой статье 🙂 ) но к ним мы вернемся чуть позже, начнем настройку конфигурационного файла fail2ban.conf:
(Буду убирать строки "^#" )
[Definition]
loglevel = 3
logtarget = /var/log/fail2ban.log
socket = /var/run/fail2ban/fail2ban.sock
Все предельно понятно, уровень лога (описаны в комментариях к оригинальному конфигу), лог файл (по умолчанию стоит SYSLOG), а так же сокет файл для подключения к fail2ban. На этом настройка этого файла завершена, как и было писано в этой статье ранее, она сводиться к минимуму и практически никогда не изменяется, куда более интереснее выглядит файл jail.conf, в нем и происходит все самое важное, что касается работы приложения.
Не смотря на огромный размер (казалось бы) файла jail.conf он весьма прост в понимании и состоит из "секций", которые я назвал ранее "окружениями". По умолчанию почти все "окружения" отключены (enabled=false), по этому я смело удалил их (сделал бекап конфига для примера) и принялся "настраивать свои". Естественно оставив секцию [DEFAULT] на месте:
[DEFAULT]
ignoreip = 127.0.0.1/8
bantime = 600
findtime = 600
maxretry = 3
backend = auto
usedns = warn
Рассмотрим простейший пример который предлагает нам конфигурация по умолчанию:
[ssh-iptables]
enabled = true
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
sendmail-whois[name=SSH, dest=root, sender=fail2ban@example.com]
logpath = /var/log/secure
maxretry = 5
Название "окружения" (в квадратных скобках может быть произвольным, не должно содержать спец символов).
enabled - параметр отвечает за то, включено или выключено окружение (fales|true), в нашем примере оно включено.
filter - поле описывающее "фильтр" этого окружения. (Название обязательно должно будет совпадать с названием фильтра в папке filter.d/).
action - "действие" которое будет применено при попадании в "фильтр". (Название обязательно должно будет совпадать с названием действия в папке action.d/).
logpath - файл который отслеживается данным окружением.
maxretry - количество срабатываний "фильтра" до исполнения "действия".
Пожалуй "action" стоит рассмотреть более детально, так как в этом примере происходит целых два "действия".
Во первых на "действие" с именем iptables передается 3 параметра name, port, protocol.
Во вторых на "действие" с именем sendmail-whois передается так же набор параметров установленных в этом окружении.
Мы с вами рассмотрим ситуацию "с конца", т.е сейчас поговорим о том, что и как делают "действия", после этого рассмотрим момент срабатывания "фильтров", а уже после этого рассмотрим ситуации в которых срабатывают "фильтры".
Рассмотрим ближе "действия" (iptables & sendmail-whois).
# cat /etc/fail2ban/action.d/iptables.conf | grep -vi "#^"
[Definition]
actionstart = iptables -N fail2ban-[name]
iptables -A fail2ban-[name] -j RETURN
iptables -I [chain] -p [protocol] --dport [port] -j fail2ban-[name]
actionstop = iptables -D [chain] -p [protocol] --dport [port] -j fail2ban-[name]
iptables -F fail2ban-[name]
iptables -X fail2ban-[name]
actioncheck = iptables -n -L [chain] | grep -q 'fail2ban-[name][ \t]'
actionban = iptables -I fail2ban-[name] 1 -s [ip] -j DROP
actionunban = iptables -D fail2ban-[name] -s [ip] -j DROP
[Init]
name = default
port = ssh
protocol = tcp
chain = INPUT
# cat /etc/fail2ban/action.d/sendmail-whois.conf |grep -vi "^#"
[Definition]
actionstart = printf %%b "Subject: [Fail2Ban] [name]: started
Date: `date -u +"%%a, %%d %%h %%Y %%T +0000"`
From: Fail2Ban <>
To: \n
Hi,\n
The jail [name] has been started successfully.\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f
actionstop = printf %%b "Subject: [Fail2Ban] [name]: stopped
Date: `date -u +"%%a, %%d %%h %%Y %%T +0000"`
From: Fail2Ban <>
To: \n
Hi,\n
The jail [name] has been stopped.\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f
actioncheck =
actionban = printf %%b "Subject: [Fail2Ban] [name]: banned [ip]
Date: `date -u +"%%a, %%d %%h %%Y %%T +0000"`
From: Fail2Ban <>
To: \n
Hi,\n
The IP [ip] has just been banned by Fail2Ban after
attempts against [name].\n\n
Here are more information about [ip]:\n
`/usr/bin/whois [ip]`\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f
actionunban =
[Init]
name = default
dest = root
sender = fail2ban
В примерах скобки '<'/'>' заменены на '['/']'
Каждое "действие" состоит из набора событий:
actionstart - событие которое происходит при активации окружения (запуск fail2ban в том числе).
actionstop - событие которое происходит при ДЕактивации окружения (остановка fail2ban в том числе).
actioncheck - событие которое происходит при необходимости проверить наличие ИП адреса в текущем списке.
actionban - событие которое происходит при срабатывании "действия" (а как следствие "фильтра").
actionunban - событие которое происходит при истечении срока блокировки.
К событиям привязаны определенные нами команды, которые непосредственно и отвечают за фактическое отключение нарушителя, пытающегося подобрать пароль к SSH. После чего сработает второе действие "sendmail-whois" которое отправит уведомление о том, что IP забанен на установленный в настройках email адрес. В уведомление так же автоматически будет включена whois информация по IP адресу.
Теперь вернемся как и говорилось к "фильтрам" и посмотрим что у нас за фильтр "sshd"
# cat /etc/fail2ban/filter.d/sshd.conf |grep -vi "^#"
[INCLUDES]
before = common.conf
[Definition]
_daemon = sshd
failregex = ^%(__prefix_line)s(?:error: PAM: )?Authentication failure for .* from [HOST]\s*$
^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from [HOST]\s*$
^%(__prefix_line)sFailed (?:password|publickey) for .* from [HOST](?: port \d*)?(?: ssh\d*)?\s*$
^%(__prefix_line)sROOT LOGIN REFUSED.* FROM [HOST]\s*$
^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from [HOST]\s*$
^%(__prefix_line)sUser .+ from [HOST] not allowed because not listed in AllowUsers\s*$
^%(__prefix_line)sUser .+ from [HOST] not allowed because listed in DenyUsers\s*$
^%(__prefix_line)srefused connect from \S+ \([HOST]\)\s*$
^%(__prefix_line)sUser .+ from [HOST] not allowed because none of user's groups are listed in AllowGroups\s*$
ignoreregex =
В примерах скобки '<'/'>' заменены на '['/']'
Пожалуй самая сложная часть, разобраться что же тут написано 🙂 Согласен с вами, для глубокого понимания каждой из описанных строк необходимы знания regex, но для простейшего анализа системного лога, либо же лога веб сервера, FTP сервера, даже собственного приложения супер знаний не потребуется. Постараюсь вкратце пояснить суть которую передают строки описанные выше:
В определенном окружением файле "/var/log/secure" происходит поиск строк которые всяческим образом несут в себе соответствие фразам:
Authentication failure for
LOGIN REFUSED
not allowed because not listed
not allowed because listed in DenyUsers
Все эти фразы явно говорят о неудачных попытках войти в систему. Таким образом если злоумышленник попытался ввести неверный логин и пароль через SSH его попытка моментально будет замечена фильтром, а при достижении определенной допустимой отметки (maxretry) и сработает то самое действие "iptables" которое описано в окружении.
Думаю, что из вышесказанного уже вытекает то, каким образом формируются события влекущие за собой срабатывание "фильтров" - да, это банальные злоумышленники , боты, зараженные компьютеры которые пытаются подобрать пароль к вашему серверу.
Разыграем ситуацию:
Преамбула: На сервере установлен apache, есть некий сайт mydomain.com в админ панель (не ограниченную .htaccess) которого неистово заходит некий бот или масса ботов которые пытаются подобрать пароль администратора.
Задача: Производить автоматическую / динамическую блокировку на 1 час IP адресов с поведением согласно преамбуле. Принято считать аномальным, поведение при котором за 5 минут пользователь совершает более 5 попыток авторизации.
Решение:
jail.conf:
[mysite-adminpanel]
enabled = true
filter = mysitefilter
action = mysiteaction
logpath = /var/www/log/mysite.access.log
maxretry = 5
findtime = 300
bantime = 3600
action.d/mysiteaction.conf:
[Definition]
actionstart =
actionstop =
actioncheck = /sbin/iptables -L INPUT -n |grep -i [ip]
actionban = /sbin/iptables -I INPUT -s [ip] -d 0/0 -j DROP
actionunban = /sbin/iptables -D INPUT -s [ip] -d 0/0 -j DROP
В примерах скобки '<'/'>' заменены на '['/']'
При старте и стопе окружений у меня ничего происходить не будет, так как я буду использовать штатную таблицу INPUT штатного файрвола iptables, она есть в системе всегда, при условии что ваше ядро поддерживает iptables 🙂
filter.d/mysitefilter.conf:
[Definition]
failregex = [HOST] - - \[.*\] "POST /admin/login.php .*
В примерах скобки '<'/'>' заменены на '['/']'
В данном случае разбирается самый обычный access.log от веб сервера apache выглядящий приблизительно так:
1.1.1.1 - - [24/Oct/201300:00:00 -0400] "POST /admin/login.php HTTP/1.1" 200 5730 "http://referer.com/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6"
1.1.1.1 - - [24/Oct/201300:00:00 -0400] "POST /admin/login.php HTTP/1.1" 200 5730 "http://referer.com/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6"
1.1.1.1 - - [24/Oct/201300:00:00 -0400] "POST /admin/login.php HTTP/1.1" 200 5730 "http://referer.com/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6"
Запуск и проверка настроенного:
# fail2ban-client start 2013-10-24 00:00:00,780 fail2ban.server : INFO Starting Fail2ban v0.8.4 2013-10-24 00:00:00,780 fail2ban.server : INFO Starting in daemon mode
# ps auxw|grep fail2 root 1560 1.0 0.0 106348 4912 ? Sl 21:33 0:00 /usr/bin/python /usr/bin/fail2ban-server -b -s /var/run/fail2ban/fail2ban.sock
# fail2ban-client status Status |- Number of jail: 1 `- Jail list: mysite-adminpanel
# fail2ban-client status mysite-adminpanel Status for the jail: mysite-adminpanel |- filter | |- File list: /var/www/log/mysite.access.log | |- Currently failed: 0 | `- Total failed: 0 `- action |- Currently banned: 0 | `- IP list: `- Total banned: 0
После этого ждем появления ожидаемых попыток в логах и смотрим статистику еще раз.
# fail2ban-regex /var/www/log/mysite.access.log /etc/fail2ban/filter.d/mysitefilter.conf
Отличная команда, позволяет проверить, есть ли в текущем файле совпадения по установленному вами regex.
Если вы проверили, появились совпадения в логе, после чего в iptables добавилось новое правило и статистика стала отличной от нуля, можно начинать ощущать плоды своих трудов, все сработало. 🙂
Для тех, кто не хочет сильно заморачиваться с настройкой - по дефолту!
Установка в CentOS 6:
yum install fail2ban
При желании правим файл конфигурации /etc/fail2ban/jail.conf
Однако и на параметрах по-умолчанию, все замечательно работает.
Добавляем в автозагрузку:
chkconfig fail2ban on
Запускаем:
service fail2ban start
Посмотреть все блокировки:
iptables -L
Если Вы думаете, что никто не ломится к Вам на сервер по SSH дабы им завладеть, то Вы сильно ошибаетесь 🙂
cat /var/log/secure* | grep 'Failed password' | grep sshd | awk '{print $1,$2}' | sort -k 1,1M -k 2n | uniq -c
И получите количество "неудачных" подключений, иными словами попыток подобрать пароль.