1. 문제 상황2. 발생 에러3. 문제 원인4. 해결 방법1) Keycloak 서버에서 인증서 체인 직접 추출2) Root + Intermediate CA만 truststore에 등록3) JVM 실행 옵션에 커스텀 truststore 설정4) 서비스 재기동 후 정상 동작 확인5. 마무리
1. 문제 상황
- Java 애플리케이션(JDK 1.8)에서 Keycloak(HTTPS)로 토큰 요청 시 TLS Handshake 도중 서버 인증서 체인을 신뢰하지 못해 실패함
2. 발생 에러
- 최초 에러: truststore에 CA 인증서 없음 → PKIX path building failed
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
- 2차 에러: fullchain.pem을 keytool로 import했으나, keytool은 PEM 안의 첫 번째 인증서(Leaf)만 등록하기 때문에 상위 CA가 빠져 동일 오류 발생
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
3. 문제 원인
- TLS Handshake 시 서버(Keycloak)는 서버 인증서(Leaf) 를 클라이언트(Java)에게 전달함. 클라이언트는 truststore에 저장된 Root CA 및 Intermediate CA 공개키로 해당 인증서의 위조 여부를 검증해야 함
- 하지만 Java truststore에 서버 인증서를 서명한 상위 CA 인증서(Root/Intermediate) 가 없어서 인증서 Chain이 신뢰 기준(Root)까지 이어지지 못했고 결과적으로 PKIX path building failed 오류가 발생
Leaf → Intermediate → Root ↑ (truststore에 없음 → Chain 단절)
즉,
시도 | 조치 | 실패 원인 | 결과 |
1차 | truststore 비어 있음 | CA 정보 없음 | PKIX 오류 |
2차 | fullchain.pem 통째 추가 | Leaf만 추가되었고 CA 누락 | 동일 오류 |
4. 해결 방법
1) Keycloak 서버에서 인증서 체인 직접 추출
- 운영 신뢰성을 위해 Keycloak 서버와 통신하여 실제 인증서 Chain을 추출한 뒤 Root / Intermediate / Leaf 인증서를 분리 저장
openssl s_client -connect <keycloak-host>:443 -servername <keycloak-host> -showcerts </dev/null 2>/dev/null \ | awk ' /-----BEGIN CERTIFICATE-----/{ n++; fn = sprintf("cert-%02d.pem", n); writing=1 } writing{ print > fn } /-----END CERTIFICATE-----/{ close(fn); writing=0 }'
2) Root + Intermediate CA만 truststore에 등록
- Leaf 인증서는 truststore 등록 불필요 (서버가 Handshake 과정에서 전달함)
# Root CA 등록 keytool -importcert \ -alias root-ca \ -file isrgrootx1.pem \ -keystore custom-truststore.jks \ -storepass <password> \ -noprompt # Intermediate CA 등록 keytool -importcert \ -alias intermediate-ca \ -file cert-02.pem \ -keystore custom-truststore.jks \ -storepass <password> \ -noprompt
3) JVM 실행 옵션에 커스텀 truststore 설정
-Djavax.net.ssl.trustStore=/path/to/custom-truststore.jks -Djavax.net.ssl.trustStorePassword=<password> -Djavax.net.ssl.trustStoreType=JKS
4) 서비스 재기동 후 정상 동작 확인
- TLS Handshake 및 PKIX 검증 정상 완료
- OAuth2 토큰 요청 성공
5. 마무리
서버 인증서(Leaf) 전달 → CA 공개키(truststore)로 서명 검증 → 암호화 채널 성립 → 요청/응답 수행