2025년 3월 27일
이론
조회 : 42|2분 읽기

JAVA 통신에서 SSL

사설 SSL with JAVA

몇 시간 전, 아무 문제 없던 자바 애플리케이션에서 메일 서버와의 통신이 갑자기 실패하기 시작했습니다.
로그를 보니 SSL 관련 예외가 발생하고 있었고, 이전까지는 없던 이슈였기 때문에 원인을 파악하는 데 시간이 걸렸습니다.
운영 환경에서 이런 SSL 이슈는 장애로 이어졌고 후에 인증서와 관련된 오류 처리를 빠르게 하기 위해 정리해봅니다.

✅ 상황 설명

해당 애플리케이션은 메일 서버와 HTTPS 통신을 하고 있었습니다.
그런데 몇 시간 전부터 메일 발송 및 상태 확인 요청이 전부 실패하기 시작했고 로그에는 다음과 같은 에러 메시지가 찍히고 있었습니다.
bash
1javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
2PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
3unable to find valid certification path to requested target
자바 환경에서 볼 수 있는 SSL 에러로, 서버가 제공한 인증서를 신뢰할 수 없을 때 발생하는 예외입니다.

🔍 원인 분석

처음엔 인증서 만료를 의심했지만, 메일 서버 인증서는 여전히 유효한 상태였습니다.
알고 보니 메일 서버 앞단에 새로운 보안 솔루션 장비(SSL 프록시) 가 추가되었고, 이 장비가 메일 서버의 앞단을 수행하고 있었습니다.
문제는 이 솔루션이 사용하는 인증서가 공인 루트 CA가 아닌, 해당 솔루션 자체에서 발급한 인증서였다는 점입니다.
JVM은 기본적으로 $JAVA_HOME/lib/security/cacerts 내 truststore에 등록된 인증서만을 신뢰하기 때문에 자바 애플리케이션은 이 인증서를 신뢰하지 않았고, SSL 핸드셰이크에 실패했던 것입니다.

🛠 해결 방법

1️⃣ 해당 도메인의 SSL 인증서 추출

우선 문제가 된 도메인에서 사용 중인 인증서를 직접 추출해야 했습니다.
다음 명령어로 서버가 제공하는 인증서를 저장할 수 있습니다:
bash
1echo | openssl s_client -connect mail.server.domain:443 | openssl x509 -outform PEM > ssl-mail.crt
  • mail.server.domain:443 < 실제 서버 도메인과 포트를 입력해야 합니다.
  • 실행하면 ssl-mail.crt 파일이 생성되며, 바로 이 인증서를 등록해야 합니다.

2️⃣ 인증서를 JVM truststore에 등록

이제 인증서를 자바의 truststore(cacerts)에 등록합니다.
keytool을 사용해 다음과 같이 등록할 수 있습니다:
bash
1sudo keytool -import -trustcacerts \
2  -keystore $JAVA_HOME/lib/security/cacerts \
3  -storepass changeit \
4  -alias ssl-mail.crt \
5  -file ssl-mail.crt
  • 기본 비밀번호는 보통 changeit입니다.
  • -alias는 등록된 인증서를 식별하기 위한 이름으로, 중복되지 않게 설정합니다.
  • 등록 시 "신뢰하시겠습니까?"라는 질문이 나오면 yes 입력.

3️⃣ 등록 확인

등록이 정상적으로 되었는지 확인하려면 다음 명령어를 사용합니다:
bash
1sudo keytool -list \
2  -keystore $JAVA_HOME/lib/security/cacerts \
3  -storepass changeit \
4  -alias ssl-mail.crt
또는 전체 목록을 보고 싶다면:
bash
1sudo keytool -list \
2  -keystore $JAVA_HOME/lib/security/cacerts \
3  -storepass changeit | grep ssl-mail

4️⃣ 애플리케이션 재시작

JVM은 truststore를 애플리케이션 시작 시점에 로딩하기 때문에,
등록 후에는 반드시 애플리케이션을 재시작해야 변경 사항이 적용됩니다.
bash
1# 예: systemd 서비스인 경우
2sudo systemctl restart my-java-service
3
4# 단순 jar 파일이면
5Ctrl + C 로 종료 후 다시 실행

✅ 결과 확인

재시작 후 SSL 통신이 정상적으로 이루어지는 것을 확인했습니다.
이전까지 실패하던 메일 발송, 수신 API가 모두 정상 동작했고
더 이상 SSLHandshakeException이 발생하지 않았습니다.

🧼 운영 팁: 등록된 인증서 삭제 방법

일정 기간 후 더 이상 해당 인증서가 필요 없어졌거나, 테스트용으로 임시 등록한 경우 삭제가 필요할 수 있습니다.
bash
1sudo keytool -delete \
2  -alias ssl-mail.crt \
3  -keystore $JAVA_HOME/lib/security/cacerts \
4  -storepass changeit
삭제 후에도 역시 JVM이나 애플리케이션 재시작이 필요합니다.

🧠 마무리하며

이슈를 겪으면서 다음과 같은 점들을 다시 한 번 확인하게 되었습니다:
  • Java는 truststore에 등록된 인증서만 신뢰합니다.
  • 외부 시스템 구조(예: SSL 프록시, 보안 장비)가 변경되면 SSL 에러가 발생할 수 있습니다.
  • 에러 메시지가 다소 난해할 수 있지만, PKIX path building failed → 인증서 체인 문제를 의미합니다.
  • 인증서 등록 후에는 반드시 애플리케이션을 재시작해야 적용됩니다.
  • 운영 환경에서는 인증서 등록/삭제 작업 시 신중하게 진행해야 합니다. 실수로 기존 공인 인증서를 덮어쓰는 일은 없어야 합니다.