[클라우드 인프라 구축기] SSH 브루트포스 5,227건 대응기

이태수·2026년 1월 19일
post-thumbnail

TL;DR

  • 운영 중인 서버에서 SSH 브루트포스 공격을 탐지했다.
  • 1월 13일 발견 당시 1,312건이었던 공격이 7일 후 5,227건으로 증가.
  • fail2ban + SSH 포트 변경 + Private Subnet 배치로 대응한 결과,
    GPU 서버 공격 0건 달성.

  1. KakaoCloud 2-Tier 아키텍처 설계
  2. GitHub Actions로 CI/CD 구축하기
  3. SSH 브루트포스 5,227건 대응기 ⬅️ 현재 글
  4. Nginx 심화 설정
  5. 서버 자동화 스크립트

1. 공격 발견 (1월 13일)


1.1 상황

MovieSir 서비스를 운영하던 중 정기 보안 점검에서 이상 징후를 발견했다.

$ sudo lastb | wc -l
1107

lastb 명령어는 실패한 로그인 시도를 보여준다.
운영 2주 만에 1,107건의 SSH 로그인 실패 기록이 쌓여 있었다.


1.2 공격 로그 분석

$ sudo lastb | head -20
monitor		ssh:notty    192.32.162.151    Tue Jan 13 04:27 - 04:27  (00:00)
config		ssh:notty    162.214.115.13    Tue Jan 13 04:23 - 04:23  (00:00)
public		ssh:notty    192.32.162.151    Tue Jan 13 04:23 - 04:23  (00:00)
...

동일한 IP에서 짧은 시간 동안 반복적으로 로그인을 시도하고 있었다.

전형적인 브루트포스(무차별 대입) 공격 패턴이다.


1.3 공격 IP 분석

$ sudo lastb | awk '{print $3}' | sort | uniq -c | sort -rn | head -10
    423 45.148.10.121
    312 143.110.174.161
    156 164.92.161.167
    ...

상위 공격 IP들을 분석한 결과:

IP국가시도 횟수시도한 계정
45.148.10.121네덜란드423회admin, AdminGPO
143.110.174.161미국 (DigitalOcean)312회user
164.92.161.167미국 (DigitalOcean)156회solv
3.37.6.179한국 (AWS)89회admin

1.4 공격 패턴

공격자들이 시도한 계정명을 분석했다.

$ sudo lastb | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
    523 admin
    312 user
    187 root
     89 test
     67 ubuntu
     45 ftpuser
     32 debian
     28 student
     21 operator
     15 guest
유형시도한 계정특징
기본 계정root, ubuntu, admin리눅스 기본 계정
서비스 계정ftpuser, mysql, postgres서비스 기본 계정
일반 계정user, test, student, guest흔한 이름

자동화된 봇이 사전에 정의된 계정 목록으로 무차별 시도하는 것을 확인했다.


1.5 GPU Server도 공격받는 중

App Server만 확인하면 안 될 것 같아서 GPU Server도 점검했다.

$ sudo lastb | wc -l
205

GPU Server에도 205건의 공격이 들어오고 있었다.
이 서버에는 PostgreSQL과 AI 모델이 있어서 더 위험했다.


2. 피해 가능성 분석

공격이 성공했다면 어떤 피해가 발생할 수 있었을까?

시나리오피해 유형심각도
DB 접근사용자 데이터 유출🔴 높음
랜섬웨어서버 암호화, 금전 요구🔴 높음
크립토마이너GPU 자원 탈취, 전기료 폭증🟠 중간
봇넷 편입DDoS 공격 가담🟠 중간

특히 GPU 서버에는 Tesla T4 GPU와 PostgreSQL이 있어서,
침입 시 크립토마이닝 + 데이터 유출의 이중 피해가 우려됐다.


3. 대응 조치 (1월 13~14일)

공격을 발견한 당일부터 바로 대응에 들어갔다.


3.1 fail2ban 상태 확인

먼저 기존 보안 도구의 상태를 확인했다.

$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 4
|  |- Total failed:     1107
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 1
   |- Total banned:     118
   `- Banned IP list:	216.180.127.200
항목의미
Total failed1,107총 실패한 로그인 시도
Total banned118차단된 IP 수
Currently banned1현재 차단 중인 IP (만료됨)

fail2ban이 작동하고 있었지만,
차단 후에도 새로운 IP에서 계속 공격이 들어오고 있었다.


3.2 fail2ban 설정 강화

# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 52222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
파라미터설명
maxretry33회 실패 시 차단 (기존 5회)
bantime36001시간 동안 차단
findtime60010분 내 실패 횟수 카운트

3.3 SSH 포트 변경

가장 효과적인 조치는 SSH 포트 변경이었다.

# /etc/ssh/sshd_config
Port 52222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
설정변경효과
Port22 → 52222자동화된 스캔 회피
PermitRootLoginnoroot 직접 로그인 차단
PasswordAuthenticationno키 인증만 허용

포트 22는 SSH의 기본 포트로, 자동화된 봇들이 가장 먼저 스캔하는 대상이다.
비표준 포트로 변경하면 대부분의 자동 공격을 회피할 수 있다.


3.4 방화벽 이중 설정

KakaoCloud 보안그룹 (L3/L4)

포트출발지용도
522220.0.0.0/0SSH (변경된 포트)
4430.0.0.0/0HTTPS
800.0.0.0/0HTTP → HTTPS 리다이렉트

ufw 방화벽 (OS 레벨)

기본 정책 설정:

# 모든 인바운드 차단, 아웃바운드 허용 (화이트리스트 방식)
sudo ufw default deny incoming
sudo ufw default allow outgoing
정책설정이유
incomingdeny허용된 포트만 열기
outgoingallow서버에서 외부 통신 허용 (apt, curl 등)

포트 허용:

sudo ufw allow 52222/tcp  # SSH (변경된 포트)
sudo ufw allow 443/tcp    # HTTPS
sudo ufw allow 80/tcp     # HTTP
sudo ufw enable

상태 확인:

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)

To                         Action      From
--                         ------      ----
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
52222/tcp                  ALLOW IN    Anywhere

왜 이중으로 설정하는가?

계층도구위치특징
클라우드보안그룹VM 외부네트워크 레벨에서 필터링
OSufw (iptables)VM 내부커널 레벨에서 필터링

이중 방어의 이점:

  • 보안그룹 설정 실수 시 ufw가 2차 방어
  • OS 마이그레이션 시 ufw 설정 유지
  • 보안그룹이 없는 환경에서도 동일한 보안 수준

3.5 GPU 서버 Private Subnet 배치

GPU 서버에는 DB와 AI 모델이 있어서 더 강력한 보호가 필요했다.

GPU 서버 보안그룹:

포트출발지용도
2210.0.1.117/32SSH (App Server만)
543210.0.1.117/32PostgreSQL
800110.0.1.117/32AI Service

모든 포트를 App Server IP에서만 접근 가능하도록 제한했다.


3.6 Bastion Host 구성

GPU 서버에 접속할 때는 App Server를 Bastion Host로 사용한다.

# ~/.ssh/config
Host moviesir-app
    HostName <App-Server-IP>
    User ubuntu
    IdentityFile ~/.ssh/your-key.pem
    Port 52222

Host moviesir-gpu
    HostName 10.0.35.62
    User ubuntu
    IdentityFile ~/.ssh/your-key.pem
    ProxyJump moviesir-app
# 한 번의 명령으로 GPU 서버 접속
$ ssh moviesir-gpu

ProxyJump를 사용하면 App Server를 경유해서
Private Subnet의 GPU 서버에 접속할 수 있다.


4. 7일 후 결과 확인 (1월 20일)

대응 조치를 완료하고 7일이 지났다. 결과를 확인해보자.


4.1 App Server

$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 2
|  |- Total failed:     2680
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     209
   `- Banned IP list:
지표1월 13일1월 20일 (7일 후)변화
총 공격 시도1,107건5,227건+4,120건
차단된 IP118개299개+181개

$ sudo lastb | awk '{print $3}' | sort | uniq -c | sort -rn | head -10
    655 130.12.181.24
    357 176.120.22.13
    328 176.120.22.47
    315 216.180.127.200
    216 143.110.174.161
    186 91.202.233.33
    116 80.94.92.164
    112 3.37.6.179

공격은 계속되고 있지만, fail2ban이 299개 IP를 차단하며 방어 중이다.


4.2 GPU Server - 공격 완전 차단

$ sudo lastb | head -5
user     ssh:notty    45.148.10.121    Tue Jan 13 01:22 - 01:22  (00:00)
AdminGPO ssh:notty    45.148.10.121    Tue Jan 13 00:47 - 00:47  (00:00)
admin    ssh:notty    45.148.10.121    Tue Jan 13 00:12 - 00:12  (00:00)
admin    ssh:notty    3.37.6.179       Tue Jan 13 00:04 - 00:04  (00:00)
admin    ssh:notty    3.37.6.179       Tue Jan 13 00:04 - 00:04  (00:00)
지표1월 13일1월 20일 (7일 후)변화
마지막 공격1월 13일1월 13일7일간 신규 공격 0건

📌 1월 13일 이후로 새로운 공격이 단 한 건도 없다.

GPU Server에서 Public IP를 제거하고 Private Subnet으로 옮긴 것이 결정적이었다.
외부에서 접근 자체가 불가능해졌기 때문이다.


4.3 보안 계층 요약


5. 트러블슈팅


5.1 SSH 포트 변경 후 접속 불가

문제: 포트를 52222로 변경했는데 SSH 접속이 안 됨

원인: 보안그룹에서 새 포트를 열지 않고 sshd만 재시작

해결:

# 1. 보안그룹에서 52222 포트 먼저 열기
# 2. ufw에서 새 포트 허용
sudo ufw allow 52222/tcp

# 3. 기존 22 포트 삭제
sudo ufw delete allow 22/tcp

# 4. sshd 재시작
sudo systemctl restart sshd

교훈:

순서작업
1보안그룹에서 새 포트 열기
2ufw에서 새 포트 허용
3sshd_config 수정
4sshd 재시작
5새 포트로 접속 테스트
6성공 후 기존 포트 닫기

5.2 fail2ban이 새 포트를 인식 못함

문제: 포트 변경 후 fail2ban이 공격을 차단 안 함

원인: jail.local에서 port 설정이 기존 22로 되어 있음

해결:

# /etc/fail2ban/jail.local
[sshd]
port = 52222  # 변경된 포트로 수정
sudo systemctl restart fail2ban

5.3 ProxyJump 연결 타임아웃

문제: ssh moviesir-gpu 실행 시 타임아웃

원인: App Server 방화벽에서 내부 SSH(22) 아웃바운드 차단

해결:

# App Server에서
sudo ufw allow out 22/tcp

6. 보안 도구 비교: 왜 fail2ban인가?


6.1 SSH 브루트포스 방어 도구들

도구유형가격특징
fail2ban호스트 기반무료로그 분석 후 IP 차단
CrowdSec호스트 + 커뮤니티무료글로벌 위협 공유
Cloudflare클라우드 WAF무료/유료DNS 기반 프록시
AWS WAF클라우드 WAF유료AWS 네이티브

6.2 상세 비교

항목fail2banCrowdSecCloudflare
설치 난이도쉬움중간쉬움 (DNS만 변경)
SSH 보호OOX (HTTP만)
리소스 사용낮음중간없음 (클라우드)
위협 인텔리전스X (로컬만)O (커뮤니티)O (유료)
실시간 차단OOO

6.3 fail2ban 선택 이유

기준판단
SSH 보호 필요Cloudflare는 HTTP만 → 탈락
비용무료 필수 → fail2ban, CrowdSec
단순성서버 2대에 CrowdSec은 오버스펙
검증됨fail2ban은 10년+ 사용된 안정적 도구

6.4 언제 다른 도구를 쓸까?

상황추천 도구
서버 1~2대, SSH 방어fail2ban
서버 10대+, 위협 공유 필요CrowdSec
웹 서비스 DDoS 방어Cloudflare
AWS 환경, 예산 있음AWS WAF + Shield

6.5 향후 확장 계획

현재: fail2ban (단일 서버 방어)
     ↓
확장 시: CrowdSec (다중 서버 위협 공유)
     ↓
대규모: Cloudflare + AWS WAF (다계층 방어)

7. 교훈


7.1 배운 점

항목교훈
기본 포트SSH 22번 포트는 자동 공격의 첫 번째 타겟
공격 속도서버 오픈 후 수 시간 내에 공격 시작
자동화대부분의 공격은 자동화된 봇에 의한 것
다층 방어단일 보안 조치로는 부족, 여러 계층 필요
Private Subnet외부 노출이 필요 없는 서버는 격리

7.2 권장 사항

서버 운영 시 최소한의 보안 조치:

# 1. SSH 포트 변경
sudo sed -i 's/#Port 22/Port 52222/' /etc/ssh/sshd_config

# 2. 비밀번호 인증 비활성화
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config

# 3. fail2ban 설치
sudo apt install fail2ban -y

# 4. 방화벽 설정
sudo ufw allow 52222/tcp
sudo ufw enable

# 5. SSH 재시작
sudo systemctl restart sshd

7.3 모니터링 습관

정기적으로 확인해야 할 명령어:

# 실패한 로그인 시도
sudo lastb | head -20

# fail2ban 상태
sudo fail2ban-client status sshd

# 현재 접속 중인 사용자
who

# 열린 포트 확인
sudo netstat -tlnp

8. 마무리


8.1 타임라인 요약

날짜상황
1월 13일공격 발견 (App 1,107건 / GPU 205건)
1월 13일fail2ban 설정 강화, SSH 포트 변경 (22→52222)
1월 14일GPU Server Public IP 제거, Private Subnet 배치
1월 20일결과 확인 (App 5,227건 누적, 299 IP 차단 / GPU 7일간 0건)

8.2 성과

항목결과
탐지5,227건 공격 시도 발견
차단299개 IP 자동 차단
방어GPU 서버 7일간 공격 0건 달성
구축5계층 보안 아키텍처

8.3 다음 단계

영역개선 가능한 점
모니터링Prometheus + Grafana로 실시간 대시보드
알림Slack/Discord 연동으로 공격 알림
로그ELK Stack으로 중앙 로그 관리
감사CloudTrail 같은 감사 로그 활성화

GitHub


이 글은 스나이퍼팩토리 카카오클라우드 AIaaS 마스터 클래스 2기 프로젝트 경험을 바탕으로 작성되었습니다.

0개의 댓글