背景
cdh6 集群为阿里服务器,三台机器搭建而成,并且开启了 kerberos,现在想尝试一下用 java api 读取 hdfs 数据。
代码如下:
public class ReadHdfsOnKerberos {
public static void main(String[] args) throws IOException {
String krbConfigPath = "D:\\Code\\kk-architecture-bigdata-practice\\Hadoop-Practice\\src\\main\\resources\\";
System.setProperty("java.security.krb5.conf", krbConfigPath + "krb5.conf");
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "Kerberos");
conf.set("java.security.krb5.conf", krbConfigPath + "krb5.conf");
UserGroupInformation.setConfiguration(conf);
System.out.println("开始登录 kerberos");
UserGroupInformation.loginUserFromKeytab("hdfs/admin@KKARCH.COM", krbConfigPath + "root.keytab");
System.out.println("登录结束");
String file = "hdfs://ip1:8020";
FileSystem fs = FileSystem.get(URI.create(file), conf);
System.out.println(fs.exists(new Path("/")));
}
}
报错如下:
[2021-11-28 00:30:43 上午]:DEBUG org.apache.hadoop.security.UserGroupInformation$HadoopLoginModule.login(UserGroupInformation.java:222)hadoop login
Exception in thread "main" java.io.IOException: Login failure for hdfs/admin@KKARCH.COM from keytab D:\Code\kk-architecture-bigdata-practice\Hadoop-Practice\src\main\resources\root.keytab: javax.security.auth.login.LoginException: Receive timed out
at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(UserGroupInformation.java:983)
at com.kkarch.hadoop.rpc.kerberos.ReadHdfsOnKerberos.main(ReadHdfsOnKerberos.java:29)
Caused by: javax.security.auth.login.LoginException: Receive timed out
at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:808)
at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
at javax.security.auth.login.LoginContext.login(LoginContext.java:587)
at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(UserGroupInformation.java:974)
... 1 more
Caused by: java.net.SocketTimeoutException: Receive timed out
at java.net.DualStackPlainDatagramSocketImpl.socketReceiveOrPeekData(Native Method)
at java.net.DualStackPlainDatagramSocketImpl.receive0(DualStackPlainDatagramSocketImpl.java:124)
at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:143)
at java.net.DatagramSocket.receive(DatagramSocket.java:812)
at sun.security.krb5.internal.UDPClient.receive(NetClient.java:206)
at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:411)
at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:364)
at java.security.AccessController.doPrivileged(Native Method)
at sun.security.krb5.KdcComm.send(KdcComm.java:348)
at sun.security.krb5.KdcComm.sendIfPossible(KdcComm.java:253)
at sun.security.krb5.KdcComm.send(KdcComm.java:229)
at sun.security.krb5.KdcComm.send(KdcComm.java:200)
at sun.security.krb5.KrbAsReqBuilder.send(KrbAsReqBuilder.java:316)
at sun.security.krb5.KrbAsReqBuilder.action(KrbAsReqBuilder.java:361)
at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:776)
... 14 more
Process finished with exit code 1
真是百思不得其解,初步怀疑是阿里云的端口没开。
kerberos 用了两个端口,一个是 88 ,kdc 在用;另一个是 749 , kadmin 在用,但是都开了:
打开 cmd ,telnet 88 和 749 端口,都是可以通的,但是报错始终提示,接收数据异常。
我一想,是不是出的方向我没配啊。但是它提示我,出方向始终是放行的
于是继续去服务器上看日志:
/var/log/krb5kdc.log
/var/log/kadmind.log
都没有新增的日志。
一筹莫展…陷入了僵局…
继续看本地的日志,突然发现,咦,这个 UDPClient,好像是在接收 udp 的请求,说明发出去的也是一个 udp 请求!
然而,阿里云的安全配置是区分 tcp 和 udp 的,我配的是一个 tcp 的策略。
于是赶紧改成了 udp
然后就特么可以了,搞了好久!!!
最后把 749 端口去掉,发现也是可以的,说明客户端认证只请求了 kdc 就可以完成认证了。