Server, Fail2ban으로 DDOS스러운 공격 막기

2019. 11. 20. 09:28개발/Server

상황

언제부턴가 사이트에 같은 url로 계속 접속하는 행동을 발견했고,

서버에 부하가 생겨 수동으로 ip을 차단하곤 했었다.

시시때때로 위와 같은 상황이 생겨서 이 부분을 자동으로 처리하리라 했다.

조치

처음에는 솔루션을 생각하다가 속도와 금액적인 이슈로 많이 제외하게 되었다.

그러다가 ssh로 무작위 접속을 막는 fail2ban을 생각하게 되었고,

이 서비스를 이용하는 방법으로 고민하게 되었다.

 

fila2ban(https://www.fail2ban.org/wiki/index.php/Main_Page)은 침입을 차단하는 프레임워크

로그 파일을 모니터링함으로써 작동한다.

 

기본이 되는 ssh 보안은 auth.log를 조회해서 특정시간 동안 얼마만큼의 이상징후가 발견되면

설정한 기간동안 차단하는 기능을 갖추고 있다.

 


시도 #1

처음에는 특정시간 동안 access 로그에 얼마만큼의 로그가 쌓이면 설정한 기간동안 차단을 하려고 했다.

그런데 개인적인문제가 있었다.

 

1. fail2ban에서는 status를 볼 수 있는데 access 로그를 이용하면 로그에 쌓이는 모든 기록이 failed로 카운팅이 된다. 왜곡된 status를 보는게 썩 좋진 않았다.

 

2. 단순히 생각했을때 fail2ban은 로그 파일을 모니터링을 하는데 기하급수적으로 쌓이는 access 로그를 본다는게 영 찝찝했다.

 


시도 #2

현재 사이트는 nginx를 웹서버를 사용하고 있다.

과하게 접속한다 생각하는 IP를 error 로그에 기록하고 fail2ban이 그 error 로그를 가리키게 한다면 위 이슈가 해결이 된다.

 

다행히 nginx에서는 request limit를 하는 module를 제공한다.

그리고 관련 글도 잘 제공해주고 있었다.

 

심지어 fail2ban에서도 자체적으로 nginx에서 사용한 limit request filter를 제공해주고 있었다. 방법은 위와 같다.

 


실행

fail2ban을 설치한다.

sudo apt-get fail2ban install

 

/etc/fail2ban 위치에 jail.local을 생성한다.

sudo vi /etc/fail2ban/jail.local

[nginx-limit-req]
enabled = true
bantime = <얼마동안 차단시킬지 (초)>
findtime = <최대 허용횟수를 체크할 시간 (초)>
maxretry = <최대 허용횟수>
banaction = iptables-multiport
banaction_allports = iptables-allports
port    = http,https
logpath = %(nginx_error_log)s

 

[nginx-limit-req] 는 /etc/fail2ban/filter.d 폴더에 있는 conf 이름이다.

ubuntu 16.04에서 테스트 할 때에는 nginx-limit-req.conf가 없어서 만들어주었는데,

ubuntu 18.04에서는 파일이 제공되어 있어서 쉽게 만들 수 있었다.

 

nginx-limit-req.conf 파일은 다음과 같이 되어있다.

보면 알겠지만 nginx에서 limit request를 사용하는 방법도 같이 설명해주고있다.

# Fail2ban filter configuration for nginx :: limit_req
# used to ban hosts, that were failed through nginx by limit request processing rate
#
# Author: Serg G. Brester (sebres)
#
# To use 'nginx-limit-req' filter you should have `ngx_http_limit_req_module`
# and define `limit_req` and `limit_req_zone` as described in nginx documentation
# http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
#
# Example:
#
#   http {
#     ...
#     limit_req_zone $binary_remote_addr zone=lr_zone:10m rate=1r/s;
#     ...
#     # http, server, or location:
#     location ... {
#       limit_req zone=lr_zone burst=1 nodelay;
#       ...
#     }
#     ...
#   }
#   ...
#

[Definition]

# Specify following expression to define exact zones, if you want to ban IPs limited
# from specified zones only.
# Example:
#
#   ngx_limit_req_zones = lr_zone|lr_zone2
#
ngx_limit_req_zones = [^"]+

# Use following full expression if you should range limit request to specified
# servers, requests, referrers etc. only :
#
# failregex = ^\s*\[[a-z]+\] \d+#\d+: \*\d+ limiting requests, excess: [\d\.]+ by zone "(?:%(ngx_limit_req_zones)s)", client: <HOST>, server: \S*, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"(, referrer: "\S+")?\s*$

# Shortly, much faster and stable version of regexp:
failregex = ^\s*\[[a-z]+\] \d+#\d+: \*\d+ limiting requests, excess: [\d\.]+ by zone "(?:%(ngx_limit_req_zones)s)", client: <HOST>,

ignoreregex =

datepattern = {^LN-BEG}

 

fail2ban 실행

sudo systemctl start fail2ban

 


체크

fail2ban 이 제대로 작동하는지 확인하는 로그는 /var/log/fail2ban.log에 기록되어 있다.

sudo tail -f /var/log/fail2ban.log

 

실행중인 fail2ban를 확인하는 방법은 status 명령어를 통해 확인할 수 있다.

sudo fail2ban-client status

 

좀 더 디테일하게 보고 싶다면 위 명령어 뒤에 jail name을 입력하면 된다.

sudo fail2ban-client status nginx-limit-req

 

이건 테스트 한다고 많이 사용한 명령어인데 ban이 된 ip를 해제하는 방법이다.

sudo fail2ban-client set nginx-limit-req unbanip IP

 


알림

이제 차단까지 잘 되었으면 다음은 알림을 받는 것이다.

 

기본 conf 파일을 보면 이메일을 받을 수 있는 부분까지 다 세팅이 되어 있어서 그대로 쓰려고 했다.

하지만, sendmail을 사용하는 fail2ban에서는 회사이메일로 gmail을 쓰는 케이스에서는 이메일을 받는게 뭔가가 더 복잡했다.

인증이라던가…

 

그래서 그냥 slack 알림을 받기로 했다.

 

slack 알림은 괜찮은 글을 찾게 되어서 99% 참조하게 되었다.

 

설정을 하면 아래와 같이 알림을 받을 수 있다.