Nginx Fail2Ban

Fail2Ban 은 이름 그대로 틀렸을 때 벤하는 프로그램입니다. 규칙에 따라 로그에서 부정한 행위를 찾아낸 뒤, 해당 행위를 한 IP를 방화벽에 등록해 차단합니다.

FreeNAS 는 방화벽 설정을 바꾸면 안 되지만, Jail 내부 방화벽 설정은 바꿔도 됩니다. Jail 또한 독립된 방화벽이 있으니, FreeBSD 의 방화벽인 IPFW 를 사용할 것입니다.

정리하면, Nginx 의 로그에서 부정한 접근을 탐지한 후 IPFW 에 해당 아이피를 차단 목록에 등록하는 식으로 동작합니다.

그럼 구성해 보겠습니다. 감옥으로 들어갑니다.

iocage console Nginx_WAF

IPFW 구성

IPFW 는 잘 구성된 프로파일들을 제공합니다. rc.conf 에서 IPFW 의 설정 파일을 로드할 수 있습니다.

vi /etc/rc.conf

아래 설정을 추가합니다.

firewall_enable="YES"
firewall_type="workstation"
firewall_logging="YES"
firewall_myservices="80/tcp 443/tcp"
firewall_allowservices="any"
firewall_logdeny="YES"

해석하자면

  • firewall 서비스를 사용한다.
  • firewall 의 타입 (프로파일) 은 workstation 으로 하고 (IPFW의 프로파일들은 여기 에서 자세하게 알아 볼 수 있습니다.)
  • 로깅을 한다.
  • 오픈할 포트는 tcp 80 포트와 tcp 443 포트이며
  • 모든 IP 에서 접속이 가능하다.
  • 차단 로그를 기록한다.

설정하였다면 IPFW 를 시작해 줍니다.

service ipfw start

Fail2Ban 설정

fail2ban 설정 파일 디렉토리로 이동합니다.

cd /usr/local/etc/fail2ban

  • action.d 디렉토리에는 부정한 접근이 있을 경우 ‘어덯게’ 차단할 것인지를 설정해 놓은 파일들이 존재합니다.
  • filter.d 디렉토리에는 로그 파일에서 ‘어떤’ 부정한 접근을 필터 (탐지) 할 것인지를 설정해 놓은 파일들이 존재합니다.
  • jail.d 디렉토리 아래 설정 파일은 어떤 종류의 부정한 접근을 어덯게 얼마나 차단할 것인지 설정할 수 있습니다.

jail.d 설정 만들기

Nginx 는 자체적으로 http 인증을 할 수 있도록 지원합니다. 이는 관리자 페이지 같은 인증이 필요한 페이지에 적용할 수 있습니다.

http 인증을 3번 이상 틀리면 차단하도록 설정하겠습니다.

vi jail.d/nginx-auth.local

[nginx-auth]
enabled = true
filter = nginx-http-auth
action = ipfw[name=nginx, port=80,443 protocol=tcp]
logpath = /var/log/nginx/error.log
findtime = 600
maxretry = 3
bantime = 3600

위 설정을 해석하면 이러합니다.

  • enabled : 이 설정을 활성화할지 설정합니다.
  • filter : 어떤 필터를 사용할지를 설정합니다.
    이 경우는 nginx 의 http 인증을 감지합니다.
  • action : 부정한 접근을 탐지했을 때 어덯게 처리할지를 설정합니다.
    • ipfw : IPFW 으로 차단합니다.
    • name : 룰의 이름입니다.
    • port : 차단할 포트입니다.
    • protocol : 어떤 프로토콜을 막을지를 설정합니다.
  • logpatch : 어떤 로그 파일을 감시할지 설정합니다.
  • fildtime : 600 초 안에
  • maxretry : 3번 틀리면
  • bantime : 3600초 동안 차단합니다.

nginx 의 http 인증을 감시해 600초 안에 3번 이상 틀리면 1시간동안 해당 IP 를 IPFW 에 올려 1시간동안 접근을 차단합니다.

IPFW action 수정

기본 설정은 몇 가지 문제가 있어 약간 수정을 해 주도록 하겠습니다.

vi action.d/ipfw.conf

수정해야 할 부분은 아래 4개 입니다.

  • actionstart : 최초 차단시 어떤 행동을 할 지
  • actionban : 차단시 어덯게 행동할지
  • actionunban : 차단을 해제할땐 어덯게 할지
  • localhost : 자신의 주소는 무엇인지

해당되는 설정을 찾아 아래와 같이 수정해 주세요.

actionstart = ipfw add 2410 <blocktype> tcp from "table(100)" to <localhost> 80, 443
actionban = ipfw table 100 add <ip>
actionunban = ipfw table 100 delete <ip>
localhost = me

각 구문의 의미는

  • ipfw 방화벽에 100번 테이블에 입력된 <IP> 가 tcp 프로토콜을 통해 <localhost>의 80, 443 포트로 <blocktype> 하지 못하도록 2410 번 규칙에 추가한다.
  • ipfw 의 100 번 테이블에다 <IP> 를 추가한다.
  • ipfw 의 100 번 테이블에서 <IP> 를 제거한다.
  • 내 주소는 me (자기 자신을 가르키는 문자) 이다.

기본 IPFW 차단 방식에 문제가 있어서 약간 수정해 준 것입니다.

Fail2Ban 서비스 등록

sysrc fail2ban_enable="YES"

Jail 시작시 자동으로 시작되도록 하고

service fail2ban start

Fail2Ban 을 시작해 줍니다.

Fail2Ban 작동 테스트

앞서 만든 Main 이라는 설정을 이용해 Fail2Ban을 테스트 하도록 하겠습니다.

http-auth 계정 파일 만들기

계정 정보가 저장된 파일을 만들어야 합니다. 계정 정보는 ‘IP:해시된 비밀번호‘ 의형태입니다.

비밀번호를 해시하는 방법이 크게 2가지 있는데 첫 번째는 openssl 을 이용하는 것이고, 두 번째는 htpasswd 라는 유틸리티를 사용하는 것입니다.

opensslbcrypt 라는 아파치에서 권장하는 해시 알고리즘을 사용할 수 없으니, htpasswd 를 사용하도록 하겠습니다.

그런데 htpasswd 는 apache 를 설치해야 사용할 수 있습니다. jail에 apache를 설치하는 대신 host 에 설치된 htpasswd를 사용하도록 하겠습니다.

암호 해싱하기

exit

먼저 감옥에서 빠져 나와 줍니다.

htpasswd -C 12 -nB 유저명

비밀번호를 입력하고, 한번 더 입력하면 계정:해시된비밀번호 가 출력됩니다.

htpasswd -C 12 -nB admion
New password: 
Re-type new password: 
admion:$2y$12$aaf1CdfcGadfacvqZ.Bz7lSSv2cVTZXIyZvgVV1ZsasdmUfa

위는 실행 예시입니다.

htpasswd 명령어는 여기를 참고해 주세요.

다시 감옥으로 들어가 주겠습니다.

iocage console Nginx_WAF

계정 파일 만들기

계정 정보가 저장될 디렉토리를 만들고

mkdir /usr/local/etc/nginx/auth

Fail2Ban 을 테스트 하기 위한 계정 파일을 만듭니다.

vi /usr/local/etc/nginx/auth/.fail2ban_test_auth

위에서 만든 것을 입력하면 됩니다.

admion:$2y$12$aaf1CdfcGadfacvqZ.Bz7lSSv2cVTZXIyZvgVV1ZsasdmUfa

그 다음 www 유저만 파일에 접근할 수 있도록 권한 설정을 해 줍니다.

chown www:www /usr/local/etc/nginx/auth/.fail2ban_test_auth
chmod 400 /usr/local/etc/nginx/auth/.fail2ban_test_auth

Nginx 설정 수정

앞서 만든 설정 파일을 수정해 main.example.com 에 로그인해야만 접근할 수 있도록 설정해보겠습니다.

vi /usr/local/etc/nginx/conf.d/main.conf

아래 설정을 필요한 부분에 추가합니다.

auth_basic "표시할 문구";
#로그인 시 나타날 문구입니다. 일반적으로 크롬 브라우저에서는 해당 문구가 보이지 않습니다.
auth_basic_user_file 계정정보파일;
#인증 파일의 위치를 지정합니다.

location / 블록에 추가하도록 하겠습니다.

server {
    listen      443 ssl http2;
    root /usr/local/www/nginx;
    server_name main.example.com;
    include /usr/local/etc/nginx/options/*;
    access_log /var/log/nginx/main/access.log;

    location / {
        auth_basic "Login";
        auth_basic_user_file /usr/local/etc/nginx/auth/.fail2ban_test_auth;
        index   index.html index.htm;
    }
}

위 설정을 사용할 경우, https://main.example.com/ 에 접근하기 위해선 암호 입력이 필요합니다.

nginx 를 재시작해 설정을 적용합니다.

nginx -s reload

차단 확인하기

이제 main.example.com 에 접속하면 ID 와 비밀번호를 입력하라는 메세지가 나타납니다.

의도적으로 잘못된 비밀번호를 3번 이상 입력해 보면 3번 이상 틀린 시점에서 페이지 로딩이 안 될 것입니다. 차단 된 것입니다.

잘 차단되었는지 확인해 보겠습니다.

fail2ban 확인

fail2ban-client status nginx-auth

Status for the jail: nginx-auth
|- Filter
|  |- Currently failed: 3
|  |- Total failed:     3
|  `- File list:        /var/log/nginx/error.log
`- Actions
   |- Currently banned: 1
   |- Total banned:     1
   `- Banned IP list: your.ip

Banned IP list 에 게이트웨이의 IP 가 있을 것입니다.

방화벽 규칙 확인

ipfw list

00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
00400 deny ip from any to ::1
00500 deny ip from ::1 to any
00600 allow ipv6-icmp from :: to ff02::/16
00700 allow ipv6-icmp from fe80::/10 to fe80::/10
00800 allow ipv6-icmp from fe80::/10 to ff02::/16
00900 allow ipv6-icmp from any to any ip6 icmp6types 1
01000 allow ipv6-icmp from any to any ip6 icmp6types 2,135,136
01100 check-state :default
01200 allow tcp from me to any established
01300 allow tcp from me to any setup keep-state :default
01400 allow udp from me to any keep-state :default
01500 allow icmp from me to any keep-state :default
01600 allow ipv6-icmp from me to any keep-state :default
01700 allow udp from 0.0.0.0 68 to 255.255.255.255 67 out
01800 allow udp from any 67 to me 68 in
01900 allow udp from any 67 to 255.255.255.255 68 in
02000 allow udp from fe80::/10 to me 546 in
02100 allow icmp from any to any icmptypes 8
02200 allow ipv6-icmp from any to any ip6 icmp6types 128,129
02300 allow icmp from any to any icmptypes 3,4,11
02400 allow ipv6-icmp from any to any ip6 icmp6types 3
02410 unreach port tcp from table(100) to me 80,443
02500 allow tcp from any to me 80
02600 allow tcp from any to me 443
65000 count ip from any to any
65100 deny { tcp or udp } from any to any 135-139,445 in
65200 deny { tcp or udp } from any to any 1026,1027 in
65300 deny { tcp or udp } from any to any 1433,1434 in
65400 deny ip from any to 255.255.255.255
65500 deny ip from any to 224.0.0.0/24 in
65500 deny udp from any to any 520 in
65500 deny tcp from any 80,443 to any 1024-65535 in
65500 deny log logamount 500 ip from any to any
65535 allow ip from any to any

02410 과 2500, 2600 을 잘 보시길 바랍니다.

  • 02410 unreach port tcp from table(100) to me 80,443
    80과 443 포트에 table(100) 에 들어있는 주소가 접근할수(unreach) 없게 한다.
  • 02500 allow tcp from any to me 80
    아무 주소나 80포트에 tcp 프로토콜로 접근 가능하게 한다.
  • 02600 allow tcp from any to me 443
    아무 주소나 443 포트에 tcp 프로토콜로 접근 가능하게 한다.

2410 룰에서 table(100) 에 들어 있는 IP 가 80과 443 포트로 접근할 수 없게 하고, 2500 룰과 2600 룰에서 나머지 모든 IP 는 접근할수 있도록 합니다.

100번 테이블에 IP 가 잘 올라갔는지 확인해 보겠습니다.

ipfw table 100 list

--- table(100), set(0) ---
192.168.1.254/24 0

잘 차단되었음을 알 수 있습니다.

차단 해제

이제 차단을 풀어보겠습니다.

fail2ban-client unban nginx-auth 차단.해제할.ip

위 명령어를 사용하면 차단이 해제됩니다.

테스트 종료

main 서버 블록과 main 로그 파일을 삭제하고 테스트를 종료하겠습니다.

rm /usr/local/etc/nginx/conf.d/main.conf
rm -r /var/log/nginx/main
service nginx restart

마치면서

Fail2Ban 을 설정하였습니다. 다음 포스팅에서는 DDClient 를 이용해 DDNS 를 설정할 것입니다.

이렇게 글을 쓰면서 알게 된 건데, 잘 알고 있다 해서 잘 가르쳐 줄 수 있는 건 아니라는 것을 깨달았습니다. 이젠 교수님께서 답답하게 수업하셔도 투덜대지 말아야겠습니다.

시리즈 네비게이션<< Nginx 설정DDNS – DDclient >>

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다