콘솔 접근 수단, 현재 SSH 세션, 공개키 전용 두 번째 관리자 세션
보안 · 구성 레시피
Fail2ban·UFW·firewalld 안전 연동
현재 배포판이 관리하는 단일 방화벽을 유지하면서 Fail2ban SSH jail을 추가하고, 관리자 잠금 방지·로그 매칭·설정 검사·긴급 unban을 순서대로 검증합니다.BEFORE YOU START
시작 전에 준비하세요
실제 SSH 포트와 승인된 관리자 IPv4 CIDR
현재 UFW·firewalld·nftables 중 규칙 소유자를 확인한 기록
상위 보안그룹에서 SSH를 관리자 CIDR로 제한한 상태
권장 대상 기존 SSH 접근 정책을 유지하면서 반복 인증 실패를 임시 차단하려는 Linux 서버 운영자
FOLLOW THE RECIPE
8단계 구성·점검 레시피
배포판과 방화벽 소유자 확인
UFW와 firewalld를 동시에 활성화하지 않습니다. 현재 배포판 기본과 실제 활성 규칙 관리자를 먼저 판별합니다.
cat /etc/os-releasesudo sshd -T | grep -E '^(port|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication) 'sudo ufw status verbosesudo firewall-cmd --state
sudo firewall-cmd --get-active-zones- UFW 또는 firewalld 한 계층만 호스트 방화벽을 관리한다.
- 실제 SSH 포트와 관리자 CIDR을 확인했다.
- 콘솔과 두 번째 공개키 SSH 세션을 유지한다.
두 방화벽이 모두 규칙을 관리하거나 직접 nft 규칙과 충돌하면 Fail2ban 설치보다 방화벽 소유권을 먼저 정리합니다.
인증 로그와 기존 Fail2ban·ban 규칙을 조사합니다.
인증 로그·기존 jail·관리자 경로 점검
Fail2ban은 로그에 실제 실패 이벤트가 있어야 동작합니다. 비밀번호 로그인을 새로 허용해 시험하지 않고 기존 journal을 읽기 전용으로 확인합니다.
sudo journalctl -u ssh.service -u sshd.service --since '-1 hour' --no-pagerfail2ban-client --version
systemctl status fail2ban.service --no-pagersudo find /etc/fail2ban -maxdepth 2 -type f -name '*.local' -printprintf '%s\n' "$SSH_CONNECTION"
who관리자 IP가 포함되므로 외부에 공유하지 않습니다.- SSH 인증 실패가 journal에 기록된다.
- 관리자 CIDR과 현재 접속 출발지 주소를 대조했다.
- 기존 jail과 사용자 정의 action의 소유 팀을 확인했다.
journal에 이벤트가 없으면 backend를 억지로 켜지 말고 OpenSSH unit 이름과 로깅 경로를 먼저 확인합니다.
배포판에 맞는 한 가지 패키지 경로로 설치합니다.
배포판 패키지로 Fail2ban 설치
Ubuntu와 Rocky 명령 중 현재 배포판에 맞는 한 분기만 사용합니다. Rocky는 조직이 승인한 저장소에 후보 패키지가 있을 때만 진행합니다.
sudo apt updateapt-get --simulate install fail2ban python3-systemdsudo apt-get install fail2ban python3-systemdsudo dnf info fail2ban후보의 저장소와 서명을 조직 정책으로 승인한 경우에만 다음 명령을 사용합니다.sudo dnf install fail2banfail2ban-client --version- 현재 배포판에 맞는 한 설치 분기만 사용했다.
- 패키지 출처와 서명 정책을 확인했다.
- 설치 직후 기존 방화벽을 비활성화하거나 교체하지 않았다.
후보 패키지가 없으면 임의 설치 스크립트를 사용하지 말고 공식 배포판 또는 승인된 저장소 절차를 마련합니다.
배포판 기본 action을 유지한 최소 SSH jail을 작성합니다.
관리자 예외와 systemd backend 구성
패키지의 jail.conf를 수정하지 않고 .local 파일을 추가합니다. banaction을 임의로 강제하지 않아 배포판이 선택한 nftables·UFW·firewalld 통합을 중복 관리하지 않습니다.
date -u +%Y%m%dT%H%M%SZsudo cp --preserve=all --no-clobber /etc/fail2ban/jail.d/sshd.local /etc/fail2ban/jail.d/sshd.local.<BACKUP_SUFFIX>.bak기존 파일이 있을 때만 실행합니다.sudoedit /etc/fail2ban/jail.d/sshd.localsudo fail2ban-client -tsudo fail2ban-regex systemd-journal sshd --journalmatch='_SYSTEMD_UNIT=ssh.service + _SYSTEMD_UNIT=sshd.service'기존 journal만 읽으며 실패 로그가 없으면 0 matches일 수 있습니다. 임의 로그인 실패를 만들지 않습니다.[sshd]
enabled = true
backend = systemd
port = <SSH_PORT>
mode = normal
findtime = 10m
maxretry = 5
bantime = 10m
ignoreip = 127.0.0.1/8 ::1 <ADMIN_IPV4_CIDR><ADMIN_IPV4_CIDR>는 실제 승인된 관리망만 사용합니다. banaction은 배포판 기본값을 따르며 UFW와 firewalld action을 동시에 지정하지 않습니다.- 배포판 jail.conf를 직접 수정하지 않았다.
- ignoreip에 실제 관리자 CIDR과 루프백만 있다.
- 실제 SSH 포트가 일치한다.
- banaction을 중복 지정하지 않았다.
fail2ban-client -t가 실패하면 서비스를 시작하지 말고 첫 오류 파일과 옵션을 수정합니다.
기존 세션을 유지한 채 설정 검사 성공 후 서비스를 시작합니다.
설정 검사 후 서비스 시작
관리자 CIDR 예외와 콘솔을 확인한 뒤 시작합니다. 공개키 인증 실패를 의도적으로 반복해 시험하지 않습니다.
sudo fail2ban-client -t && sudo systemctl enable --now fail2ban.service && sudo fail2ban-client reloadsystemctl status fail2ban.service --no-pager
sudo journalctl -u fail2ban.service -n 100 --no-pagersudo fail2ban-client statussudo fail2ban-client status sshd- 설정 검사·시작·reload가 &&로 연결돼 신규 jail이 실제 반영됐다.
- sshd jail이 표시되고 오류 로그가 없다.
- 기존 세션과 공개키 두 번째 세션이 유지된다.
서비스는 active지만 sshd jail이 없으면 파일 로딩 순서·enabled·backend 오류를 확인합니다.
로그 매칭과 Fail2ban이 만든 규칙을 읽기 전용으로 검증합니다.
jail·로그·방화벽 동작 검증
실제 공격 로그가 발생할 때 카운터가 증가하는지 관찰합니다. 관리자 주소에서 실패 로그를 생성하는 방식은 사용하지 않습니다.
sudo fail2ban-client status sshdsudo fail2ban-client get sshd ignoreipsudo fail2ban-client get sshd actionssudo journalctl -u fail2ban.service --since '-30 minutes' --no-pager- 관리자 CIDR이 ignoreip에 정확히 반영됐다.
- 현재 배포판 방화벽과 호환되는 단일 action만 사용한다.
- 운영에서 자연 발생한 실패 이벤트가 있다면 failed 카운터가 증가한다.
필터 카운터는 증가하지만 ban이 없다면 임계값·action을, 카운터가 0이면 journal match와 OpenSSH 로그를 확인합니다.
SSH 잠금 복구와 방화벽 중복 여부를 최종 점검합니다.
잠금 방지와 방화벽 단일 소유 점검
Fail2ban은 상위 CIDR 제한과 공개키 인증을 대체하지 않습니다. 차단 규칙을 추가하는 주체가 하나인지 확인합니다.
sudo ufw status numberedsudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-allsudo fail2ban-client status sshdssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no -t <ADMIN_USER>@<SERVER_IP> 'id && sudo -v'현재 세션을 닫지 않은 채 승인된 관리자 CIDR에서 실행합니다.- UFW와 firewalld를 동시에 운영하지 않는다.
- 상위 보안그룹이 SSH를 관리자 CIDR로 제한한다.
- 공개키 전용 새 SSH 세션과 sudo가 성공한다.
- 긴급 unban 명령과 콘솔 경로를 운영 문서에 남겼다.
- 영구 ban보다 짧은 초기 bantime으로 오탐을 관찰한다.
관리자 세션이 실패하면 기존 세션을 닫지 말고 ignoreip·실제 출발지 CIDR·차단 목록부터 복구합니다.
오탐이나 잠금 시 해당 IP만 unban하고 신규 jail 파일을 비활성화합니다.
긴급 unban과 jail 원복
콘솔 또는 살아 있는 기존 세션에서 정확한 클라이언트 IP만 unban합니다. 신규 파일을 삭제하지 않고 비활성화하고, 이전 백업이 있을 때만 복원합니다.
sudo fail2ban-client status sshdsudo fail2ban-client set sshd unbanip <ADMIN_CLIENT_IP>콘솔 또는 유지 중인 기존 세션에서 실제 관리자 IP를 확인한 뒤 실행합니다.sudo mv /etc/fail2ban/jail.d/sshd.local /etc/fail2ban/jail.d/sshd.local.disabled.<ROLLBACK_SUFFIX>sudo cp --preserve=all /etc/fail2ban/jail.d/sshd.local.<BACKUP_SUFFIX>.bak /etc/fail2ban/jail.d/sshd.local작업 전 실제 백업이 있었던 경우에만 실행합니다.sudo fail2ban-client -t && sudo fail2ban-client reloadssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no -t <ADMIN_USER>@<SERVER_IP> 'id && sudo -v'- 전체 ban을 해제하지 않고 정확한 관리자 IP만 unban했다.
- 현재 SSH·콘솔 세션을 유지했다.
- 이전 파일 복원 또는 신규 파일 비활성화 중 맞는 분기만 사용했다.
- 설정 검사 후 reload하고 새 공개키 세션을 확인했다.
unban 뒤에도 접속이 안 되면 상위 방화벽·호스트 기본 규칙·sshd 자체 정책을 분리해 확인합니다.
오탐 로그를 보존하고 필터·임계값·관리망 주소 변경을 검토합니다.
SECURITY CHECK
운영 전 마지막 보안 점검
- UFW·firewalld·직접 nftables 중 규칙 소유자를 하나로 유지한다.
- 관리자 CIDR을 ignoreip에 넣고 콘솔·기존 세션을 확보한다.
- 배포판 jail.conf는 수정하지 않고 .local만 사용한다.
- 상위 SSH CIDR 제한과 공개키 인증을 계속 유지한다.
- 오탐 시 정확한 IP만 unban하는 복구 절차를 시험한다.
COMMON ERRORS
자주 막히는 지점
관리자 자신이 차단됨
- 증상
- 새 SSH 연결이 timeout 또는 즉시 거부됩니다.
- 가능한 원인
- NAT 뒤 실제 출발지와 ignoreip CIDR이 다르거나 이미 ban됐을 수 있습니다.
- 확인 순서
- 콘솔·기존 세션에서 SSH_CONNECTION과 ban 목록을 대조하고 정확한 IP만 unban합니다.
sshd jail이 시작되지 않음
- 증상
- No file(s) found 또는 journal backend 오류가 기록됩니다.
- 가능한 원인
- 파일 logpath와 systemd backend를 섞었거나 python-systemd 지원이 없을 수 있습니다.
- 확인 순서
- systemd backend에서는 logpath를 제거하고 journal의 실제 OpenSSH unit을 확인합니다.
ban 카운터는 증가하지만 접속이 계속됨
- 증상
- Fail2ban에는 banned IP가 있으나 방화벽에서 차단되지 않습니다.
- 가능한 원인
- 배포판 action과 실제 UFW·firewalld·nftables 소유자가 불일치할 수 있습니다.
- 확인 순서
- 유효 action과 활성 방화벽을 확인하고 두 방화벽을 동시에 켜지 않은 채 배포판 기본 action을 복원합니다.
PRIMARY REFERENCES
공식 문서
설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.