Blog
clouderaimpalajdbctlsldapkeytool

Cloudera Impala JDBC 에 TLS + LDAP 인증 적용하기

PKIX 에러에서 해방되기. 인증서 체인 추출, 전용 TrustStore 만들기, Impala JDBC URL 작성까지 순수 JDBC로 구현하기.

Data Dynamics2026年4月11日16 min read
This post is not yet translated. The original Korean version is shown below.

개발 환경에서는 평문으로 잘 붙던 Cloudera Impala 가 운영 환경으로 넘어가는 순간 PKIX path building failed 라는 수수께끼 같은 에러와 함께 연결이 뚝 끊기는 경험, 다들 한 번쯤 해보셨죠? 마치 집 열쇠는 있는데 현관 잠금장치가 바뀐 것과 같습니다. 이 글은 Cloudera Impala JDBC Connector (Simba 기반 상용 드라이버) 만 사용하고, 프레임워크 없이 순수 JDBC DriverManager 로 TLS + LDAP 인증을 적용해 Impala 에 접속하는 전체 과정을 정리합니다.

이 글에서 배우는 것

  • PKIX path building failed 에러의 원인과 해결 방법
  • 애플리케이션 전용 TrustStore(JKS) 를 만드는 이유와 방법
  • Cloudera Impala JDBC URL 파라미터의 의미와 올바른 작성법
  • 비밀 정보를 URL 에 넣지 않고 Properties 로 분리하는 패턴
  • 자주 만나는 에러 5종 세트와 그 해결법

TL;DR

  1. 클러스터 관리자에게 root CA 인증서 PEM 파일 (ca.pem) 을 요청해서 받도록 한다.
  2. keytool 로 애플리케이션 전용 TrustStore (JKS) 를 새로 만들어 CA 를 import 한다.
  3. JDBC URL 에 SSL=1;SSLTrustStore=...;AuthMech=3 를 붙이고 UID/PWD/SSLTrustStorePwdProperties 로 분리한다.
  4. Class.forName("com.cloudera.impala.jdbc.Driver")DriverManager.getConnection().
  5. SELECT 1 이 실행하면 완료.

1. 준비물

요리를 시작하기 전에 재료를 먼저 챙기듯, 아래 다섯 가지가 모두 갖춰져야 진행할 수 있습니다. 하나라도 없으면 클러스터 관리자에게 요청하세요.

#항목예시
1Cloudera Impala JDBC Connector JARImpalaJDBC42.jar + 함께 제공되는 의존성 JAR가 있다면 추가
2TLS 가 켜진 Impala daemon 엔드포인트impalad-lb.corp.example.com:21050
3클러스터의 root CA 인증서 (PEM)ca.pem
4LDAP 계정UID / PWD. 형식은 관리자에게 확인
5JDK 8 이상java -version

체인 전체가 아니라 root CA 만 있으면 충분합니다.

2. TLS 인증서를 TrustStore 에 import

2.1 왜 애플리케이션 전용 TrustStore 를 쓰는가

JDK 시스템 인증서 저장소(cacerts)에 직접 넣고 싶은 유혹이 들 수 있습니다. 하지만 사무실 건물 마스터키를 개인 사물함에 보관하는 셈이라, 다음 이유로 권장하지 않습니다.

  • 같은 JDK 를 쓰는 다른 애플리케이션 전체에 영향을 줄 수 있음
  • JDK 를 업그레이드하면 cacerts 가 교체되어 import 가 사라짐
  • 컨테이너 이미지를 매번 다시 빌드해야 함

대신 애플리케이션과 함께 배포하는 전용 TrustStore 파일 (JKS) 을 새로 만드는 것이 정답입니다. JDK 교체에 영향이 없고, 보안 경계도 명확해지며, Docker 이미지에는 COPY truststore.jks /app/ 한 줄이면 끝납니다.

한 문장으로: TrustStore 는 애플리케이션 전용으로 만들면 JDK 업그레이드나 컨테이너 교체에도 흔들리지 않습니다.

2.2 인증서 확보

인증서를 확보하는 방법은 두 가지입니다. 관리자가 파일을 바로 줄 수 있다면 방법 1이 훨씬 편하고, 그렇지 않다면 서버에서 직접 추출하는 방법 2를 쓰면 됩니다.

방법 1 — 관리자에게 PEM 파일 받기 (권장)

받은 파일이 올바른지 먼저 확인합니다.

openssl x509 -in ca.pem -noout -subject -issuer -dates

Subject:Issuer: 가 같으면 root CA 입니다.

방법 2 — openssl s_client 로 서버에서 직접 추출

openssl s_client -connect impalad-lb.corp.example.com:21050 \
  -showcerts </dev/null 2>/dev/null \
  | awk '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/' \
  > impala-chain.pem

체인에서 root CA 를 찾으려면 각 인증서의 subject/issuer 를 비교합니다.

csplit -z -s -f cert- -b '%02d.pem' impala-chain.pem \
  '/-----BEGIN CERTIFICATE-----/' '{*}'
 
for f in cert-*.pem; do
  echo "=== $f ==="
  openssl x509 -in "$f" -noout -subject -issuer
done

Subject:Issuer: 가 동일한 파일이 root CA 입니다.

2.3 keytool 로 TrustStore 만들기

드디어 이 글의 핵심 단계입니다. 명령어 한 줄로 CA 인증서를 새 TrustStore 에 담아두면, Java 애플리케이션이 Impala 서버를 신뢰할 수 있게 됩니다.

keytool -importcert -noprompt \
  -file ca.pem \
  -alias cloudera-root-ca \
  -keystore ./truststore.jks \
  -storepass 'CHANGE_ME_STRONG_PASSPHRASE' \
  -storetype JKS

각 옵션의 의미는 다음과 같습니다.

옵션설명
-importcertX.509 인증서를 keystore 에 추가
-noprompt프롬프트 건너뛰기. 스크립트에서 필수
-file넣을 인증서 파일
-aliaskeystore 내부 식별자. 같은 alias 로 다시 넣으면 덮어쓰기됨
-keystoreTrustStore 파일 경로. 없으면 새로 생성
-storepasskeystore 암호. 환경변수로 주입 권장
-storetype JKS포맷 명시. JDK 9+ 기본은 PKCS12 이므로 명시하는 편이 안전

2.4 TrustStore 검증

만든 TrustStore 에 CA 가 제대로 들어갔는지 확인합니다.

keytool -list -v \
  -keystore ./truststore.jks \
  -storepass 'CHANGE_ME_STRONG_PASSPHRASE' \
  -alias cloudera-root-ca

출력에서 확인할 포인트:

  • Owner: 가 받은 root CA 의 DN 과 일치
  • Valid from ... until: 만료일
  • SHA-256 fingerprint 를 관리자가 알려준 값과 대조 (MITM 방어의 최후 보루)

2.5 자주 놓치는 함정

배포 전에 한 번 훑어보세요.

  • Root CA 만 넣었는가?
  • -alias 가 기존 것과 중복되지 않는가
  • TrustStore 경로가 실행 시점에 접근 가능한가. 상대경로 주의
  • 인증서 만료 모니터링이 있는가
  • -storepass 가 소스코드에 하드코딩되지 않았는가

3. Impala JDBC URL 작성

3.1 URL 템플릿

jdbc:impala://impalad-lb.corp.example.com:21050;AuthMech=3;SSL=1;SSLTrustStore=/app/truststore.jks

3.2 파라미터 설명

파라미터설명
AuthMech3User Name And Password. LDAP 바인드 인증을 의미
SSL1TLS 활성화. 반드시 대문자 SSL=1. 소문자 ssl=true 는 Apache Hive JDBC 문법이며 Cloudera 드라이버에서 인식 안 됨
SSLTrustStore/app/truststore.jks앞서 만든 TrustStore 의 절대경로

3.3 보안 민감 정보는 URL 에 넣지 말 것

UID/PWDSSLTrustStorePwd 는 절대 URL 에 넣지 마세요. JDBC URL 은 로그·스레드 덤프·에러 스택트레이스에 너무도 쉽게 찍힙니다. 비밀번호가 담긴 URL 이 로그 파일에 남는 순간, 로그에 접근 가능한 모든 사람이 그 비밀번호를 볼 수 있게 됩니다. java.util.Properties 로 반드시 분리하세요.

Properties props = new Properties();
props.setProperty("UID", System.getenv("IMPALA_LDAP_UID"));
props.setProperty("PWD", System.getenv("IMPALA_LDAP_PWD"));
props.setProperty("SSLTrustStorePwd", System.getenv("IMPALA_TRUSTSTORE_PWD"));

Cloudera 드라이버는 URL 파라미터와 Properties 를 동일하게 인식합니다.

4. 순수 JDBC 로 연결

이제 모든 준비가 끝났습니다. Spring 같은 프레임워크 없이, 딱 필요한 코드만으로 연결을 확인하는 최소 예제를 보겠습니다. main 메서드에 넣고 바로 실행할 수 있어요.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
 
public class ImpalaJdbcSmokeTest {
 
  private static final String DRIVER_CLASS =
      "com.cloudera.impala.jdbc.Driver";
 
  // 비밀 정보는 포함하지 않는다.
  private static final String JDBC_URL =
      "jdbc:impala://impalad-lb.corp.example.com:21050"
          + ";AuthMech=3"
          + ";SSL=1"
          + ";SSLTrustStore=/app/truststore.jks";
 
  public static void main(String[] args) throws Exception {
    Class.forName(DRIVER_CLASS);
 
    Properties props = new Properties();
    props.setProperty("UID", requireEnv("IMPALA_LDAP_UID"));
    props.setProperty("PWD", requireEnv("IMPALA_LDAP_PWD"));
    props.setProperty("SSLTrustStorePwd", requireEnv("IMPALA_TRUSTSTORE_PWD"));
 
    try (Connection conn = DriverManager.getConnection(JDBC_URL, props);
         PreparedStatement ps = conn.prepareStatement("SELECT 1 AS ok");
         ResultSet rs = ps.executeQuery()) {
      if (rs.next()) {
        System.out.println("connected, result = " + rs.getInt("ok"));
      }
    }
  }
 
  private static String requireEnv(String name) {
    String v = System.getenv(name);
    if (v == null || v.isEmpty()) {
      throw new IllegalStateException("환경변수 " + name + " 가 비어있습니다.");
    }
    return v;
  }
}

실행:

export IMPALA_LDAP_UID='alice'
export IMPALA_LDAP_PWD='...'
export IMPALA_TRUSTSTORE_PWD='CHANGE_ME_STRONG_PASSPHRASE'
 
java -cp 'ImpalaJDBC42.jar:libs/*:.' ImpalaJdbcSmokeTest

connected, result = 1 이 출력되면 TLS + LDAP 경로가 전부 통과한 것입니다. 이 한 줄이 나오는 순간이 가장 뿌듯한 순간이죠.

디버그가 필요할 때

연결이 실패했을 때 막막하다면, JVM 에 SSL handshake 로그를 켜보세요. 원인이 거의 항상 눈에 보입니다.

java -Djavax.net.debug=ssl:handshake \
     -cp 'ImpalaJDBC42.jar:libs/*:.' \
     ImpalaJdbcSmokeTest

ServerHello, Certificate, ServerHelloDone 단계의 출력을 보면 서버가 보낸 체인과 TrustStore 가 연결되는지 확인할 수 있습니다. 운영 배포 후에는 로그량 때문에 반드시 끄세요.

5. 자주 만나는 에러와 해결

TLS + LDAP 연결 과정에서 만나는 에러는 패턴이 정해져 있습니다. 어느 층에서 실패했는지만 파악하면 대부분 10분 안에 해결됩니다.

PKIX path building failed

원인: Java 가 서버 인증서를 신뢰 체인까지 연결하지 못한 것입니다. TrustStore 에 root CA 가 없거나 잘못된 파일을 가리키는 경우가 대부분입니다.

  • keytool -list 로 alias 가 실제로 들어있는지 확인
  • JDBC URL 의 SSLTrustStore 경로가 실행 시점 기준으로 맞는지 확인
  • JVM 옵션(-Djavax.net.ssl.trustStore=...) 과 URL 파라미터가 둘 다 있으면 URL 이 우선

Unrecognized SSL message, plaintext connection?

원인: 클라이언트는 TLS 로 말하는데 서버가 평문으로 응답. 포트 번호가 틀렸거나, TLS 가 아닌 포트에 SSL=1 을 붙인 경우입니다.

  • TLS 가 켜진 Impala daemon 포트를 관리자에게 재확인
  • HTTP transport 환경이라면 TransportMode=http;HttpPath=... 가 추가로 필요한지 확인

No subject alternative names matching IP address

원인: 서버 인증서의 SAN 에 접속 hostname 이 빠져 있습니다. 내부 LB FQDN 이 인증서에 없는 경우가 대부분입니다.

  • 관리자에게 SAN 에 LB FQDN 을 추가해 재발급 요청 (정공법)
  • AllowHostNameCNMismatch=1 로 우회는 가능하지만 MITM 방어를 포기하는 설정이므로 운영 금지

Invalid operation: LDAP authentication failed

원인: TLS 는 통과했고 UID/PWD 가 서버에 도달했지만 LDAP 바인드가 실패했습니다.

  • UID 형식 확인. sAMAccountName(alice) / DOMAIN\alice / DN(uid=alice,...) 중 어느 형식인지 관리자에게 재확인
  • 비밀번호에 세미콜론·따옴표·공백이 있으면 반드시 Properties 방식으로 분리 (URL 에 넣지 말 것)
  • 계정 잠금 상태인지 AD 관리자에게 확인

Could not open client transport

원인: TCP/SASL 수준에서 실패. 네트워크 이슈인 경우가 많습니다.

  • telnet impalad-lb.corp.example.com 21050 로 TCP 자체가 열리는지 확인
  • 사내 프록시/방화벽에서 해당 포트 허용 여부 확인
  • 클러스터가 실제로 Kerberos 를 강제하는데 AuthMech=3 으로 붙고 있는 상황일 수도 있음. 관리자에게 실제 요구 인증 방식 재확인

6. 운영 체크리스트

개발 PC 에서는 잘 됐는데 운영 배포 며칠 뒤 터지는 경우가 의외로 많습니다. 아래 리스트를 한 번씩 체크하면 그런 시나리오를 대부분 예방할 수 있습니다.

  • TrustStore 파일이 배포 파일(JAR/WAR/Docker 이미지)에 포함되어 함께 배포되는가
  • storepass 가 환경변수 또는 Secret Store 로 주입되는가
  • JDBC URL 이 로그에 찍혀도 비밀 정보가 포함되지 않도록 Properties 로 분리되었는가
  • 인증서 만료일 모니터링이 있는가 (openssl x509 -in ca.pem -noout -enddate)
  • Cloudera Impala JDBC Connector 버전이 고정되어 있는가
  • CI 에서 실제 Impala 엔드포인트로 SELECT 1 smoke test 가 돌고 있는가
  • 연결 실패 시 실패 카운트 기반 알람이 있는가 (일시적 네트워크 지터와 구분)

여기까지 따라오셨다면 로컬에서 Cloudera Impala 에 TLS + LDAP 로 붙고, 문제가 생겼을 때 어느 층에서 실패했는지 진단하는 도구도 갖춘 것입니다.

마치며 — 핵심 요약

  • PKIX path building failed 의 원인은 대부분 TrustStore 에 root CA 가 없거나 경로가 틀린 것입니다.
  • JDK cacerts 대신 애플리케이션 전용 TrustStore(JKS) 를 만들어 배포하세요.
  • Cloudera JDBC URL 에서 SSL=1 은 반드시 대문자여야 하며, SSLTrustStore 에 절대경로를 지정합니다.
  • UID, PWD, SSLTrustStorePwd 는 절대 URL 에 넣지 말고 Properties 로 분리하세요.
  • 연결이 안 될 때는 -Djavax.net.debug=ssl:handshake 로 handshake 로그를 켜면 원인이 빠르게 잡힙니다.
  • 운영 배포 전 체크리스트를 꼭 확인하세요 — 로컬에서 됐다고 운영에서 된다는 보장이 없습니다.

TLS 연결은 한 번 제대로 셋업해두면 이후에는 신경 쓸 일이 거의 없습니다. 처음 한 번만 꼼꼼히 짚고 넘어가세요.

— Data Dynamics 엔지니어링 팀