私は一般公開されているサービスを備えたすべてのサーバーでfail2banを使用していますが、
- 私が管理するホスト間で禁止されたIPを共有する簡単な方法はありますか?
- そのデータを収集して公開するサービスはありますか?
このサーバーをセットアップしてから1日目から、無数のログイン試行があります。
私は一般公開されているサービスを備えたすべてのサーバーでfail2banを使用していますが、
このサーバーをセットアップしてから1日目から、無数のログイン試行があります。
回答:
このサイトでfail2banデータを集中管理するシステムを見たことがあり、修正版を作成しました。データベースは同じですが、いくつかのスクリプトを変更して作成しました。
私のシステムには4つのコンポーネントがあります。
fail2banデータベース
これは1つのテーブルのみを含む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;
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;
?>
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);
?>
phpconfig
このファイルは/ etc / fail2banに移動し、データベース構成とjailの選択があります。
<?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>
すべてのサーバーでこの構造を使用すると、1つのサーバーで1つのホストが禁止されるたびに、他のすべてのサーバーも禁止されます。
そこで、同じIPアドレスが私のWebサーバーのクラスターに次々とヒットするのを見てから、これを行う方法について多くの調査を行いました。私はAWSを使用しているので、5台のサーバーをテストした最初の2日間で簡単な方法があり、うまく機能する可能性があると考えました。
最初にお勧めするのは、一時的にSELinuxを無効にすることです。最後に対処します。私はSELinuxの専門家ではありませんが、今までやってきたことはうまくいきます。
主な要件は共有ファイルソースです。AWSEFSを使用しています。新しいドライブをプロビジョニングしてマウントしたら、/ etc / fail2ban / fail2ban.conf内のlogtargetを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を再起動すると、まだエラーが発生していました。jail.localでaction = action_mwlを使用するとバグがあります。少しグーグルで調べたところ、これが今のところ機能していることがわかりました。複数のファイルを指す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は起動しません。これがこれを展開しようとしている人に役立つことを願っています。
はい、はい。両方を行うことができます。
IPのリストを共有するための適切なメカニズムを見つける必要があります。たとえば、AWSを使用している場合は、s3を利用できます。Linuxホスト間でrsyncを使用することも、すべてのホストに共通のデータベースを使用することもできます。好みのプログラミング言語でサービスをノックアップすると、安らぎのAPIが選択できます。
言葉で言えば、リストを公開している場合、ウェブサイトを作成して簡単なテキストファイルをホストできますが、一部は既にそのようなリストを提供しています(私が知っているクラウドソースではありません)。独自のサイト/サービスを作成する方法は回答の範囲外ですが、それほど難しくするべきではありません。
Is there an easy way to share banned IPs between hosts I control?
かなり手動のセットアップではiptables
、更新ルールを呼び出す構成を変更して、ホストのリストをループする(ファイルから読み取られます)独自のスクリプトを呼び出し、iptables
SSHを介してそれぞれの呼び出しを行うようにします。これが機能するように設定されたすべてのホスト間でキーベースの認証が必要になります。puppetなどの管理自動化ツールを使用すると、これを設定して保守しやすくなります。これはそれほど効率的ではありませんが、大量のプローブトラフィック(および/または膨大な数のホスト)がなければ、それで十分だと確信しています。少数のホストしかない場合は、ファイルをループする必要さえありません。各ホストを順番に他のホストを呼び出すように設定します。スクリプト作成の労力は最小限に抑えられます。
Is there a way to share banned IPs publicly?
間違いなく多くの方法があります。上記のスクリプトでデータをDBにドロップし、クライアントにそのルールを読み取らせ、新しいルールをポーリングし、入ってくるときにそれらを実行します。ホストは情報を送信しています。たとえば、この場合:
しかし、これは重大な問題ではないはずです。データベースを少し賢くすれば、努力する価値があると判断すれば、複数の送信をよりきれいに管理できます。
それを公共サービスとして実行すると、管理者の面倒な世界が開きます: