
최근 A 서버에서 B 서버를 호출할 때 일부 요청은 정상적으로 처리되는 반면, 일부 요청에서 javax.net.ssl.SSLException 에러가 발생하는 현상을 겪었습니다. 더 확인해봐야할 것은 이 문제가 B 서버뿐 아니라 C, D 서버를 호출할 때도 동일하게 발생했다는 점이었습니다.
이러한 에러 발생 패턴을 통해, 문제의 원인은 A 서버 자체 또는 공통으로 사용하는 네트워크 통신 로직에 있을 것이라고 판단했습니다. 그리고 실제로 원인을 찾아보니 TLS 설정 문제였습니다.
TLS(Transport Layer Security) 는 인터넷 환경에서 데이터를 안전하게 주고받기 위해 사용하는 암호화 통신 프로토콜입니다.
우리가 흔히 사용하는 HTTPS는 바로 이 TLS 위에서 작동하는 HTTP 프로토콜이라고 보시면 됩니다.
TLS의 핵심 역할:
암호화: 데이터를 제3자가 볼 수 없도록 보호
무결성: 데이터가 전송 중에 변경되지 않았는지 확인
인증: 통신하는 상대방이 신뢰할 수 있는지 검증 (주로 인증서를 통해)
❓ 모든 요청에 TLS 설정이 필요한가?
모든 요청이 TLS 설정을 요구하지는 않습니다.
하지만 중요한 기준은 바로 요청이 HTTPS를 사용하는지 여부입니다.
요청 방식 TLS 필요 여부 설명
HTTP ❌ 필요 없음 암호화되지 않은 평문 통신
HTTPS ✅ 반드시 필요 TLS를 사용한 보안 통신
즉, HTTPS로 통신하는 모든 요청에는 TLS 설정이 필요하며, 서버와 클라이언트는 서로 호환되는 TLS 버전 및 Cipher suite를 지원해야 합니다.
이번 케이스에서 A 서버는 B 서버뿐 아니라 C, D 서버에도 요청을 보내고 있었고, 이들 모두 AWS Load Balancer(LB)를 통해 구성되어 있었습니다.
A 서버의 요청 흐름:
A 서버 → AWS Load Balancer → B, C, D 서버
이때 요청 중 일부만 javax.net.ssl.SSLException 에러가 발생했고, 그 이유는 바로 AWS Load Balancer의 TLS 설정(Security policy)과 A 서버의 TLS 설정이 맞지 않았기 때문이었습니다.
AWS에서는 Load Balancer에 대해 Security policy라는 설정 항목을 제공합니다. 이 설정을 통해 허용할 TLS 버전과 Cipher suite를 제한할 수 있습니다.
최근 서버를 재구성하면서, 이전과 다른 Security policy인 ELBSecurityPolicy-TLS13-1-2-Res-2021-06을 적용했는데, 이 정책은 TLS 1.2 이상과 특정 암호화 방식만을 허용합니다.
하지만 A 서버는 기본 설정으로 TLS 요청을 보냈기 때문에 TLS설정이 무작위로 설정되었고 그 중 일부 요청들이 협상 과정에서 실패하여 SSLException이 발생한 것이었습니다.
문제를 해결하기 위해 A 서버에서 명시적으로 TLS 버전과 Cipher suite를 지정했습니다. 이렇게 하면 Load Balancer와 TLS 협상 과정에서 호환 문제 없이 통신이 가능해집니다.
✅ 참고: Java에서는 SSLContext, SSLSocketFactory, HttpClient.Builder, RestTemplate 등을 통해 TLS 설정을 직접 지정할 수 있습니다.
✅ 정리