목차
- 왜 Fail2ban 오탐이 생길까요?
- Fail2ban 동작 원리와 정규식 최적화 포인트
- 로그 분석 먼저: Fail2ban 오탐 줄이기의 출발점
- 1. 최근 차단 이벤트 확인
- 2. 원본 로그에서 실패 패턴 확인
- 3. 정상 로그와 실패 로그를 같이 비교
- 실전 구현: Fail2ban 필터와 정규식 다듬기
- 1. 기존 필터 확인
- 2. 커스텀 필터 작성
- 3. jail 설정 분리
- 4. 정규식 테스트
- ⚠️ 제가 실제로 겪었던 Fail2ban 오탐 패턴과 해결법
- 프록시 뒤에서 IP가 꼬이는 경우
- 로그 문장이 비슷해서 정상 이벤트가 같이 잡히는 경우
- 한 줄 정규식으로 모든 걸 해결하려는 경우
- 테스트 없이 서비스 재시작하는 경우
- 검증 절차: 설정 후 무엇을 확인해야 할까
- 검증 체크리스트
- 결과 정리: Fail2ban 오탐 줄이기 전후 비교
- 자주 묻는 질문: Fail2ban 오탐 대응 FAQ
- Q1.
maxretry만 올리면 해결되지 않나요? - Q2.
ignoreregex는 꼭 써야 하나요? - Q3. 로그 분석은 어느 정도까지 해야 하나요?
- Q4. 기본 필터를 수정해도 되나요?
- 마무리: 로그를 읽는 습관이 Fail2ban 운영을 살립니다
[보안] Fail2ban 오탐 줄이기: 로그 분석과 정규식 최적화 전략
Fail2ban 오탐 때문에 정상 사용자가 차단되는 상황, 한 번쯤 겪어보셨을 겁니다. 저도 홈랩이랑 외부에 노출된 몇몇 서비스에서 비슷한 Fail2ban 오탐 문제를 꽤 겪었습니다. 처음엔 "차단이 잘 되면 좋은 거 아닌가?" 싶었는데, 실제 운영에서는 이야기가 좀 다르더라고요. 특히 SSH, Nginx, 메일 서비스처럼 로그 형식이 조금만 달라져도 Fail2ban 정규식이 과하게 반응해서 멀쩡한 요청까지 공격으로 오인하는 경우가 생깁니다. 이번 글에서는 제가 실제로 정리해 둔 방식대로, 로그 분석부터 정규식(regex, 정규 표현식) 튜닝까지 단계별로 풀어보겠습니다.
핵심은 단순합니다. 차단 수치를 무작정 올리거나 <code>maxretry만 만지는 게 아니라, 먼저 로그를 읽고 패턴을 이해한 다음, 그에 맞는 필터를 만드는 겁니다. 이 흐름만 잡히면 침입 방지 시스템을 좀 더 안정적으로 운영할 수 있습니다.
Fail2ban 오탐을 줄이기 위해 로그 수집, 패턴 분석, 정규식 튜닝, 차단 검증까지 이어지는 전체 흐름을 한눈에 보여주는 이미지입니다.
왜 Fail2ban 오탐이 생길까요?
쉽게 말해 Fail2ban은 로그를 보고 판단합니다. 네트워크 패킷 자체를 해석하는 게 아니라, 서비스가 남긴 텍스트 로그를 기준으로 차단하거든요. 그래서 서비스 설정이 바뀌거나 프록시(Proxy, 중계 서버)가 앞단에 추가되면, 기존 필터가 예상하지 못한 문자열이 로그에 섞이게 됩니다.
예를 들어 이런 경우가 대표적입니다.
- 리버스 프록시(Reverse Proxy, 역방향 프록시) 뒤에 있어서 실제 클라이언트 IP 대신 프록시 IP가 보이는 경우
- 애플리케이션 로그 포맷이 커스텀되어 기본 필터와 맞지 않는 경우
- 에러 로그와 경고 로그가 비슷한 문장 구조를 가져서 실패 이벤트로 잘못 매칭되는 경우
- 한글 메시지 또는 추가 모듈 로그가 섞여 정규식이 과하게 넓게 잡히는 경우
저도 예전에 Nginx 뒤에 붙은 인증 서비스에서 Fail2ban 오탐이 계속 나서 삽질 좀 했습니다. 원인은 단순했어요. 기존 필터가 authentication failure 같은 문자열만 보고 잡고 있었는데, 실제로는 봇 공격이 아니라 브라우저 재시도 요청 일부까지 걸리고 있었거든요.
Fail2ban 동작 원리와 정규식 최적화 포인트
Fail2ban은 크게 세 가지를 봅니다. 필터(filter), 저널 또는 로그 소스(log source), 그리고 차단 정책(jail)입니다. 여기서 Fail2ban 오탐을 줄이는 핵심은 필터입니다.
| 구성 요소 | 역할 | 오탐과의 관계 |
|---|---|---|
| Filter | 로그에서 실패 패턴 추출 | 정규식이 넓으면 정상 로그도 공격으로 인식 |
| Jail | 재시도 횟수, 차단 시간, 대상 서비스 설정 | 필터가 잘못되면 정책이 정상 사용자에게 적용 |
| Action | iptables, nftables 등으로 차단 수행 | 실수한 필터가 실제 차단으로 이어짐 |
여기서 중요한 포인트! 정규식은 많이 잡는 게 좋은 게 아닙니다. 정확하게 잡는 게 중요합니다.
제가 보통 보는 기준은 이렇습니다.
- 실패 이벤트를 명확히 나타내는 고정 문자열이 있는가
- IP 주소 위치가 일정한가
- 정상 요청과 실패 요청을 구분하는 문장이 분리되는가
- 시간대별, 서비스별 로그 변형이 있는가
이 네 가지만 점검해도 Fail2ban 오탐 확률이 꽤 줄어듭니다.
로그 분석 먼저: Fail2ban 오탐 줄이기의 출발점
정규식을 바로 고치기 전에 반드시 로그를 먼저 봐야 합니다. 이걸 건너뛰면 거의 감으로 튜닝하게 되는데, 그러면 나중에 더 크게 꼬입니다. 실제로 써보니까 로그 20줄 제대로 보는 게 설정 20번 바꾸는 것보다 훨씬 빠르더라고요.
1. 최근 차단 이벤트 확인
sudo fail2ban-client status
sudo fail2ban-client status sshd
이 명령으로 활성화된 jail과 현재 차단된 IP를 먼저 확인합니다. 어떤 jail이 유독 많이 반응하는지부터 보는 거죠.
2. 원본 로그에서 실패 패턴 확인
sudo tail -n 200 /var/log/auth.log
sudo journalctl -u ssh --since "1 hour ago"
sudo grep -i "fail\|invalid\|error" /var/log/auth.log | tail -n 50
시스템마다 로그 경로는 다를 수 있습니다. Debian/Ubuntu 계열은 auth.log, systemd 환경은 journalctl 기반으로 보는 경우가 많습니다.
3. 정상 로그와 실패 로그를 같이 비교
이 단계가 진짜 중요합니다. Fail2ban 오탐은 보통 실패 로그만 보면 안 보입니다. 정상 사용자 접속, 키 교환, 세션 종료 같은 문장까지 같이 봐야 차이가 보이거든요.
sudo grep -E "Failed password|Accepted password|Invalid user|Connection closed" /var/log/auth.log | tail -n 100
제가 자주 하는 방식은 실패 케이스와 정상 케이스를 각각 10~20줄씩 복사해서 옆에 두고 비교하는 겁니다. 어떤 단어가 실패에서만 나오는지 찾는 거죠.
정상 로그인 로그와 실패 로그인 로그를 나란히 비교하면서 정규식에 포함해야 할 문자열과 제외해야 할 문자열을 구분하는 과정을 표현한 이미지입니다.
실전 구현: Fail2ban 필터와 정규식 다듬기
이제 본격적으로 Fail2ban 정규식을 손보겠습니다. 여기서는 SSH 계열 로그를 예시로 들지만, 원리는 Nginx나 메일 서비스에도 그대로 적용됩니다.
1. 기존 필터 확인
sudo ls /etc/fail2ban/filter.d/
sudo sed -n '1,200p' /etc/fail2ban/filter.d/sshd.conf
기존 필터를 무작정 덮어쓰는 건 추천하지 않습니다. 기본 파일은 참고만 하고, 별도 커스텀 필터를 만드는 편이 유지보수에 좋습니다.
2. 커스텀 필터 작성
# /etc/fail2ban/filter.d/sshd-local.conf
[Definition]
failregex = ^%(__prefix_line)sFailed password for (?:invalid user )?.* from <HOST> port \d+ ssh2$
^%(__prefix_line)sInvalid user .* from <HOST>$
ignoreregex = ^%(__prefix_line)sConnection closed by authenticating user .*$
^%(__prefix_line)sAccepted publickey for .*$
여기서 의도는 명확합니다.
failregex는 실패로 확정할 수 있는 로그만 좁게 잡습니다ignoreregex는 헷갈릴 수 있는 정상 또는 무해한 로그를 제외합니다<HOST>는 Fail2ban이 IP를 추출할 때 사용하는 플레이스홀더입니다
처음엔 이게 뭔가 싶었는데, 실제로는 ignoreregex를 잘 쓰는 순간 Fail2ban 오탐이 확 줄더라고요. 많은 분들이 failregex만 만지는데, 사실 둘을 같이 봐야 합니다.
3. jail 설정 분리
# /etc/fail2ban/jail.local
[sshd-local]
enabled = true
filter = sshd-local
port = ssh
logpath = /var/log/auth.log
maxretry = 5
findtime = 10m
bantime = 30m
maxretry, findtime, bantime은 정책값입니다. Fail2ban 오탐이 자주 난다고 무조건 maxretry를 크게 올리면 실제 공격 대응이 느슨해질 수 있습니다. 그래서 저는 먼저 필터를 좁히고, 그 다음 정책을 조정하는 순서를 지킵니다.
4. 정규식 테스트
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd-local.conf
이 명령은 거의 필수입니다. 실제 로그 파일에 대해 내가 만든 정규식이 몇 줄을 매칭하는지 보여주거든요. 여기서 정상 로그가 잡히면 배포 전에 바로 알 수 있습니다. 드디어 됐다! 싶은 순간도 보통 여기서 옵니다.
fail2ban-regex 명령으로 필터가 어떤 로그를 매칭하는지 검증하고, 예상치 못한 정상 로그가 걸리는 부분을 찾아내는 과정을 시각화한 이미지입니다.
⚠️ 제가 실제로 겪었던 Fail2ban 오탐 패턴과 해결법
운영하다 보면 생각보다 단순한 이유로 오탐이 납니다. 아래는 제가 자주 본 패턴입니다.
프록시 뒤에서 IP가 꼬이는 경우
Nginx 같은 리버스 프록시 뒤에 인증 서비스가 있으면, 애플리케이션 로그에 원본 IP 대신 프록시 IP가 찍히는 경우가 있습니다. 그러면 한 사용자의 실패가 아니라 프록시 전체가 문제처럼 보일 수 있죠. 이럴 땐 애플리케이션 로그 포맷에서 실제 클라이언트 IP가 어디에 기록되는지 먼저 확인해야 합니다.
로그 문장이 비슷해서 정상 이벤트가 같이 잡히는 경우
예를 들어 Connection closed 같은 문장은 실패 직후에도 보이고 정상 종료에도 보일 수 있습니다. 이런 문장을 넓게 잡아버리면 Fail2ban 오탐이 생깁니다. 그래서 저는 실패 판단용 문자열은 가급적 Failed, Invalid user처럼 의미가 분명한 것만 씁니다.
한 줄 정규식으로 모든 걸 해결하려는 경우
이거 정말 많이 봅니다. 정규식을 너무 똑똑하게 만들려고 하면 나중에 본인도 못 읽게 됩니다. 차라리 여러 줄의 failregex로 케이스를 나누는 게 유지보수에 훨씬 좋습니다.
테스트 없이 서비스 재시작하는 경우
저도 초반에 이 실수 했었습니다. 필터 바꾸고 바로 재시작했는데, 다음 날 정상 사용자 한 명이 접속이 안 된다고 연락이 오더라고요. 그 뒤로는 무조건 fail2ban-regex 테스트부터 합니다.
검증 절차: 설정 후 무엇을 확인해야 할까
설정을 넣었다고 끝이 아닙니다. Fail2ban 오탐은 운영 중에 드러나는 경우가 많아서, 적용 후 검증 루틴이 필요합니다.
- 필터 문법 테스트
- 실제 로그에 대한 매칭 수 확인
- 서비스 재시작 또는 설정 리로드
- 최근 1시간 로그에서 정상 이벤트가 차단 대상에 포함되는지 확인
- 차단된 IP 목록과 대응 로그를 대조
sudo fail2ban-client reload
sudo fail2ban-client status sshd-local
sudo fail2ban-client get sshd-local banip
가능하면 테스트 계정으로 정상 로그인과 실패 로그인을 각각 발생시켜 보는 것도 좋습니다. 홈랩 환경에서는 이런 검증을 해보기 좋아서, 저도 새 필터 만들면 꼭 직접 재현해 봅니다.
검증 체크리스트
- 정상 로그인 이벤트가
failregex에 잡히지 않는가 - 실패 이벤트는 빠짐없이 잡히는가
- 차단된 IP가 실제 공격 주체와 일치하는가
- 로그 포맷 변경 시 필터가 깨질 가능성은 없는가
결과 정리: Fail2ban 오탐 줄이기 전후 비교
| 점검 항목 | 오탐 줄이기 전 | 오탐 줄인 후 |
|---|---|---|
| 필터 범위 | 에러 비슷한 문자열을 넓게 포함 | 실패로 확정 가능한 문장만 포함 |
| 정상 사용자 영향 | 재시도나 세션 종료 로그까지 차단 가능 | 정상 이벤트는 ignoreregex로 제외 |
| 운영 안정성 | 차단 이유 추적이 어려움 | 왜 차단됐는지 로그와 정규식이 명확함 |
| 유지보수 | 한 줄짜리 복잡한 정규식에 의존 | 케이스별로 읽기 쉬운 필터 분리 |
결국 중요한 건 "많이 막는 것"보다 "정확히 막는 것"입니다. 서버 보안은 강하게만 간다고 좋은 게 아니더라고요. 특히 운영 환경에서는 정상 사용자의 경험도 같이 지켜야 하니까요.
Fail2ban 오탐이 줄어든 뒤 차단 로그와 정상 접속 로그가 명확하게 구분되고, 관리자 입장에서 추적이 쉬워진 상태를 보여주는 결과 이미지입니다.
자주 묻는 질문: Fail2ban 오탐 대응 FAQ
Q1. maxretry만 올리면 해결되지 않나요?
일시적으로는 덜 민감해질 수 있습니다. 근데 근본 해결은 아닙니다. 정규식이 잘못되면 정상 로그를 계속 실패로 판단하니까요.
Q2. ignoreregex는 꼭 써야 하나요?
반드시 필요한 건 아니지만, 실제 운영에서는 꽤 유용합니다. 특히 비슷한 형식의 정상 로그가 많은 서비스에서는 Fail2ban 오탐 방지에 효과가 큽니다.
Q3. 로그 분석은 어느 정도까지 해야 하나요?
최소한 정상 이벤트와 실패 이벤트를 각각 여러 줄씩 비교해 보시는 걸 권합니다. 한두 줄 보고 만들면 예외 케이스를 놓치기 쉽습니다.
Q4. 기본 필터를 수정해도 되나요?
가능은 하지만 권장하지 않습니다. 배포판 업데이트나 패키지 변경 시 추적이 어려워질 수 있어서, 별도 로컬 필터 파일로 분리하는 편이 낫습니다.
마무리: 로그를 읽는 습관이 Fail2ban 운영을 살립니다
이번 글에서는 Fail2ban 오탐을 줄이기 위해 로그를 어떻게 읽고, Fail2ban 정규식을 어떤 기준으로 다듬어야 하는지 정리해봤습니다. 저도 처음엔 단순히 차단 시간이랑 재시도 횟수만 조정했었는데, 결국 답은 로그 안에 있더라고요. 실제로 해보니까 정규식을 똑똑하게 짜는 것보다, 서비스 로그가 어떤 의미를 가지는지 먼저 이해하는 게 훨씬 중요했습니다.
혹시 지금도 정상 사용자가 자꾸 차단돼서 골치 아프시다면, 오늘 바로 fail2ban-regex부터 돌려보세요. 거기서 의외로 실마리가 바로 나옵니다. 다음 글에서는 Nginx 액세스 로그 기준으로 봇 요청과 인증 실패를 분리해서 침입 방지 시스템 정책을 나누는 방법도 다뤄볼 예정입니다. 이전 글에서 방화벽 정책과 로그 로테이션(log rotation, 로그 순환) 정리해두셨다면 같이 보시면 흐름이 더 잘 잡히실 겁니다.
로그 분석, 정규식 최소화, ignoreregex 활용, 테스트 검증이라는 네 가지 핵심 원칙을 한 장으로 정리한 요약 이미지입니다.
'IT > 보안' 카테고리의 다른 글
| [보안] 중소기업 Wazuh 도입 1년 회고: SIEM 구축 성공과 실패 사례 (1) | 2026.06.30 |
|---|---|
| [보안] OAuth 2.0 보안 허점 파헤치기: 실제 공격 사례와 방어 전략 (0) | 2026.06.28 |
| [보안] 안전한 웹 서버를 위한 TLS/SSL 설정 베스트 프랙티스 체크리스트 10가지 (1) | 2026.06.28 |
| [보안] Let's Encrypt 갱신 오류, 흔한 문제와 해결 전략 (0) | 2026.06.25 |
| [보안] Wireshark로 악성 트래픽 탐지: 네트워크 포렌식 기법 (1) | 2026.06.22 |
| [보안] Nmap 오류 해결: 스캔 실패 원인부터 디버깅 팁까지 (0) | 2026.06.21 |