502 발생

평화로운 출근 시간에 해당 내용이 전달되었다.

이전 포스팅에서도 작성하였다시피 5xx대 에러는 서버와 직접적인 통신이 되지 않아 서버에 로그가 남지 않는 경우가 대다수이다. (서버에서 5xx대 에러를 응답하는 경우는 선녀다.)

발생 위치 확인

5xx에러가 발생하는 위치부터 확인을 해야하는데 해당 내용은
DNS 캐싱 문제로 인한 5xx Error
에 정리하였다.

그럼 다시 이번 에러는 어디서 발생했는지 확인해보니

ELB에서 502가 발생하였다.

로드밸런서 모니터링에서는 ELB와 Target에서 발생한 HTTP 상태코드를 보여주는데 웹 취약점을 돌릴 때 발생하는 502는 전부 ELB에서 발생하였다.

그러면 이제 502가 발생한 위치를 파악했으니 ALB Access Log를 확인해보았다.

ALB Access Log

https 2024-06-10T13:50:58.480543Z app/ALB-Address Source IP Destination IP 0.001 0.001 -1 502 - 298 679 "GET Domain-URL"

여기서 주목할만한 내용은 0.001 0.001 -1 값인데 각각 의미하는 내용은 아래와 같다.

request_processing_time : 0.001

  • LB가 요청을 수신한 시간부터 대상으로 요청을 전송한 시간까지의 총 경과 시간
  • LB가 대상으로 요청을 디스패치할 수 없는 경우 이 값은 -1로 설정

target_processing_time: 0.001

  • LB가 대상에 요청을 보낸 시간부터 대상이 응답 헤더를 보내기 시작할 때까지의 총 경과 시간
  • LB가 대상으로 요청을 디스패치할 수 없는 경우 이 값은 -1로 설정

response_processing_time: -1

  • LB가 대상에서 응답 헤더를 수신한 시간부터 클라이언트에 응답을 보내기 시작할 때까지의 총 경과 시간
  • LB가 대상으로부터 응답을 받지 못하면 이 값은 -1로 설정

즉, 로드밸런서는 들어온 요청을 수신하여 대상(서버)에게 전달을 하였고 해당 요청에 대해서 응답헤더를 받았지만 대상이 응답을 완료하기 전에 연결이 끊어졌음을 의미한다.

클라이언트 -> ALB: 요청 전송
ALB -> 백엔드 서버: 요청 전달
백엔드 서버 -> ALB: 응답 헤더 전송
백엔드 서버 --X ALB: 전체 페이로드 전송 전 연결 끊김

해당 내용에 대해서 Application Load Balancer HTTP 502 오류를 해결하려면 어떻게 해야 하나요?
를 참고하였는데

현재 우리가 발생하는 이유와 비슷한 내용이 포함되어 있었다.

Apache KeepAliveTimeout, ALB Connection idle timeout

결론은 ALB에서 FIN 플래그를 보내기 전에 서비스에서 FIN 플래그 보내지 못하게 해야한다는 내용이다.
즉, Apache(WEB Server)에서 KeepAliveTimeout 값 > ALB에서 Connection idle timeout 값이어야 한다.

기존 설정값은
Apache KeepAliveTimeout: 10
ALB Connection idle timeout: 60
이었는데 해당 값을 어떻게 조절해야하는지가 고민이 되었다.

그래서 선배님들에게 여쭤보았는데

위와 같은 감사한 답변을 받았다.

그런데...

해결 실패


무조건 성공할 줄 알았던 해결 내용이 실패하니 이젠 다른 설정값들이 괜히 문제점처럼 느껴졌다.

의심갔던 설정들은 아래와 같았다.

  1. MaxKeepAliveRequests (Apache)
    웹 취약점을 돌리면 분당 최대 1000회에 가까운 트래픽이 TCP 연결을 시도한다.
    이 설정은 하나의 지속적인 연결에서 서비스를 제공할 요청의 최대 값을 설정하는 값이다.
    해당 값은 100으로 설정되어 있는데 만약 이 설정이 문제였으면 서버 로그가 남았을 것이라고 판단된다.

  2. ProxyPass / {ALB-DNS-Address} disablereuse=On
    'disablereuse=On' 옵션은 백엔드 서버와의 연결을 재사용하지 않는 옵션이다.
    위 옵션으로 인해 높은 수의 연결 요청이 발생하면 서버의 연결 제한을 초과하거나 과부하를 유발하여 위 이슈가 발생할 수 있을거라 판단하였으나 위 옵션으로 인해 문제가 발생하면 504 에러가 발생한다고 한다.

TCP Dump로 패킷을 확인하고 싶었으나 웹 취약점 스캔은 글로벌(해외 지부)에서 돌리는 것이라 정확하게 언제 돌린다를 알 수 없었다.
그러다가 협조를 구해서 웹 취약점 스캔을 돌리는 시간을 전달받아 해당시간에 TCP Dump로 패킷을 확인하였다.

TCP Dump

17:02:09.259562 IP ALB-IP.63320 > WEB-SERVER-IP.http: Flags [S], seq 3514370013, win 26883, options [mss 8961,sackOK,TS val 1575149654 ecr 0,nop,wscale 8], length 0
17:02:09.259622 IP WEB-SERVER-IP.http > ALB-IP.63320: Flags [S.], seq 1747571872, ack 3514370014, win 62727, options [mss 8961,nop,wscale 10], length 0
17:02:09.260548 IP ALB-IP.63320 > WEB-SERVER-IP.http: Flags [.], ack 1, win 106, length 0
17:02:09.260695 IP ALB-IP.63320 > WEB-SERVER-IP.http: Flags [P.], seq 1:1246, ack 1, win 106, length 1245: HTTP: GET URI HTTP/1.1
17:02:09.260840 IP WEB-SERVER-IP.http > ALB-IP.63320: Flags [R], seq 1747571873, win 0, length 0
17:02:09.260846 IP ALB-IP.63320 > WEB-SERVER-IP.http: Flags [R], seq 3514370014, win 0, length 0

TCP 연결을 다 하고 GET 요청을 하니 서버에서 RST 패킷을 응답한다.

클라이언트(LB)             서버
   |                     |
   | ---- SYN ---->      |
   |                     |
   | <---- SYN-ACK ----  |
   |                     |
   | ---- ACK ---->      |
   |                     |
   | ---- HTTP GET ----> |
   |                     |
   |     <---- RST ----  |

그렇다면 이젠 서버(OS)에서 RST 플래그를 응답하는 경우가 어떤게 있는지 알아보아야 한다.

  1. Port Closed: 서버 애플리케이션이 특정 포트를 열고 있지 않아서, TCP 연결이 성립된 후 요청을 받을 수 없을 때 RST 패킷을 보냅니다.
    ▶️ 확인 결과: 포트 정상적으로 열려있다.

  2. Process Termination: 서버 애플리케이션이 비정상적으로 종료되거나 강제로 종료된 경우, 커널이 해당 포트로 오는 모든 연결을 RST로 응답할 수 있습니다.
    ▶️ 확인 결과: 프로세스는 정상적으로 살아있다.

  3. Application Level Error: 서버 애플리케이션이 특정 조건을 만족하지 않는 요청을 받을 때 의도적으로 RST 패킷을 보낼 수 있습니다. 예를 들어, 잘못된 요청 형식이거나 인증 실패 등이 있습니다.
    ▶️ 확인 결과: 가능성은 있으나 잘못된 요청 뿐만 아니라 루트로 오는 요청도 RST 플래그로 응답한다.

  4. Resource Exhaustion: 서버의 메모리나 파일 디스크립터 등 자원이 부족하여 더 이상 연결을 처리할 수 없는 경우 RST 패킷을 보낼 수 있습니다.
    ▶️ 확인 결과: 모니터링 결과 리소스 부족 현상은 보이지 않았다.

  5. 세션 타임아웃 (Session Timeout): 서버가 연결된 클라이언트 세션이 타임아웃된 것으로 간주하여 RST 패킷을 보낼 수 있습니다.
    ▶️ 확인 결과: 세션 타임아웃값은 질리도록 수정했다.

  6. 프로토콜 위반 (Protocol Violation): 클라이언트가 TCP/IP 프로토콜 규약을 위반하는 패킷을 보낸 경우 서버가 RST 패킷을 보낼 수 있습니다.
    ▶️ 확인 결과: 정상적인 패킷도 RST 플래그로 응답한다.

  7. 네트워크 이슈 (Network Issues): 네트워크 중간의 라우터나 스위치에서 문제가 발생하여 패킷이 잘못 전달되는 경우 RST 패킷이 발생할 수 있습니다.
    ▶️ 확인 결과: 502가 발생하는 와중에도 다른 접속에 대해서 200 응답을 한다.

  8. 방화벽 설정 (Firewall Configuration): 네트워크 방화벽이나 보안 장치가 특정 패킷을 차단하거나 정책에 의해 RST 패킷을 보낼 수 있습니다.
    ▶️ 확인 결과: 방화벽은 로드밸런서 앞단에 있고 IP는 화이트리스트 처리하고 스캔을 돌리는...... 어?

문제 해결

갑자기 든 생각이 런타임 보안 프로그램이 떠올랐다.
그리고 해당 콘솔로 이동해서 로그를 보는순간 허무해졌다...

해당 단계에서 Source IP에 대해서 차단 정책을 설정하고 모든 요청에 대해서 차단을 하고 있었다.

테스트를 진행해보니

  • 최초 공격은 Target에 대해서 502 발생 (애플리케이션 및 서버 로그 O)
  • IP 블랙리스트 등록 후에는 ELB에서 502 발생 (애플리케이션 및 서버 로그 X)

해결했다는 기쁨보다 '이 생각을 왜 못했지' 라는 허무함이 더 몰려왔다...
방화벽에서 차단을 했으면 로드밸런서까지 요청이 오지 못했다라는 생각을 하고 문제를 해결하려고 하니 방화벽 및 IPS에 대해서는 전혀 생각을 하지 않고 문제를 해결하려고 하고 있었다.

이렇게 본인 스스로 자책을 하며 찜찜하게 문제를 해결했다...

profile
Junior DevOps Engineer

0개의 댓글