조회수: 21

PKIX path building failed (Java) 해결

PKIX path building failed: Java가 인증서를 자체 cacerts 저장소의 루트로 연결하지 못한 것입니다. 빠진 CA를 임포트하거나 서버를 고칩니다. 무료 즉시 진단으로 바로 확인.

내 도메인에 이 문제가 있는지 지금 확인

무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.

Problem

Java 클라이언트가 javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target를 던집니다. Java가 서버 인증서를 받아 신뢰하는 루트까지 체인을 만들려 했지만 실패한 것입니다. 빠진 조각은 Java 자체의 신뢰 저장소(cacerts) 안에 있으며, 이는 운영체제의 것과 별개입니다. 서버가 체인을 완성하는 데 필요한 중간 인증서를 안 보냈거나, 이 JVM이 쓰는 cacerts에 루트/중간이 아예 없거나, 프록시가 cacerts가 들어본 적 없는 사설 CA로 연결을 재서명한 것입니다. 인증서가 깨진 경우는 드뭅니다 — 신뢰 앵커가 없는 것입니다.

Symptoms

  • 스택 트레이스가 SunCertPathBuilderException을 지목하고 unable to find valid certification path to requested target로 끝납니다. 상위로는 보통 SSLHandshakeException, 한 단계 아래에는 sun.security.validator.ValidatorException으로 나타납니다.
  • 같은 호스트가 브라우저와 같은 컴퓨터의 curl에서는 잘 열리는데, 모든 Java 프로세스 — 의존성을 내려받는 빌드, API를 호출하는 앱, TLS 위의 JDBC 드라이버 — 는 실패합니다.
  • 새/최소 JDK 이미지로 옮긴 직후, 프록시가 있는 회사 노트북, 또는 사설 CA를 쓰는 내부 서비스에서 흔히 나타납니다.
  • openssl s_client -connect HOST:443 -servername HOST는 OS 눈에 완전해 보이는 체인을 보여주는데 Java는 여전히 거부합니다 — 이것이 서버 다운이 아니라 cacerts 문제라는 신호입니다.

Top 3 Causes

  1. CA가 Java cacerts에 없음 - Java는 자체 신뢰 저장소를 유지하고, 따로 지시하지 않는 한 OS 저장소를 무시합니다. JVM이 오래됐거나(번들 루트가 CA보다 앞섬), 축소됐거나, 브라우저·curl이 신뢰하는 것과 그냥 다른 런타임이면, 완벽히 공개된 인증서도 실패할 수 있습니다. “다른 건 다 되는데 Java만 안 됨”의 기본 설명입니다.
  2. 서버가 중간 인증서를 안 보냄 - 서버가 리프만 보내고 루트로 이어줄 중간 인증서를 생략합니다. 브라우저는 빠진 중간 인증서를 자동으로 가져오지만, Java는 기본적으로 AIA fetching을 하지 않아 체인을 못 만듭니다. 여기서 진짜 버그는 서버에 있고(풀체인 배포), 중간 인증서를 cacerts에 임포트하는 건 한 기기용 로컬 임시방편일 뿐입니다.
  3. 프록시나 백신이 TLS를 가로챔 - 회사 프록시나 ‘HTTPS 검사’ 백신이 연결을 복호화해 사설 CA로 재서명합니다. IT가 거기에 설치해 뒀으니 OS와 브라우저는 그 CA를 신뢰하지만, Java의 cacerts에는 없어 모든 Java TLS 호출이 PKIX path building failed로 실패합니다. 해결은 그 프록시 루트를 Java가 쓰는 truststore에 추가하는 것 — 가로채기가 정당한지 확인한 뒤에.

Diagnose with DechoNet

  • SSL 점검은 서버가 실제로 보내는 체인을 보여줍니다. 여기서 중간 인증서가 빠졌다면 원인 #2이고 해결은 서버에 있습니다. 공개 인터넷에서는 체인이 완전한데 내 컴퓨터의 Java만 실패하면, 앵커가 로컬에 없는 것 — 이 JVM의 cacerts에 CA가 그냥 없거나(원인 #1), 프록시가 cacerts에 없는 루트로 트래픽을 재서명하는 것(원인 #3)입니다.
  • HTTP 점검은 TLS를 제쳐두고 엔드포인트가 응답하는지 확인해 줘서, 신뢰 저장소 문제와 도달 불가 서비스를 구분하게 해줍니다.

Resolution Checklist

  • 관여하는 JVM을 먼저 찾으세요: which java, java -version, 그리고 프로세스의 JAVA_HOME. 고치는 cacerts는 실제로 앱을 띄우는 JDK/JRE의 것이어야 하며, 아니면 아무것도 바뀌지 않습니다.
  • 제시된 체인을 점검하세요: openssl s_client -connect YOUR_DOMAIN:443 -servername YOUR_DOMAIN -showcerts. 중간 인증서 없이 CERTIFICATE 블록이 하나 → 원인 #2; 풀체인을 배포해 서버를 고치고 SSL 점검으로 확인하세요.
  • 서버 체인은 완전한데 Java가 여전히 실패하면 빠진 CA를 cacerts에 임포트하세요: keytool -importcert -trustcacerts -alias your-ca -file ca.crt -keystore "$JAVA_HOME/lib/security/cacerts" -storepass changeit. 리프가 아니라 중간/루트 CA를 임포트하세요 — 리프는 갱신마다 바뀌지만 CA는 그대로입니다.
  • JDK의 cacerts를 직접 편집하기보다 전용 truststore를 쓰세요(JDK 업그레이드가 cacerts를 교체하며 임포트를 조용히 날립니다). -Djavax.net.ssl.trustStore=/path/store.jks -Djavax.net.ssl.trustStorePassword=...로 앱이 그것을 가리키게 하세요.
  • 체인이 정확히 어디서 끊기는지 보려면 핸드셰이크 로깅을 켜세요: -Djavax.net.debug=ssl:handshake. Atlassian의 작은 SSLPoke 클래스는 전체 앱 없이 현재 truststore로 단일 호스트를 테스트하는 빠른 방법입니다.
  • 정당한 회사 프록시라면 그 루트를 Java가 쓰는 truststore에 같은 방식으로 keytool로 임포트하세요. 가로채는 CA를 특정할 수 없다면 임포트하지 말고, 정말 우리 IT 부서의 프록시인지 먼저 확인하세요.

When to Escalate

  • 인터넷에서는 완전한 체인이 보이는데 특정 기기의 Java만 실패하면, 그 JVM들은 CA가 없거나 루트가 Java에 배포된 적 없는 프록시 뒤에 있는 것입니다. 이는 함대/IT 작업 — CA를 베이스 이미지나 관리 truststore에 넣는 것이지, 개발자 한 명의 노트북에 넣는 게 아닙니다.
  • 이를 없애려고 전부 신뢰 TrustManager-Dcom.sun.net.ssl... 편법에 손대지 마세요. 검증을 끄면, 나를 지키던 앵커 누락 오류가, 반대편이 내 진짜 서버든 위조 인증서를 든 공격자든 똑같이 동작하는 조용하고 영구적인 구멍으로 바뀝니다.

관련 도구

관련 가이드

가이드 공유

[Ad] Guide Detail Inline
← 전체 가이드 보기