Docker 배포 시 Elasticsearch SSL 인증 문제 해결

오형상·2025년 2월 16일
0

Ficket_elasticsearch

목록 보기
7/7

1. 문제 상황

로컬 환경에서는 Elasticsearch와의 통신이 정상적으로 이루어졌지만, Docker 환경에서 배포 후 애플리케이션이 Elasticsearch에 연결하려고 할 때 PKIX path building failed 오류가 발생했습니다. 이는 Elasticsearch의 인증서를 신뢰할 수 없는 문제로 인해 Java의 TrustStore에서 유효성을 확인하지 못하기 때문에 발생하는 문제입니다.

2. 문제 원인

  • 애플리케이션이 Elasticsearch와 보안 연결(SSL/TLS)을 설정하는 과정에서, Elasticsearch의 Self-signed SSL 인증서가 JVM의 기본 TrustStore에 등록되지 않았기 때문에 신뢰할 수 없는 인증서로 인식됨
  • Docker 컨테이너 내부의 Java 환경에서 Elasticsearch의 CA 인증서를 신뢰하도록 설정하지 않았음

3. 해결 방법

3.1 Elasticsearch 인증서 등록

Docker 컨테이너 내에서 Elasticsearch의 인증서를 신뢰하도록 TrustStore에 추가해야 합니다. 이를 위해 Dockerfile을 수정하여 인증서를 추가하는 과정을 포함했습니다.

# Elasticsearch CA 인증서 복사
COPY esCert/elasticsearch.crt /usr/local/share/ca-certificates/ca.crt

# Java TrustStore에 `ca.crt` 등록
RUN keytool -import -trustcacerts -keystore /usr/local/openjdk-17/lib/security/cacerts \
    -storepass changeit -noprompt -alias elasticsearch-root-ca \
    -file /usr/local/share/ca-certificates/ca.crt

이렇게 하면 Elasticsearch의 CA 인증서를 Java의 TrustStore에 등록하여 신뢰할 수 있도록 설정할 수 있습니다.

3.2 ElasticsearchClient 설정 변경

기존에는 애플리케이션 코드에서 SSLContext를 수동으로 생성하여 인증서를 로드했지만, 이를 JVM 기본 TrustStore를 사용하도록 변경하여 인증서 관리를 단순화했습니다.

변경 전 (수동 SSLContext 설정)

private SSLContext getSSLContext() throws Exception {
    byte[] decodedCertificate = Base64.getMimeDecoder().decode(certificateBase64);

    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    X509Certificate ca;
    try (InputStream certificateInputStream = new ByteArrayInputStream(decodedCertificate)) {
        ca = (X509Certificate) certificateFactory.generateCertificate(certificateInputStream);
    }

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(keyStore);

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), new java.security.SecureRandom());
    return sslContext;
}

변경 후 (JVM 기본 TrustStore 사용)

@Bean
public RestClient restClient() throws Exception {
    // JVM 기본 TrustStore 사용 (별도의 인증서 로드 필요 없음)
    SSLContext sslContext = SSLContext.getDefault();

    RestClientBuilder builder = RestClient.builder(new HttpHost(host, port, "https"))
            .setHttpClientConfigCallback(httpAsyncClientBuilder -> httpAsyncClientBuilder
                    .setSSLContext(sslContext) // TrustStore 사용
                    .setDefaultCredentialsProvider(credentialsProvider()));

    return builder.build();
}

3.3 Dockerfile 수정 사항

Docker 환경에서 애플리케이션을 실행할 때 Elasticsearch의 CA 인증서를 신뢰하도록 하기 위해 Dockerfile을 수정했습니다.

# Base Image
FROM openjdk:17-jdk-slim

# 작업 디렉토리 설정
WORKDIR /app

# Elasticsearch CA 인증서 복사
COPY esCert/elasticsearch.crt /usr/local/share/ca-certificates/ca.crt

# Java TrustStore에 `ca.crt` 등록
RUN keytool -import -trustcacerts -keystore /usr/local/openjdk-17/lib/security/cacerts \
    -storepass changeit -noprompt -alias elasticsearch-root-ca \
    -file /usr/local/share/ca-certificates/ca.crt

# JAR 파일 복사
COPY Ficket/ficket-search/build/libs/ficket-search-0.0.1-SNAPSHOT.jar app.jar

# 애플리케이션 실행 포트
EXPOSE 8094

# 애플리케이션 실행
CMD ["java", "-Duser.timezone=Asia/Seoul", \
     "-Dspring.application.name=search-service", \
     "-Dspring.profiles.active=prod", \
     "-Dspring.config.import=optional:configserver:http://config-server:8888", \
     "-Djavax.net.ssl.trustStore=/usr/local/openjdk-17/lib/security/cacerts", \
     "-Djavax.net.ssl.trustStorePassword=changeit", \
     "-jar", "app.jar"]

이제 Elasticsearch의 인증서를 Docker 컨테이너 내부에서 올바르게 신뢰하도록 설정할 수 있으며, 이를 통해 PKIX path building failed 오류를 해결할 수 있습니다.

0개의 댓글