서버가 공격당하고 있어요.
저에게
by HOON
1
Last updated on Jan. 26, 2025, 2:17 p.m.
안녕하세요. 오늘은 DevSecOps로 한층 더 다가가게된 사례를 설명드리겠습니다.
(추가로 제가 아직까지 Lightsail의 가장 저렴한 버전을 유지하는 이유도 같이 설명 될 수 있을 것 같습니다.)
서버가 공격당했어요, 저에게..ㅎㅎ
서버에 접속하려고보니, down되어있습니다.
이상합니다. 최근 작업은 Prometheus, Grafana를 적용하고, nginx, postgresql 메트릭을 추가한게 전부입니다.
Lightsail 메트릭을 살펴보았습니다.
위 사진은 CPU 메트릭을 추적한건데, 보면 1/25일 18:20분에 CPU가 약 60%가까이 뛴 것을 볼 수 있습니다. 아마 이 때 서버가 다운됐을겁니다.
아래 사진은 Incoming Network Traffic로 혹시나 외부에서 DDos나 공격이 들어와 서버가 멈추진 않았을까 하여 살펴보았으나 오히려 잠잠했습니다.
제 예상이 틀렸습니다. 서버가 공격을 당했다면 Incoming Network Traffic가 치솟아야하는데 잠잠합니다.
근데 누가 공격했어요?
답은 한가지입니다.
내부적으로 어떤 요인에 의해 cpu를 과하게 쓰고있었고 그로인해 서버가 down됐다.
그럼 이제 타겟이 좁혀졌으니 내부에 무슨 문제가 있었는지 확인해보겠습니다.
우선 저는 서버를 재부팅하고 htop으로 실시간 서버 리소스를 확인해보겠습니다.
보니까, 전혀 예상치못한 fail2ban에서 cpu자원을 잡고있었습니다. fail2ban은 로그 기반으로 request 요청을 분석하여 미리 정해둔 rule에 부합하면 (해킹 시도가 있었다 판단하게되면) 자동으로 ban 할 수 있는 도구입니다.
로그 기반.. 로그 기반?
모든것이 문제였다
fail2ban은 로그 기반으로 패턴을 분석한다고 말했습니다. 그럼 fail2ban이 갑자기 cpu 리소스를 잡는 이유는 분석할 로그가 많다는 뜻이겠죠?
갑자기 로그가 쌓일만한게 뭐가있을까 되돌아보니, 엊그제 prometheus를 설정하면서 nginx 메트릭을 사용하기위해 nginx.conf 파일을 수정하였습니다.
아래는 nginx.conf 중 일부입니다.
location /nginx_status {
stub_status;
allow all;
deny all;
}
별 이상 없어보입니다. 뭐가 문제일까요??
다시 로그를 살펴보기위해 마운트된 경로로 이동해서 로그를 살펴보겠습니다.
이게 문제였네요. 저는 Prometheus에서 nginx 메트릭을 수집하기위해 5초마다 데이터를 가져오도록 설정했습니다.
근데 데이터를 가져올때마다 정보성 로그임에도 로그를 작성하도록 되어있어 과도한 로그가 쌓이게되었고,
그 결과 Fail2ban이 nginx/access.log를 분석하다보니 5초마다 쌓이는 과도한 로그를 계속해서 분석해야했습니다. 따라서 cpu과부하가 오게 된 상황입니다.
자 이제 수정해야지?
그럼 수정해보겠습니다.
생각보다 수정은 간단합니다.
우선 수정으로 우선순위가 높은 nginx 메트릭 로그 레벨을 낮추도록 하겠습니다.
아까 보여드린 nginx.conf파일의 /nginx_statsu만 수정하면 됩니다.
location /nginx_status {
stub_status;
allow all;
deny all;
access_log off; # access_log는 작성하지 않겠다.
}
그럼 다시 로그를 살펴보겠습니다.
- - [26/Jan/2025:13:43:10 +0900] "GET /blog/ HTTP/1.1" 200 17166 "https://hongjunghoon.com/blog/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36"
- - [26/Jan/2025:13:43:14 +0900] "GET /blog/29/ HTTP/1.1" 200 23369 "https://hongjunghoon.com/blog/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36"
- - [26/Jan/2025:13:43:14 +0900] "GET /grafana/api/live/ws HTTP/1.1" 401 40 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36"
사라졌네요! 그럼 이렇게 마무리하면 좋겠지만. 저에겐 아직 할 일이 남았습니다.
- 아무리 그래도 fail2ban이 이렇게 리소스를 잡을 이유가 있나?
- access.log를 보니까 오래 된 데이터까지 남아있었습니다.
마저 해결해보자
🤷🏻♂️아무리 그래도 fail2ban이 이렇게 리소스를 잡을 이유가 있나?
nginx가 부하가 걸릴 이유가 뭐가 있을까?? 하고 구글링 해봤습니다.
첫 번째로 우선 로그를 살펴보겠습니다.
2025-01-26 12:37:18,077 fail2ban.actions [38562]: NOTICE [sshd] Restore Ban 185.142.*
2025-01-26 12:37:18,476 fail2ban.actions [38562]: NOTICE [sshd] Restore Ban 185.148.*
2025-01-26 12:37:18,723 fail2ban.actions [38562]: NOTICE [sshd] Restore Ban 185.149.*
2025-01-26 12:37:18,999 fail2ban.actions [38562]: NOTICE [sshd] Restore Ban 185.169.*
2025-01-26 12:37:19,281 fail2ban.actions [38562]: NOTICE [sshd] Restore Ban 185.182.*
2025-01-26 12:37:19,528 fail2ban.actions [38562]: NOTICE [sshd] Restore Ban 185.183.*
Restore Ban?? ban 된 ip를 다시 저장하는 작업이 필요한가?
이는 fail2ban의 작동 매커니즘을 보면 알 수 있습니다. fail2ban은 서버가 재부팅된다거나, systemctl restart fail2ban
등으로 서비스가 재부팅될경우, fail2ban은 db에 갖고있는 ip리스트들을 다시한번 Restore 하면서 저장합니다.
이 때, 서버에 부하가 걸릴 수 있다는것을 알아냈습니다.
그럼 시간이 걸리는게 당연합니다. 초기에 jail.conf의 bantime = -1로 설정해서 영구적으로 ban 되도록 설정했거든요
따라서 여태 ban 된 ip는 3900개가 넘습니다.
따라서 bantime = 48h 로 수정해서 2일동안 ban 을 유지하도록 수정하였습니다.
🤷🏻♂️access.log를 보니까 오래 된 데이터까지 남아있었습니다.
현재 access.log의 파일 크기를 살펴보면 108MB정도 되네요. 너무 큽니다.
$ ls -l /opt/container_webservice/logs/
total 106200
-rw-r--r-- 1 root root 107790360 Jan 26 14:01 access.log
-rw-r--r-- 1 root root 943475 Jan 26 13:55 error.log
저희는 로그 파일을 자동으로 관리해주는 logrotate를 사용해보겠습니다.
sudo nano /etc/logrotate.d/nginx #logratate 폴더에 nginx 파일을 하나 만들어줍니다.
/opt/container_webservice/logs/access.log /opt/container_webservice/logs/error.log {
daily # 매일 로그 파일을 회전
rotate 7 # 최근 7개의 로그 파일만 유지
compress # 오래된 로그를 gzip으로 압축
delaycompress # 가장 최근 로그는 압축하지 않음
missingok # 로그 파일이 없어도 에러 발생하지 않음
notifempty # 비어있는 로그 파일은 무시
create 0644 root root # 새 로그 파일 생성 시 권한과 소유자 설정
postrotate
systemctl reload nginx # 로그 파일 회전 후 NGINX 다시 로드
endscript
}
이렇게 현재 access.log의 경로를 잡아주고, 각각의 설정값을 넣어주면, 로그는 자동으로 logrotate가 효율적으로 관리해줄겁니다.
마지막으로, CPU 점유율이 확실히 줄어든 모습입니다.
끝으로
오늘 블로그에 작성한 에러는 전혀 예상치 못했지만, 이러한 경험 하나하나가 나중에 다 소중한 자산이 될 걸 알고있습니다.
만약 제가 서버를 비싼값주고 좋은 성능으로 구매했다면 이런 경험을 하지 못했을수도 있었겠죠.
이게 아직까지 제가 가장 저렴한 서버를 유지하는 이유입니다. (절대 돈 없어서 그런거 아닙니다.)
이 게시글을 보시는 분이라면 어떤 에러가 생긴다 한들 현명하게 해결 할 수 있길 바라면서 포스트 마무리하겠습니다.
새해 복 많이 받으세요!
Leave a Comment: