Applying TLS + LDAP Authentication to Cloudera Impala JDBC
Escape PKIX errors for good. Extract the certificate chain, create a dedicated TrustStore, and build the Impala JDBC URL — all with plain JDBC.
It's a common scenario in the field: Cloudera Impala connects fine over plaintext in the dev environment, but in production it fails with PKIX path building failed. This post walks through the entire process of applying TLS + LDAP authentication to connect to Impala using only the Cloudera Impala JDBC Connector (Simba-based commercial driver) and plain JDBC DriverManager — no frameworks involved.
TL;DR
- Request the root CA certificate PEM file (
ca.pem) from your cluster administrator. - Use
keytoolto create a new application-specific TrustStore (JKS) and import the CA. - Add
SSL=1;SSLTrustStore=...;AuthMech=3to the JDBC URL, and separateUID/PWD/SSLTrustStorePwdintoProperties. - Call
Class.forName("com.cloudera.impala.jdbc.Driver")thenDriverManager.getConnection(). - Run
SELECT 1— if it succeeds, you're done.
1. Prerequisites
Make sure you have everything below before starting. If anything is missing, request it from your cluster administrator.
| # | Item | Example |
|---|---|---|
| 1 | Cloudera Impala JDBC Connector JAR | ImpalaJDBC42.jar + any dependency JARs provided with it |
| 2 | TLS-enabled Impala daemon endpoint | impalad-lb.corp.example.com:21050 |
| 3 | Cluster's root CA certificate (PEM) | ca.pem |
| 4 | LDAP credentials | UID / PWD. Confirm the format with your administrator |
| 5 | JDK 8 or later | java -version |
You only need the root CA — the full chain is not necessary.
2. Import the TLS Certificate into a TrustStore
2.1 Why use an application-specific TrustStore
You could add it directly to the JDK's cacerts, but this is not recommended for the following reasons:
- It can affect all other applications using the same JDK
- Upgrading the JDK replaces
cacerts, causing your import to disappear - You'd need to rebuild the container image every time
The alternative is to create a dedicated TrustStore file (JKS) that ships with your application. It's unaffected by JDK upgrades, provides a clear security boundary, and for Docker images it's just one line: COPY truststore.jks /app/.
2.2 Obtaining the certificate
Method 1 — Get the PEM file from the administrator (recommended)
First, verify that the received file is correct:
openssl x509 -in ca.pem -noout -subject -issuer -datesIf Subject: and Issuer: are identical, it's the root CA.
Method 2 — Extract directly from the server using 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.pemTo find the root CA in the chain, compare the subject/issuer of each certificate:
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
doneThe file where Subject: and Issuer: are identical is the root CA.
2.3 Create the TrustStore with keytool
This is the key step of this post.
keytool -importcert -noprompt \
-file ca.pem \
-alias cloudera-root-ca \
-keystore ./truststore.jks \
-storepass 'CHANGE_ME_STRONG_PASSPHRASE' \
-storetype JKSHere's what each option does:
| Option | Description |
|---|---|
-importcert | Add an X.509 certificate to the keystore |
-noprompt | Skip prompts. Required for scripting |
-file | The certificate file to import |
-alias | Internal identifier within the keystore. Re-importing with the same alias overwrites |
-keystore | TrustStore file path. Creates a new file if it doesn't exist |
-storepass | Keystore password. Recommended to inject via environment variables |
-storetype JKS | Explicitly specify the format. JDK 9+ defaults to PKCS12, so it's safer to be explicit |
2.4 Verify the TrustStore
Confirm that the CA was properly imported into the TrustStore:
keytool -list -v \
-keystore ./truststore.jks \
-storepass 'CHANGE_ME_STRONG_PASSPHRASE' \
-alias cloudera-root-caPoints to verify in the output:
Owner:matches the DN of the received root CAValid from ... until:expiration date- Cross-check the
SHA-256fingerprint with the value provided by the administrator (the last line of defense against MITM)
2.5 Common pitfalls
Review these before deployment:
- Did you import only the root CA?
- Does the
-aliasconflict with an existing one? - Is the TrustStore path accessible at runtime? Watch out for relative paths
- Do you have certificate expiration monitoring in place?
- Is the
-storepasshardcoded in source code?
3. Composing the Impala JDBC URL
3.1 URL template
jdbc:impala://impalad-lb.corp.example.com:21050;AuthMech=3;SSL=1;SSLTrustStore=/app/truststore.jks3.2 Parameter descriptions
| Parameter | Value | Description |
|---|---|---|
AuthMech | 3 | User Name And Password. This means LDAP bind authentication |
SSL | 1 | Enable TLS. Must be uppercase SSL=1. Lowercase ssl=true is Apache Hive JDBC syntax and is not recognized by the Cloudera driver |
SSLTrustStore | /app/truststore.jks | Absolute path to the TrustStore created earlier |
3.3 Never put sensitive information in the URL
Do not put UID/PWD and SSLTrustStorePwd in the URL. JDBC URLs commonly appear in logs, thread dumps, and error stack traces. Separate them using 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"));The Cloudera driver treats URL parameters and Properties identically.
4. Connecting with plain JDBC
Here's a minimal reproducible example without any framework. You can put it in a main method and run it directly.
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";
// No secrets included.
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("Environment variable " + name + " is empty.");
}
return v;
}
}Running:
export IMPALA_LDAP_UID='alice'
export IMPALA_LDAP_PWD='...'
export IMPALA_TRUSTSTORE_PWD='CHANGE_ME_STRONG_PASSPHRASE'
java -cp 'ImpalaJDBC42.jar:libs/*:.' ImpalaJdbcSmokeTestIf connected, result = 1 appears, the entire TLS + LDAP path is working.
Debugging
If the connection fails, enabling SSL handshake logging in the JVM almost always reveals the cause:
java -Djavax.net.debug=ssl:handshake \
-cp 'ImpalaJDBC42.jar:libs/*:.' \
ImpalaJdbcSmokeTestCheck the output at the ServerHello, Certificate, and ServerHelloDone stages to see if the chain sent by the server links to your TrustStore. Be sure to disable this in production — the log volume is significant.
5. Common Errors and Solutions
PKIX path building failed
Cause: Java cannot link the server certificate to a trust chain. Most commonly, the root CA is missing from the TrustStore or the file path is wrong.
- Verify the alias actually exists with
keytool -list - Check that the
SSLTrustStorepath in the JDBC URL is correct relative to the execution context - If both JVM options (
-Djavax.net.ssl.trustStore=...) and URL parameters exist, the URL takes precedence
Unrecognized SSL message, plaintext connection?
Cause: The client is speaking TLS but the server is responding in plaintext. The port number is wrong, or you're using SSL=1 on a non-TLS port.
- Re-confirm the TLS-enabled Impala daemon port with the administrator
- If using HTTP transport, check whether
TransportMode=http;HttpPath=...is additionally required
No subject alternative names matching IP address
Cause: The server certificate's SAN does not include the connection hostname. This usually happens when the internal LB FQDN is missing from the certificate.
- Ask the administrator to reissue the certificate with the LB FQDN added to the SAN (the proper approach)
AllowHostNameCNMismatch=1can work around this, but it disables MITM protection — never use in production
Invalid operation: LDAP authentication failed
Cause: TLS passed and the UID/PWD reached the server, but LDAP bind failed.
- Verify the UID format. Confirm with the administrator whether it's sAMAccountName (
alice),DOMAIN\alice, or DN (uid=alice,...) - If the password contains semicolons, quotes, or spaces, you must use the
Propertiesapproach (do not put it in the URL) - Check with the AD administrator whether the account is locked
Could not open client transport
Cause: Failure at the TCP/SASL level. Often a network issue.
- Test TCP connectivity with
telnet impalad-lb.corp.example.com 21050 - Check if the port is allowed through corporate proxy/firewall
- The cluster may actually be enforcing Kerberos while you're connecting with
AuthMech=3. Re-confirm the actual required authentication method with the administrator
6. Production Checklist
This list helps prevent scenarios where things work on a dev PC but break days after production deployment.
- Is the TrustStore file included in the deployment artifact (JAR/WAR/Docker image) and deployed together?
- Is the
storepassinjected via environment variable or secret store? - Is the JDBC URL free of secrets even when it appears in logs, using
Propertiesfor sensitive values? - Is there certificate expiration monitoring in place? (
openssl x509 -in ca.pem -noout -enddate) - Is the Cloudera Impala JDBC Connector version pinned?
- Does CI run a
SELECT 1smoke test against a real Impala endpoint? - Is there a failure-count-based alarm for connection failures? (to distinguish from transient network jitter)
If you've followed along this far, you can now connect to Cloudera Impala with TLS + LDAP locally, and you have the diagnostic tools to identify which layer failed when something goes wrong.
— Data Dynamics Engineering Team