공개적으로 보이는 서비스가있는 모든 서버에서 fail2ban을 사용하고 있습니다.
- 내가 제어하는 호스트간에 금지 된 IP를 공유 하는 쉬운 방법이 있습니까?
- 해당 데이터를 수집하고 게시하는 서비스가 있습니까?
이 서버를 설정 한 1 일 이후로 수많은 로그인 시도가있었습니다.
공개적으로 보이는 서비스가있는 모든 서버에서 fail2ban을 사용하고 있습니다.
이 서버를 설정 한 1 일 이후로 수많은 로그인 시도가있었습니다.
답변:
한때이 사이트 에서 fail2ban 데이터를 중앙 집중화하는 시스템을보고 수정 된 버전을 만들었습니다. 데이터베이스는 동일하지만 bu를 변경하고 스크립트를 만들었습니다.
내 시스템에는 4 가지 구성 요소가 있습니다.
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;
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;
?>
크론
이것을 매분마다 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>
모든 서버에서이 구조를 사용하면 한 호스트에서 한 호스트가 금지 될 때마다 다른 모든 서버에서도 해당 서버가 금지됩니다.
그래서 동일한 IP 주소가 웹 서버의 클러스터에 하나씩 충돌하는 것을 보면서이 작업을 수행하는 방법에 대한 많은 연구를했습니다. AWS를 사용하고 있기 때문에 5 일 동안 서버를 테스트 한 첫 이틀 동안 쉬운 방법이 있고 아름답게 작동 할 것이라고 생각했습니다.
가장 먼저 권하는 것은 SELinux를 일시적으로 비활성화하는 것입니다. 마지막에이를 처리 할 것입니다. 저는 SELinux 전문가는 아니지만 지금까지 제가 한 일입니다.
기본 요구 사항은 공유 파일 소스이며 AWS EFS를 사용합니다. 새 드라이브가 프로비저닝되고 마운트되면 /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를 통해 각 호출 을하는 자체 고안 스크립트를 호출하는 것 입니다. 이를 위해 구성된 모든 호스트간에 키 기반 인증이 필요합니다. 꼭두각시와 같은 관리자 자동화 도구를 사용하면이를 설정하고 쉽게 유지할 수 있습니다. 이것은 매우 효율적이지는 않지만 대량의 프로빙 트래픽 (및 / 또는 많은 수의 호스트가없는)을 보지 않으면 충분할 것입니다. 호스트가 몇 개인 경우 파일을 반복 할 필요조차 없습니다. 순서대로 다른 호스트를 호출하도록 각각을 구성하십시오. 스크립팅 노력은 최소화 될 것입니다.
Is there a way to share banned IPs publicly?
의심 할 여지없이 여러 가지 방법이 있습니다. 위의 스크립트를 사용하여 데이터를 DB에 삭제하고 클라이언트가 그 데이터를 읽도록하여 새 규칙을 폴링하고 들어오는 규칙을 실행하도록하십시오. 호스트가 정보를 제출하고 있습니다 (예 :이 경우).
그러나 이것은 중대한 문제가되어서는 안되며, 데이터베이스에 대해 조금 더 영리한 경우에는 노력할만한 가치가 있다고 판단되면 여러 제출물을보다 깨끗하게 관리 할 수 있습니다.
공공 서비스로 운영하면 관리자의 번거 로움이 생길 수 있습니다.