Blog
clouderaimpalajdbctlsldapkeytool

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

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

Data Dynamics2026年4月11日12 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 에 접속하는 전체 과정을 정리합니다.

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/ 한 줄이면 끝납니다.

2.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 만들기

이 글의 핵심 단계입니다.

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 은 로그·스레드 덤프·에러 스택트레이스에 흔히 찍힙니다. 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 로 연결

프레임워크 없이 최소로 재현 가능한 예제입니다. 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. 자주 만나는 에러와 해결

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 로 붙고, 문제가 생겼을 때 어느 층에서 실패했는지 진단하는 도구도 갖춘 것입니다.

— Data Dynamics 엔지니어링 팀