인프라

fail2ban sshd Jail (점증 bantime)

인프라

fail2ban sshd Jail (점증 bantime) — 실전 적용 구조와 코드 예시

언제 쓰나 · SSH 브루트포스 시도가 쏟아지는 VM(OCI/AWS/GCP Always Free 포함)에서 자동 차단이 필요할 때 · 같은 IP가 반복해서 시도하면 차단 시간을 기하급수적으로 늘려 "첫 번째는 1시간, 두 번째는 2시간, … 최대 1주" 처럼 처벌하고 싶을 때 · Oracle Linux 9 / RHEL 계열의 firewalld + systemd journal 환경에서 바로 적용 가능한 구성을 찾을 때 · 메모리 2GB 이상 VM (1GB 이하는 fail2ban 설치 중 load spike 발생으로 비권장)

#infra#fail2ban#sshd#Jail
다운로드
# fail2ban sshd Jail (점증 bantime)

## 언제 쓰는가
- SSH 브루트포스 시도가 쏟아지는 VM(OCI/AWS/GCP Always Free 포함)에서 자동 차단이 필요할 때
- 같은 IP가 반복해서 시도하면 차단 시간을 기하급수적으로 늘려 "첫 번째는 1시간, 두 번째는 2시간, … 최대 1주" 처럼 처벌하고 싶을 때
- Oracle Linux 9 / RHEL 계열의 firewalld + systemd journal 환경에서 바로 적용 가능한 구성을 찾을 때
- 메모리 2GB 이상 VM (1GB 이하는 fail2ban 설치 중 load spike 발생으로 비권장)

## 핵심 구조
- **단일 설정 파일**: `/etc/fail2ban/jail.local` — 패키지가 덮어쓰지 않음 (`jail.conf`는 절대 건드리지 않기)
- **backend = systemd**: journald에서 sshd 로그를 바로 읽음 (Oracle Linux 9 등 journald 기본 환경에서 추가 설정 불필요)
- **차단 엔진 = firewalld rich-rules**: nftables/iptables 직접 건드리지 않고 firewalld와 통합. 재부팅 후에도 유지됨
- **점증 차단(bantime.increment)**: 같은 IP가 다시 걸릴 때마다 `bantime *= factor` 로 차단 시간 증가, `bantime.maxtime`에서 상한
- **화이트리스트**: 본인 IP와 관리 네트워크는 `ignoreip`에 필수 등록 (실수로 본인이 차단되면 ARM 인스턴스는 복구가 번거로움)
- **aggressive 모드**: `mode = aggressive`로 sshd filter가 실패 이벤트를 더 적극적으로 매칭 (preauth 차단 포함)

## 코드 예시
`/etc/fail2ban/jail.local`:
```ini
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 3
ignoreip = 127.0.0.1/8 ::1 <본인 IP> <백업 IP>
backend = systemd
banaction = firewallcmd-rich-rules[actiontype=<multiport>]
banaction_allports = firewallcmd-rich-rules[actiontype=<allports>]

# 반복 위반 시 bantime 점증
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w

[sshd]
enabled = true
mode = aggressive
port = ssh
```

설치 + 가동 (Oracle Linux 9):
```bash
sudo dnf install -y fail2ban fail2ban-firewalld fail2ban-systemd
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd     # 상태/차단 IP 확인
sudo fail2ban-client set sshd unbanip <IP>  # 수동 해제
```

확인:
```bash
sudo fail2ban-client status sshd
# Status for the jail: sshd
# |- Filter
# |  |- Currently failed: N
# |  |- Total failed:     N
# |  `- Journal matches:  _SYSTEMD_UNIT=sshd.service ...
# `- Actions
#    |- Currently banned: M
#    |- Total banned:     M
#    `- Banned IP list:   ...
```

## 주의사항
- **`jail.local`만 편집**. `jail.conf`는 패키지 업데이트로 덮어써지므로 절대 수정 금지
- **`ignoreip`에 본인 IP 추가 필수**. 특히 `findtime` 10분 동안 SSH 테스트 중 키 교환 실패를 3회 이상 만들 수 있음
- **fail2ban-firewalld 패키지 없이 사용**하면 `banaction = iptables-multiport` 기본값이 적용되어 firewalld와 충돌할 수 있음
- **1GB 이하 VM에서는 설치 시점에 load spike**(경험상 `load 27+`까지 튐) → OOM/스왑 폭주 위험. 이런 서버는 sshd 하드닝 + 키 전용 인증으로 대체 권장
- **`bantime.increment`는 fail2ban 0.11+** 필요. 이전 버전은 옵션 무시됨
- **점증은 DB 기반**: `/var/lib/fail2ban/fail2ban.sqlite3`에 히스토리 저장. 이 파일 삭제 시 점증 리셋됨
- **IPv6 차단도 포함**: `banaction`이 rich-rules이면 v4/v6 모두 차단
- **시크릿 주입 아님**: `<본인 IP>`는 예시이므로 실제 고정 IP로 교체할 것. 동적 IP면 대역으로 지정하거나 SSH jump host 사용

## 재사용 방법
1. 위 `jail.local`을 `/etc/fail2ban/` 에 저장, `ignoreip` 값만 환경에 맞게 치환
2. `dnf install -y fail2ban fail2ban-firewalld fail2ban-systemd` (RHEL 계열) / `apt install fail2ban` (Debian 계열은 firewalld 패키지 조합 달라짐)
3. `systemctl enable --now fail2ban`
4. 10분 이상 경과 후 `fail2ban-client status sshd`로 동작 확인
5. sshd 하드닝(`sshd-hardening.md`)과 반드시 함께 적용
6. 참고 실전 지표: OCI A1.Flex ARM 2 OCPU / 12GB × 2대에 2026-04-17 적용 후 누적 차단 IP 27개, 총 실패 566회 기록 (1시간 단위)
jt · v1 · CC0-1.0 · 복사 0