JVM truststore를 사용해 사설 HTTPS 서버 호출하기
TOC
- Overview
- Java 애플리케이션의 HTTPS 요청
- 기본 SSLContext를 사용하는 경우
- custom SSLContext를 사용하는 경우
- HTTPS 요청이 실패하는 경우
- 정리
Overview
Java 애플리케이션이 사설 HTTPS 서버를 호출할 때 어떤 truststore가 서버 인증서 검증에 사용되는지 설명한다.
HTTP client가 기본 SSLContext를 사용하는지, custom SSLContext를 사용하는지에 따라 truststore가 달라진다.
Java 애플리케이션의 HTTPS 요청
Java 애플리케이션이 HTTPS 요청을 보내면 HTTP client는 SSLContext를 사용해 TLS 연결을 구성한다. SSLContext의 TrustManager는 truststore를 기준으로 서버 인증서를 검증한다.
flowchart LR
A[Java 애플리케이션] --> B[HTTP client]
B --> C[SSLContext]
C --> D[TrustManager]
D --> E[truststore]
E --> F{서버 인증서 검증}
F -->|성공| G[HTTPS 통신]
F -->|실패| H[TLS handshake 실패]
기본 SSLContext를 사용하는 경우
HTTP client에 custom SSLContext를 지정하지 않으면 기본 SSLContext를 사용한다. Java 11 HttpClient의 구현에도 다음과 같은 분기가 있다.
if (builder.sslContext == null) {
sslContext = SSLContext.getDefault();
} else {
sslContext = builder.sslContext;
}
기본 SSLContext는 JSSE의 TrustManager를 사용한다. 기본 SSLContext가 초기화될 때 JVM 시스템 속성에 지정된 truststore를 서버 인증서 검증에 사용한다.
java \
-Djavax.net.ssl.trustStore=/path/private-ca-truststore.p12 \
-Djavax.net.ssl.trustStorePassword="$TRUSTSTORE_PASSWORD" \
-Djavax.net.ssl.trustStoreType=PKCS12 \
Application
-Djavax.net.ssl.trustStore는 환경변수가 아니라 JVM 시스템 속성이다. 애플리케이션 코드가 .p12 파일을 직접 읽지 않아도, 기본 TLS 설정을 사용하는 HTTP client는 이 truststore를 사용할 수 있다.
custom SSLContext를 사용하는 경우
HTTP client에 custom SSLContext를 지정하면 JVM 기본 truststore 대신 해당 SSLContext에 설정된 truststore를 사용한다.
TrustManagerFactory factory =
TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()
);
factory.init(customTrustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, factory.getTrustManagers(), null);
HttpClient client = HttpClient.newBuilder()
.sslContext(sslContext)
.build();
이 방식에서는 customTrustStore를 애플리케이션이 선택한다. 따라서 JVM 시스템 속성에 기본 truststore를 지정했더라도, 이 client에는 custom truststore가 적용된다.
flowchart LR
A[애플리케이션이 선택한 truststore] --> B[TrustManagerFactory]
B --> C[custom SSLContext]
C --> D[HTTP client]
D --> E[선택한 truststore 기준 검증]
HTTPS 요청이 실패하는 경우
| 상황 | 먼저 확인할 내용 |
|---|---|
PKIX path building failed |
현재 사용 중인 truststore에 Root CA가 있는가 |
| JVM truststore 설정이 적용되지 않음 | HTTP client가 custom SSLContext를 사용하는가 |
| hostname 오류 | 요청 도메인과 인증서의 SAN이 일치하는가 |
| 인증서 경로 오류 | Intermediate CA를 포함한 인증서 경로가 완성되는가 |
정리
flowchart LR
A[HTTP client] --> B{Custom SSLContext specified?}
B -->|No| C[Default SSLContext]
B -->|Yes| D[Custom SSLContext]
C --> E[JVM system property trustStore]
D --> F[Selected truststore]
E --> G[Server certificate validation]
F --> G