Назад | Перейти на главную страницу

Совместное использование заблокированных IP-адресов fail2ban

Я использую fail2ban на всех серверах с общедоступными сервисами, и мне интересно:

  1. Есть легко как разделить заблокированные IP-адреса между контролируемыми мной хостами?
  2. Есть ли какая-нибудь служба для сбора и публикации этих данных?

Я получил бесчисленное количество попыток входа в систему с первого дня настройки этого сервера.

Однажды я видел систему централизации данных fail2ban на этом сайте, и создал измененную версию. База данных такая же, но я изменил и создал несколько скриптов.

Моя система состоит из 4 компонентов:

  1. база данных fail2ban

    Это база данных MySQL, содержащая только одну таблицу: erp_core_fail2ban:

    CREATE TABLE IF NOT EXISTS 'erp_core_fail2ban' (
      'id' bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      'hostname' varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
      'created' datetime NOT NULL,
      'name' text COLLATE utf8_unicode_ci NOT NULL,
      'protocol' varchar(16) COLLATE utf8_unicode_ci NOT NULL,
      'port' varchar(32) COLLATE utf8_unicode_ci NOT NULL,
      'ip' varchar(64) COLLATE utf8_unicode_ci NOT NULL,
      PRIMARY KEY ('id'),
      KEY 'hostname' ('hostname','ip')
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
  2. fail2ban.php

    Каждый раз, когда хост блокируется, он заполняет базу данных:

    
    <?php
    require_once("/etc/fail2ban/phpconfig.php");
    
    $name = $_SERVER["argv"][1];
    $protocol = $_SERVER["argv"][2];
    $port = $_SERVER["argv"][3];
    if (!preg_match('/^\d{1,5}$/', $port))
        $port = getservbyname($_SERVER["argv"][3], $protocol);
    $ip = $_SERVER["argv"][4];
    
    $hostname = gethostname();
    
    $query = "INSERT INTO 'erp_core_fail2ban' set hostname='" . addslashes($hostname) . "', name='" . addslashes($name) ."', protocol='" . addslashes($protocol) . "', port='" . addslashes($port) . "', ip='" . addslashes($ip) . "', created=NOW()";
    $result = mysql_query($query) or die('Query failed: ' . mysql_error());
    mysql_close($link);
    exit;
    ?>
    
  3. cron2ban

    Вы запускаете это на crontab каждую минуту. Он получит последние добавленные хосты и заблокирует их.

    
    <?php
    // phpconfig.php will have database configuration settings
    require_once("/etc/fail2ban/phpconfig.php");
    
    // file with only a line, containing the last id banned
    $lastbanfile="/etc/fail2ban/lastban";
    
    $lastban = file_get_contents($lastbanfile);
    
    // select only hosts banned after last check
    $sql = "select id, ip from erp_core_fail2ban where id > $lastban";
    $result = mysql_query($sql) or die('Query failed: ' . mysql_error());
    mysql_close($link);
    
    while ($row = mysql_fetch_array($result)) {
            //
            $id = $row['id'];
            $ip = $row['ip'];
    
    
        exec("fail2ban-client set $jail banip $ip");
    
    } // $id contains the last banned host, add it to the config file file_put_contents($lastbanfile, $id); ?>
  4. phpconfig

    Этот файл идет в / etc / fail2ban и содержит конфигурацию базы данных и выбор тюрьмы.

    
    <?php
    // jail to be used
    $jail = "ssh";
    
    // file to keep the last ban
    $lastbanfile="/etc/fail2ban/lastban";
    
    // database configuration
    $dbserver="localhost";
    $dbuser="root";
    $dbpass="root";
    $dbname="fail2ban";
    
    // connect to database
    $link = mysql_connect($dbserver, $dbuser, $dbpass) or die('Could not connect: ' . mysql_error());
    mysql_select_db($dbname) or die('Could not select database');
    
    ?>
    

Создайте эти файлы и измените конфигурацию из fail2ban:

После строки с actionban = ..... вставлена ​​новая строка для вызова PHP-скрипта:

/root/fail2ban.php <name> <protocol> <port> <ip>

Использование этой структуры на всех ваших серверах гарантирует, что каждый раз, когда один хост будет заблокирован на одном сервере, все остальные серверы также будут его запрещать.

Поэтому я провел кучу исследований о том, как это сделать, после того, как увидел, что один и тот же IP-адрес один за другим попадает в мой кластер веб-серверов. Поскольку я использую AWS, я подумал, что может быть простой способ, и он прекрасно работает в первые два дня тестирования 5 серверов.

Первое, что я рекомендую, это временно отключить SELinux, мы разберемся с этим в конце. Я не эксперт по SELinux, но то, что я сделал, пока работает.

Основное требование - общий источник файлов, я использую AWS EFS. После того, как новый диск подготовлен и смонтирован, я изменил logtarget внутри /etc/fail2ban/fail2ban.conf на подпапку на диске EFS.

logtarget = /efsmount/fail2ban/server1.log

Затем я написал простой фильтр и поместил его в /etc/fail2ban/filter.d/fail2ban-log.conf

[Definition]

failregex = .* Ban <HOST>

ignoreregex =

Добавлен фильтр в /etc/fail2ban/jail.local

[fail2ban-log]
enabled = true
port = http,https
findtime = 86400 ; 1 day
logpath  = /efsmount/fail2ban/server1.log
        /efsmount/fail2ban/server2.log
        /efsmount/fail2ban/server3.log
        /efsmount/fail2ban/server4.log
maxretry = 1

Затем перезапустили fail2ban

sudo fail2ban-client reload

Все идет нормально! Нет, самая болезненная часть - это SELinux. После того, как я немного поработал fail2ban, я выполнил эту команду, которая позволила бы fail2ban проходить через фильтры.

sudo grep fail2ban /var/log/audit/audit.log | sudo audit2allow -M fail2ban-nfs

Audit2allow скажет вам запустить эту команду

sudo semodule -i fail2ban-nfs.pp

Я все еще проверяю свои журналы SELinux здесь и там, чтобы узнать, есть ли еще отказы. Если у кого-то есть подсказка, как получить этот чистый SELinux другим методом, это было бы здорово.

sudo cat /var/log/audit/audit.log |grep fail2ban |grep denied

В этот момент я все еще получал ошибки при перезапуске fail2ban. Ошибка при использовании action = action_mwl в jail.local. После небольшого поиска в Google я обнаружил, что это работает до сих пор. Из того, что я прочитал, это из-за разрывов строк в директиве logpath, указывающей на несколько файлов. Я пробовал использовать запятые, пробелы и т. Д., С action_mwl больше ничего не работало.

action_mwm = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
             %(mta)s-whois-matches[name=%(__name__)s, dest="%(destemail)s", chain="%(chain)s"]

action = %(action_mwm)s

Не забудьте снова включить SELinux!

Я только что реализовал это, и до сих пор, похоже, он работает хорошо. Однако мне пришлось обновить часть php, потому что сценарии в исходном ответе используют устаревшие функции.

Вот обновленные скрипты

phpconfig.php

#!/usr/bin/php
<?php
// jail to be used
$jail = "ssh";

// file to keep the last ban
$lastbanfile="/etc/fail2ban/lastban";

// database configuration
$dbserver="[your.mysql.hostname]";
$dbport="[sql.port.default.is.3306]";
$dbuser="[sql.user";
$dbpass="[sql.password]";
$dbname="[sql.table]";

// connect to database
$link = mysqli_connect($dbserver, $dbuser, $dbpass, $dbname, $dbport) or die('Could not connect: ' . mysqli_error());
mysqli_select_db($link,$dbname) or die('Could not select database');

?>

fail2ban.php

#!/usr/bin/php 
<?php
require_once("/etc/fail2ban/phpconfig.php");

$name = $_SERVER["argv"][1];
$protocol = $_SERVER["argv"][2];
$port = $_SERVER["argv"][3];
if (!preg_match('/^\d{1,5}$/', $port))
    $port = getservbyname($_SERVER["argv"][3], $protocol);
$ip = $_SERVER["argv"][4];

$hostname = gethostname();

$query = "INSERT INTO erp_core_fail2ban (hostname,created,name,protocol,port,ip) VALUES ('$hostname',NOW(),'$name','$protocol','$port','$ip')";
echo $query;
$result = mysqli_query($link,$query) or die('Query failed: ' . mysqli_error($link));
mysqli_close($link);
exit;
?>

cron2ban.php

#!/usr/bin/php
<?php
// phpconfig.php will have database configuration settings
require_once("/etc/fail2ban/phpconfig.php");

// file with only a line, containing the last id banned
$lastbanfile="/etc/fail2ban/lastban";

$lastban = file_get_contents($lastbanfile);
// select only hosts banned after last check
$sql = "SELECT id,ip FROM erp_core_fail2ban WHERE id > $lastban";
$result = mysqli_query($link,$sql) or die('Query failed: ' . mysqli_error($link));
mysqli_close($link);

while ($row = mysqli_fetch_array($result)) {
        //
        $id = $row['id'];
        $ip = $row['ip'];

    exec("fail2ban-client set $jail banip $ip");


}

// $id contains the last banned host, add it to the config file
file_put_contents($lastbanfile, $id);
?>

Кроме того, где бы вы ни разместили действие fail2ban.php, он должен иметь такой же отступ, как и строка над ним. Например:

actionban = ...
            /etc/fail2ban/fail2ban.php

В противном случае fail2ban не запустится. Надеюсь, это поможет любому, кто пытается это развернуть.

Альтернатива fail2ban является DenyHosts который поставляется с функцией синхронизации. Установка довольно похожа на fail2ban, видеть Учебник Cyberciti для более подробной информации.

Проблема в том, что служба синхронизации является централизованным, и исходный код на стороне сервера кажется недоступным, поэтому вы не можете легко запустить свою собственную службу DenyHosts, и вам придется полагаться на стороннюю организацию (что может быть приемлемым для некоторых случаев использования).

Да и да. И то, и другое можно сделать.

Вам нужно найти подходящий механизм для обмена списком IP-адресов. Например, если вы используете AWS, вы можете воспользоваться преимуществами s3. Вы можете использовать rsync между хостами Linux или базу данных, общую для всех хостов. Вы можете создать сервис с любимым языком программирования, который предоставляет спокойный API, выбор за вами.

С точки зрения общего доступа к списку, вы можете создать веб-сайт и разместить на нем простой текстовый файл, некоторые уже предоставляют такие списки (а не краудсорсинг, о котором я знаю). Как создать свой собственный сайт / услугу будет выходить за рамки ответа, однако это не должно быть ужасно сложно.

Is there an easy way to share banned IPs between hosts I control?

Достаточно ручной настройкой было бы изменение конфигурации, которая вызывает iptables для обновления правил, чтобы он вызывал сценарий, созданный вами, который просматривает список хостов (читается из файла?) и делает iptables звонит по каждому через SSH. Вам понадобится аутентификация на основе ключей между всеми хостами, настроенными для этого. Инструменты автоматизации администрирования, такие как марионетка, могут упростить настройку и обслуживание. Это было бы не очень эффективно, но я уверен, что этого будет достаточно, если вы не увидите большой объем исследуемого трафика (и / или не имеете большого количества хостов). Если у вас всего несколько хостов, вам даже не нужно перебирать файл: настройте каждый так, чтобы он просто вызывал другие по порядку. Усилия по написанию сценариев будут минимальными.

Is there a way to share banned IPs publicly?

Несомненно, способов много. Попросите приведенный выше сценарий (-ы) перетащить данные в БД и попросить клиентов читать из нее, опрашивать новые правила и запускать их по мере их поступления. Простое «запускать правило, как вы его видите» не будет идеальным, если многие хосты отправляют информацию, например, в этом случае:

  1. В 12:00 сервер 1 говорит: «Забанить хост X сейчас» и «разблокировать хост X через час».
  2. В 12:45 сервер 2 сообщает: «Забанить хост X сейчас» и «разблокировать хост X через час».
  3. Перекрытие означает, что сервер 3 будет банить хост X на час, а не на час + 45 минут, если следовать инструкциям по порядку.

но это не должно быть серьезной проблемой, и если вы станете немного умнее с базой данных, вы сможете более аккуратно управлять несколькими отправками, если решите, что это того стоит.

Однако запуск этого как общедоступной службы откроет вам целый мир проблем с администратором:

  • Управление пропускной способностью и другими ресурсами, если у вас появится много пользователей.
  • Организация и применение способов оплаты, если вы попытаетесь решить проблему с ресурсами, взимая плату за доступ каким-либо образом.
  • Имея дело с попытками загрязнения вашей базы данных, злоумышленник пытается заблокировать конкурента в местах, подписавшихся на список, в качестве коммерческого неудобства или попытки шантажа.
  • Работа с жалобами, когда кто-то заблокирован и думает, что этого не должно быть.
  • Борьба с DDoS-атаками, которые воля приходите, если ваш сервис вообще успешно доставляет неудобства чьим-то ботам.