impalad 앞단에 로드밸런서를 두고 Hue · NiFi · beeline · impala-shell 이 모두 LB 주소로 붙게 만든다. Kerberos 와 TLS 가 모두 켜진 클러스터라 클라이언트마다 SPN 과 truststore 를 어떻게 줄지가 실제 작업의 대부분이다.
LB 는 요청을 뒤쪽 impalad 노드 중 하나로 분배한다. 그런데 각 노드의 keytab 에는 자기 호스트명 SPN(impala/node01@REALM) 만 있고 LB 이름으로 된 SPN 은 없다. 그래서 KrbHostFQDN 에 LB FQDN 을 고정하면 클라이언트는 impala/impala-lb@REALM 티켓을 요청하는데 실제로 붙은 노드는 그 키가 없어 인증이 깨진다.
_HOST 는 드라이버가 실제 TCP 로 연결된 서버의 FQDN 으로 런타임에 치환하는 플레이스홀더다. node01 에 붙으면 impala/node01@REALM, node02 에 붙으면 impala/node02@REALM 을 만들어 쓰므로 LB 가 어디로 보내든 노드가 가진 keytab 과 항상 일치한다.
LB FQDN 을 그대로 쓰고 싶다면 KDC 에 LB SPN 을 만들고 모든 impalad 노드 keytab 에 추가해야 한다. 노드를 늘릴 때마다 keytab 을 갱신해야 하므로 관리 부담이 크다.
kadmin: addprinc -randkey impala/impala-lb.example.internal@REALM
kadmin: ktadd -k /etc/security/keytabs/impala.keytab impala/impala-lb.example.internal@REALM
둘 다 "호스트명 불일치" 를 다루기 때문에 헷갈리기 쉬운데, 보는 호스트명이 다르다.
| SSL validation | Kerberos _HOST |
|
|---|---|---|
| 검증 대상 | 서버가 제시한 인증서 | 서비스 SPN 일치 |
| 비교하는 값 | 인증서 CN · SAN ↔ 접속한 호스트명 | SPN 의 호스트 부분 ↔ 노드가 가진 키 |
| 관련 파라미터 | SSL=1, AllowSelfSignedCerts=1, CAIssuedCertNamesMismatch=1 |
AuthMech=1, KrbHostFQDN=_HOST, KrbServiceName, KrbRealm |
| 끄면 | 인증서 검증 생략, truststore 불필요 | 끌 수 없다. 인증은 필수 |
인증서가 노드 호스트명으로 발급돼 있고 LB 주소로 붙으면 CN 불일치가 나므로, 검증을 끄거나 CAIssuedCertNamesMismatch=1 로 이 검사만 무시한다. 검증을 끄더라도 Kerberos 인증은 그대로 필요하고 _HOST 도 그대로 필요하다.
kinit -kt /etc/security/keytabs/analytics.keytab analytics@REALM
klist # Default principal 의 뒷부분이 KrbRealm 값이다
beeline -u "jdbc:impala://impala-lb.example.internal:21050/default;\
AuthMech=1;KrbRealm=REALM;KrbHostFQDN=_HOST;KrbServiceName=impala;\
SSL=1;SSLTrustStore=/opt/cloudera/security/impala_truststore.jks;SSLTrustStorePwd=${STOREPASS}"
No known driver to handle "jdbc:impala://..." 가 나오면 Impala JDBC 드라이버 jar 가 클래스패스에 없는 것이다. 서버에 있는지 먼저 찾는다.
find /opt/cloudera -name "*ImpalaJDBC*" -o -name "*impala*jdbc*" 2>/dev/null
Cloudera Manager 가 만든 cm_auto_global_truststore.jks 를 그대로 쓰거나 이름을 바꿔 써도 된다. 다만 이 파일은 CM agent 가 있는 노드에만 있으므로 NiFi 노드 전체에 같은 경로로 복사해야 한다. 암호는 /var/lib/cloudera-scm-agent/agent-cert/cm_auto_host_key_pw 에 있다.
find / -name "cm_auto_global_truststore.jks" 2>/dev/null
cat /var/lib/cloudera-scm-agent/agent-cert/cm_auto_host_key_pw
CM 자동 생성 truststore 를 쓰기 곤란하면 루트 CA pem 으로 새로 만드는 편이 깔끔하다.
keytool -import -alias cmrootca -noprompt \
-file /var/lib/cloudera-scm-agent/agent-cert/cm-auto-global_cacerts.pem \
-keystore /opt/cloudera/security/impala_truststore.jks -storepass ${STOREPASS}
keytool -list -keystore /opt/cloudera/security/impala_truststore.jks -storepass ${STOREPASS}
NiFi 의 ImpalaConnectionPool(DBCPConnectionPool) 에는 위 JDBC URL 을 그대로 넣고, KerberosKeytabUserService 로 티켓을 공급한다. Controller Service 가 Invalid 로 남으면 대개 StandardSSLContextService 의 truststore 경로 · 암호가 먼저 문제다.
Cloudera Manager → Hue → Configuration 에서 valve 를 검색해 hue_safety_valve.ini 에 넣는다.
[impala]
server_host=impala-lb.example.internal
server_port=21050
[[ssl]]
enabled=true
validate=false
저장 후 Hue 를 재시작하고 웹 UI 에서 쿼리를 한 번 돌려 확인한다.
커맨드라인으로는 이렇게 붙는다.
impala-shell -i impala-lb.example.internal:21050 --protocol=hs2 -d default -k --ssl
기본값으로 만들려면 alias 를 걸거나 ~/.impalarc 를 둔다. 섹션명은 [impala] 가 맞다.
[impala]
impalad=impala-lb.example.internal:21050
protocol=hs2
ssl=true
kerberos=true
kerberos_service_name=impala
default_db=default
.impalarc 는 impala-shell 을 실행하는 계정의 홈에 있어야 한다. root 로 만들고 다른 계정으로 실행하면 읽히지 않는다. 자동 로드가 의심되면 명시적으로 지정해 가른다.
whoami && echo $HOME
impala-shell --config_file=$HOME/.impalarc --verbose
impala-shell --config_file=$HOME/.impalarc -q "select 1;"
설정 파일의 키 이름은 커맨드라인 long-form 인자와 비슷하지만 반드시 같지는 않다는 점이 공식 문서에 명시돼 있다. 그래서 파일이 안 먹으면 impalad 한 줄만 남긴 최소 구성부터 시작해 옵션을 하나씩 늘려 어느 키에서 깨지는지 찾는 것이 빠르다. 커맨드라인 옵션은 설정 파일 값을 덮어쓴다.
이 사례에서는 커맨드라인 옵션은 정상 동작했지만 동일한 값을 담은 ~/.impalarc 는 끝까지 반영되지 않았다. 어느 키가 거부됐는지는 대화에 남아 있지 않다.