Java通过JDBC连接Kerberos认证Hive时报GSS initiate failed错误
问题场景
在Eclipse中通过Java JDBC连接部署在Linux服务器上、运行状态正常的自建Hive服务,已导入全部所需依赖Jar包,使用的测试代码如下:
BasicConfigurator.configure(); try { Class.forName("org.apache.hive.jdbc.HiveDriver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } final String keyPath = "Here is the keypath"; final String user = "myuser/FQDN@REALM.COM"; Configuration conf = new Configuration(); conf.set("hadoop.security.authentication", "kerberos"); System.setProperty("java.security.krb5.conf", "PATH:/krb5.conf"); System.setProperty("sun.security.krb5.debug", "true"); System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); UserGroupInformation ugi; UserGroupInformation.setConfiguration(conf); ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(user, keyPath); UserGroupInformation.setLoginUser(ugi); System.out.println("TRYING TO CONNECT"); Connection cnct = null; cnct = DriverManager.getConnection( "jdbc:hive2://FQDN:10000/default;principal=ADDED PRINCIPAL HERE", "user", "pass"); System.out.println("Connected"); cnct.close();
报错信息
运行代码时抛出如下异常,核心错误为GSS initiate failed:
Exception in thread "main" java.sql.SQLException: Could not open connection to jdbc:hive2://FQDN:10000/default;principal=PRINCIPAL HERE: Peer indicated failure: GSS initiate failed at org.apache.hive.jdbc.HiveConnection.openTransport(HiveConnection.java:146) at org.apache.hive.jdbc.HiveConnection.<init>(HiveConnection.java:123) at org.apache.hive.jdbc.HiveDriver.connect(HiveDriver.java:105) at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:677) at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:228) at TestHiveJdbc.main(TestHiveJdbc.java:56) Caused by: org.apache.thrift.transport.TTransportException: Peer indicated failure: GSS initiate failed at org.apache.thrift.transport.TSaslTransport.receiveSaslMessage(TSaslTransport.java:190) at org.apache.thrift.transport.TSaslTransport.open(TSaslTransport.java:258) at org.apache.thrift.transport.TSaslClientTransport.open(TSaslClientTransport.java:37) at org.apache.hadoop.hive.thrift.client.TUGIAssumingTransport$1.run(TUGIAssumingTransport.java:52) at org.apache.hadoop.hive.thrift.client.TUGIAssumingTransport$1.run(TUGIAssumingTransport.java:49) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/javax.security.auth.Subject.doAs(Subject.java:423) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657) at org.apache.hadoop.hive.thrift.client.TUGIAssumingTransport.open(TUGIAssumingTransport.java:49) at org.apache.hive.jdbc.HiveConnection.openTransport(HiveConnection.java:144) ... 5 more
故障原因与对应解决方案
该错误为Kerberos认证阶段SASL协商失败导致,按优先级排查以下问题:
- krb5.conf配置错误:代码中
java.security.krb5.conf属性值带了无效的PATH:前缀,必须替换为本地krb5.conf文件的绝对路径,例如Windows环境为C:/work/conf/krb5.conf,Linux环境为/etc/krb5.conf。同时确认本地krb5.conf内容和服务端KDC、Hive节点配置完全一致,包含正确的REALM定义、KDC地址、域名映射规则,REALM名称大小写严格敏感。 - 连接逻辑未在Kerberos上下文特权块中执行:直接通过
setLoginUser设置全局登录用户在部分JDK版本下会出现认证上下文丢失,获取UGI实例后,必须将JDBC连接、SQL执行等所有和Hive交互的逻辑包裹在ugi.doAs()特权块中运行。 - JDBC连接参数错误:
- 连接串中的Hive地址必须使用HiveServer2节点的FQDN(全限定域名),不能使用IP或短主机名,否则会和服务端principal的主机名校验不通过;
- 连接串中的principal参数必须和HiveServer2服务配置的Kerberos主体完全一致,标准格式为
hive/_HOST@YOUR_REALM.COM,其中_HOST会自动替换为连接的HiveServer2 FQDN,不能填写自定义值; - Kerberos认证模式下不需要在
DriverManager.getConnection中传入用户名、密码参数,冗余的账号密码会干扰SASL认证流程,直接删除这两个入参即可。
- keytab文件有效性问题:确认keyPath指向的keytab文件本地可读,先在命令行执行
kinit -kt 你的keytab路径 你的principal命令验证keytab有效性,如果命令行认证都失败,需要重新向KDC管理员申请对应principal的keytab。 - 主机名解析失败:本地开发环境必须能正常解析KDC节点、HiveServer2节点的FQDN,如果内网DNS没有配置对应解析,直接修改本地hosts文件添加IP和FQDN的静态映射即可。
- 时间不同步:Kerberos默认允许的客户端、服务端时间差为5分钟,确认本地开发机、KDC节点、HiveServer2节点的系统时间差在阈值范围内,超出则同步时间即可。
- 依赖版本冲突:确认导入的Hive JDBC、Hadoop Common、Thrift依赖的大版本和服务端Hive、Hadoop版本完全匹配,跨大版本的依赖会出现SASL协议不兼容的问题,直接替换为和服务端同版本的依赖包即可。
修正后可运行的参考代码
import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.conf.Configuration; import java.sql.Connection; import java.sql.DriverManager; import org.apache.log4j.BasicConfigurator; import java.security.PrivilegedExceptionAction; public class TestHiveJdbc { public static void main(String[] args) throws Exception { BasicConfigurator.configure(); Class.forName("org.apache.hive.jdbc.HiveDriver"); // 替换为本地keytab的实际绝对路径 final String keyPath = "C:/work/conf/myuser.keytab"; // 替换为自己的Kerberos主体,注意大小写 final String user = "myuser/hiveserver01.xxx.com@XXX.COM"; // 替换为本地krb5.conf的实际绝对路径 final String krb5Path = "C:/work/conf/krb5.conf"; Configuration conf = new Configuration(); conf.set("hadoop.security.authentication", "kerberos"); System.setProperty("java.security.krb5.conf", krb5Path); System.setProperty("sun.security.krb5.debug", "true"); System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); UserGroupInformation.setConfiguration(conf); UserGroupInformation ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(user, keyPath); // 所有Hive操作放在doAs块中执行 Connection cnct = ugi.doAs(new PrivilegedExceptionAction<Connection>() { @Override public Connection run() throws Exception { System.out.println("TRYING TO CONNECT"); // 替换为实际的HiveServer2 FQDN、端口、principal,去掉用户名密码参数 Connection conn = DriverManager.getConnection( "jdbc:hive2://hiveserver01.xxx.com:10000/default;principal=hive/_HOST@XXX.COM"); System.out.println("Connected"); return conn; } }); cnct.close(); } }
内容的提问来源于stack exchange,提问作者Nikhil Sharma
相关产品推荐
相关产品推荐

