Fail2ban, Nginx 가상호스트 공격을 놓치던 사각지대 해결기
밤낮없이 서버를 지키는 파수꾼 fail2ban이 어느 날부터인가 왠지 모르게 뚫린 것 같은 찜찜함을 안겨주더군요. WordPress 사이트에 계속해서 wp-login 무차별 대입 공격 시도가 감지되는데, 정작 fail2ban은 아무런 차단 조치도 취하지 않고 있었습니다. 로그 파일에는 분명히 공격 흔적이 선명하게 남아있었지만, fail2ban은 마치 눈뜬장님처럼 그 공격들을 흘려보내고 있었죠. 처음엔 필터 문제인가 싶어 몇 번을 들여다봤는지 모릅니다. 하지만 원인은 예상외로 단순한 곳에 있었습니다. 바로 Nginx 가상호스트별로 분리된 로그 경로 때문이었죠. 이 글에서는 fail2ban이 Nginx 가상호스트 환경에서 발생한 공격을 놓치고 있었던 이유와, 이를 해결하기 위해 어떤 과정을 거쳤는지 제가 직접 부딪히고 해결한 경험을 공유해 드리고자 합니다. 서버를 운영하면서 의외의 사각지대가 발생할 수 있다는 것을 다시 한번 깨달았던 소중한 경험이었습니다.
이 글에서 짚는 것
- Nginx 가상호스트 환경에서 fail2ban이 로그를 놓치는 원인
- fail2ban WordPress jail의 logpath 설정의 중요성
- 가상호스트별 로그 파일 경로를 fail2ban에 정확히 지정하는 방법
- 서버 보안 설정 시 로그 경로 확인의 중요성
- 실제 공격 차단 결과를 통해 fail2ban 설정 검증하기
이런 분께 — Nginx와 fail2ban을 사용하여 WordPress 사이트를 운영하는 개발자 및 서버 관리자 · 난이도는 중급 정도
문제의 시작: Nginx 가상호스트와 fail2ban의 사각지대
어느 날 갑자기 WordPress 관리자 페이지에 무차별 대입 공격이 쏟아지고 있다는 알림을 받게 되었습니다. 서버 로그를 확인해보니 wp-login.php로의 접근 시도가 계속해서 기록되고 있었죠. 하지만 이상하게도, 이런 공격들을 막아줘야 할 fail2ban은 전혀 작동하지 않는 듯했습니다. 평소 같으면 몇 번의 시도 후에 IP가 차단되었다는 메시지가 fail2ban 로그에 남아야 하는데, 그 어떤 기록도 찾을 수 없더군요. 공격은 계속되는데, 방어 시스템은 침묵하고 있는 상황이었습니다.
처음에는 fail2ban 필터 규칙이 너무 느슨한가 싶어 maxretry나 findtime 같은 설정을 조정해보려고 했습니다. WordPress용 필터인 wordpress.conf나 wordpress-hard.conf의 내용도 꼼꼼히 살펴보았죠. 혹시 패턴 매칭에 문제가 있나 싶어 공격 로그를 직접 복사해서 fail2ban-regex 명령어로 테스트까지 해보았습니다. 하지만 필터 자체는 정상적으로 공격 패턴을 인식하는 것으로 나타났습니다. 그렇다면 대체 무엇이 문제일까, 한참을 헤매게 되더군요.
공격 시도는 실시간으로 Nginx의 access.log에 기록되고 있었지만, fail2ban은 그 로그들을 전혀 보지 못하는 것 같았습니다. 이 문제는 단순히 WordPress 로그인 공격뿐만 아니라, 다른 가상호스트에 대한 잠재적인 SQL 인젝션(SQLi)이나 파일 포함(LFI) 공격 시도까지도 fail2ban이 감지하지 못할 수 있다는 불안감을 안겨주었습니다. 이는 서버 전체 보안에 심각한 구멍이 될 수 있는 상황이었죠. 당장이라도 원인을 찾아 해결해야 한다는 압박감을 느꼈습니다.
로그 파일 추적: 공격 기록은 어디에 숨어있었나?
fail2ban 필터가 정상 작동하는 것을 확인한 후, 다음으로 의심한 것은 바로 로그 파일의 위치였습니다. fail2ban이 감시해야 할 로그를 제대로 들여다보고 있지 못하는 것이 아닐까 하는 가설을 세웠죠. 제가 운영하는 서버는 Nginx를 사용하고 있었고, 여러 WordPress 사이트를 가상호스트(Virtual Host)로 운영하고 있었습니다. Nginx 설정 파일을 다시 한번 꼼꼼하게 살펴보게 되었네요.
nginx.conf의 기본 설정과 각 가상호스트 설정 파일을 하나씩 열어보았습니다. 예상대로, Nginx는 기본 access.log 외에 각 가상호스트 설정 블록 내에서 별도의 access_log 지시어를 사용하여 특정 도메인에 대한 로그를 별도 파일로 기록하고 있었습니다. 예를 들어, your-domain.com이라는 가상호스트의 로그는 /var/log/nginx/your-domain.com_access.log와 같은 경로에 저장되고 있었던 것이죠. 이 사실을 확인하고 나서야 문제가 명확해지기 시작했습니다. 공격 시도는 분명히 특정 가상호스트로 들어왔고, 그 기록은 해당 가상호스트의 전용 로그 파일에 남았던 것입니다.
이러한 Nginx의 가상호스트별 로그 분리 방식은 서버 관리자 입장에서는 트래픽 분석이나 문제 해결에 훨씬 효율적입니다. 하지만 fail2ban과 같은 로그 기반 보안 도구를 설정할 때는 자칫 사각지대를 만들 수 있는 요인이 되기도 합니다. fail2ban이 어떤 로그 파일을 감시하고 있는지를 정확히 파악하는 것이 무엇보다 중요하겠다는 것을 깨닫는 순간이었습니다.
WordPress Jail의 초기 설정과 오해
문제가 발생했던 당시 fail2ban의 WordPress jail 설정은 대부분 기본값에 가까웠습니다. /etc/fail2ban/jail.d/wordpress.conf 파일에는 다음과 같은 내용이 포함되어 있었죠. 여기서 핵심은 logpath 설정이었습니다.
/etc/fail2ban/jail.d/wordpress.conf
[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 86400
보시다시피 logpath는 /var/log/nginx/access.log 하나만을 바라보고 있었습니다. 저는 Nginx 서버를 운영하면서 이 경로가 모든 웹 트래픽 로그를 담고 있을 것이라고 막연히 생각하고 있었던 겁니다. 대부분의 설치 가이드나 기본 설정이 이렇게 되어 있기 때문에, 별다른 의심 없이 사용하고 있었던 것이죠. 하지만 앞서 말씀드렸듯이 Nginx는 가상호스트별로 로그를 분리해서 기록하고 있었고, 실제로 wp-login 공격 시도는 /var/log/nginx/your-domain.com_access.log 같은 개별 로그 파일에 쌓이고 있었습니다.
이런 오해는 저뿐만 아니라 많은 개발자나 서버 관리자들이 흔히 겪을 수 있는 부분이라고 생각합니다. 기본 설정이 모든 환경에 최적화되어 있을 것이라는 가정에서 비롯되는 것이죠. 특히 여러 도메인을 하나의 서버에서 운영하는 Nginx 가상호스트 환경에서는 기본 access.log 외에 추가적인 로그 파일이 생성될 수 있다는 점을 항상 염두에 두어야 합니다. fail2ban이 특정 공격을 감지하지 못한다면, 가장 먼저 logpath 설정과 실제 로그 파일의 위치를 대조해보는 것이 현명한 접근법임을 다시 한번 확인하는 계기가 되었습니다.
원인 분석: 가상호스트별 로그와 fail2ban의 불일치
이제 문제는 명확해졌습니다. fail2ban은 /var/log/nginx/access.log 파일만 열심히 들여다보고 있었고, 실제로 공격 로그가 기록되고 있던 /var/log/nginx/your-domain.com_access.log 파일은 아예 감시 대상에서 제외되어 있었던 것이죠. 이는 Nginx의 기본 설정과 fail2ban의 WordPress jail 설정 간의 근본적인 불일치 때문에 발생한 것이었습니다. 마치 도서관의 특정 코너에만 관심을 가지고 다른 중요한 코너는 아예 존재하지 않는다고 생각한 것과 비슷하다고 할까요?
이러한 불일치는 단순한 설정 오류를 넘어, 서버 보안에 심각한 공백을 초래할 수 있습니다. fail2ban이 감지하지 못하는 공격들은 계속해서 서버 자원을 소모하고, 잠재적으로 더 심각한 보안 취약점으로 이어질 수 있기 때문입니다. 특히 무차별 대입 공격은 성공하면 계정 탈취로 직결될 수 있으므로, 제때 차단하는 것이 매우 중요합니다. 다른 가상호스트에서 SQLi나 LFI 같은 공격이 발생했더라도, 로그 경로가 지정되어 있지 않았다면 이 역시 감지되지 않고 넘어갈 수 있었을 겁니다.
가장 중요한 교훈은 '기본 설정이 모든 환경을 커버한다고 가정하지 말라'는 것이었습니다. 특히 서버 환경이 복잡해질수록, 각 컴포넌트(Nginx, fail2ban 등)의 설정이 실제 운영 환경과 어떻게 상호작용하는지 세심하게 검토해야 합니다. 이 문제를 해결하기 위해서는 fail2ban에게 '네가 봐야 할 로그 파일이 하나 더 있어!'라고 알려주는 작업이 필요했습니다. 결국, logpath 설정에 감시해야 할 모든 로그 파일 경로를 명시적으로 추가해주는 것이 핵심 해결책이었죠.
해결 과정: logpath 확장과 시스템 안정화
문제의 원인을 파악한 뒤에는 해결책을 적용하는 것은 비교적 간단했습니다. fail2ban의 WordPress jail 설정 파일인 /etc/fail2ban/jail.d/wordpress.conf를 열어 logpath 항목에 공격 로그가 기록되고 있던 가상호스트별 로그 파일 경로를 추가해주었습니다. 여러 로그 파일을 감시하려면 공백으로 구분하여 나열해주면 됩니다.
/etc/fail2ban/jail.d/wordpress.conf
[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/nginx/access.log /var/log/nginx/your-domain.com_access.log
maxretry = 3
bantime = 86400
여기서 /var/log/nginx/your-domain.com_access.log는 실제 운영 중인 가상호스트의 로그 파일 경로로 바꾸어 적용했습니다. 만약 다른 가상호스트가 있다면 그 경로들도 함께 추가해주어야 합니다. 이 변경을 통해 fail2ban이 이제 모든 관련 로그 파일을 감시할 수 있게 된 것이죠. 이 외에도, 점검 과정에서 logrotate가 .bak 중복 파일 때문에 간헐적으로 실패하는 것을 발견하여 해당 문제도 함께 처리했습니다. 또한, 컨테이너 환경의 메모리 할당량이 부족해 보이던 부분도 상향 조정하여 전반적인 서버 안정성을 높이는 기회로 삼았습니다.
설정을 변경한 후에는 fail2ban 서비스를 재시작하여 변경 사항을 적용해야 합니다. 이 과정이 제대로 이루어지지 않으면 아무리 설정을 바꿔도 효과를 볼 수 없으니 주의해야 합니다. 다음 명령어를 사용해서 서비스를 다시 시작했습니다.
systemctl restart fail2ban
서비스 재시작 후에는 fail2ban이 로그 파일을 다시 읽고 새로운 설정을 적용하게 됩니다. 이제 제대로 작동할 것이라는 기대를 가지고 다음 단계를 진행했습니다.
즉각적인 효과와 검증: 141개의 차단 기록
fail2ban 서비스를 재시작하고 나서 얼마 지나지 않아, 저는 놀라운 결과를 확인하게 되었습니다. fail2ban이 재시작되면서 과거 로그들을 소급하여 다시 분석했는데, 무려 141건의 과거 공격 시도를 즉시 차단 처리했다는 기록이 로그에 나타났기 때문입니다. 그동안 fail2ban이 얼마나 많은 공격을 놓치고 있었는지 한눈에 알 수 있는 대목이었죠. 이 숫자를 보고 나니, 제대로 된 설정 하나가 얼마나 중요한지 새삼 깨닫게 되더군요.
재시작 이후 새로운 wp-login 무차별 대입 공격 시도가 들어왔을 때도, fail2ban은 지체 없이 해당 IP를 차단하는 것을 확인했습니다. 더 이상 공격 시도가 감지되는데도 아무런 조치도 취해지지 않는 답답한 상황은 벌어지지 않았습니다. Nginx 로그에는 공격 기록이 남았지만, fail2ban 로그에서는 해당 IP가 즉시 차단되었다는 메시지를 확인할 수 있었죠. 이는 logpath 설정 변경이 정확히 문제를 해결했다는 확실한 증거였습니다.
또한, 이번 해결 과정은 단순히 WordPress 로그인 공격 방어를 넘어, 다른 가상호스트에 대한 잠재적인 SQLi나 LFI 공격 시도까지도 이제는 fail2ban이 감지하고 차단할 수 있을 것이라는 기대감을 주었습니다. 모든 로그 파일을 감시하도록 설정했으니, 이제는 어떤 유형의 공격이든 fail2ban의 눈을 피하기는 어려울 것입니다. 이처럼 직접 문제를 해결하고 그 효과를 바로 확인하는 과정은 개발자에게 큰 만족감을 안겨주는 것 같습니다.
마무리: 서버 보안 설정의 꼼꼼함은 기본
이번 fail2ban 설정 오류 경험은 서버 보안에 있어 '꼼꼼함'이 얼마나 중요한지를 다시 한번 일깨워주었습니다. 특히 여러 서비스를 한 서버에서 운영하는 가상호스트 환경에서는 기본 설정이 모든 상황을 커버한다고 안일하게 생각해서는 안 된다는 것을 뼈저리게 느꼈습니다. 항상 실제 로그가 어디에 기록되는지, 그리고 보안 도구가 그 로그를 제대로 감시하고 있는지 확인하는 습관을 들여야 합니다.
단순히 'fail2ban이 설치되어 있으니 안전할 거야'라고 생각하기보다는, 주기적으로 fail2ban 로그를 확인하고, 실제로 공격이 발생했을 때 제대로 작동하는지 검증하는 과정이 필요합니다. 저처럼 logpath 하나 때문에 중요한 공격들을 놓치는 일이 없도록, 여러분의 서버 환경도 한번 점검해보시길 권해드립니다. 불필요한 비용을 들여 비싼 보안 솔루션을 도입하기 전에, 현재 운영 중인 시스템의 기본 설정을 똑똑하게 최적화하는 것이 먼저라는 생각이 드네요. 작은 설정 변경 하나가 서버 보안에 큰 차이를 만들 수 있음을 기억해주세요.
끝으로
fail2ban이 Nginx 가상호스트의 공격을 놓치고 있었던 문제는 결국 logpath 설정의 사각지대에서 비롯되었습니다. 이번 경험을 통해 서버 환경의 복잡성에 비례하여 보안 설정도 더욱 세심하게 관리해야 한다는 교훈을 얻었습니다. 이 글이 같은 문제로 고민하는 분들에게 작은 실마리가 되기를 바랍니다.

Top comments (0)