很高兴大家有兴趣看到这里,今天笔者来说说,怎么访问已经 Enable 了 Kerberos 的 Hadoop 服务,以 HDFS 为例子。访问其他服务时,大家可以有些启发,而不会盲目无从下手。
再来说说, Kerberos 的整个简单认证过程。
Kerberos 的认证过程如下图所示。我们可以简单的理解为,User 或者 Service 会用 Principal 到 AS 去认证(KRB_AS_REQ),AS 会返回一个用 Principal Key 加密的 TGT(KRB_AS_REP),这时候只有 AS 和这个 Principal 的使用者可以识别该 TGT。在拿到加密的 TGT 之后,User 或者 Service 会使用 Principal 的 Key 来解密 TGT,并使用解密后的 TGT 去 TGS 获取 Service Ticket(KRB_TGS_REQ, KRB_TGS_REP)。在 Kerberos 认证的集群中,只有拿着这个 Service Ticket 才可以访问真正的 Server 从而实现自己的业务逻辑(KRB_AP_REQ, KRB_AP_REP)。一般我们将 TGT 的存放文件,称为 Kerberos Confidential 文件,默认的存放目录为/tmp,文件名则由 krb5cc 和用户的 id 组成,例如“/tmp/krb5cc_0”为root的 confidential 文件。
接下来分为 CLI 以 principal + password 的方式访问 HDFS,以及 Java SDK 以 key tab 的方式访问 HDFS。前者适合 user 进行简单访问, 后者适合 service 进行常驻式的服务访问。 Kerberos 部署请看上一篇:实现基于Cloudera的企业级安全大数据平台-Kerberos的整合。 HDFS 的部署很简单,在这里不复述,请看 Cloudera 官方文档, 并 Enable HDFS HA。
CLI 访问 HDFS
Active NameNode: 192.168.1.1
Kerberos KDC Server: 192.168.1.1
DFSClient: 192.168.1.18
Cloudera Version: 5.8.2
在 Kerberos KDC Server 的操作
以 kadmin 的身份进行认证,创建测试 principal:
kinit cdh-master/[email protected] # 该管理员 principal 是上一篇定义的
kadmin
> addprinc hdfs/[email protected] # 此处初始化 principal 密码
在 DFSClient端的操作
在 DFSClient 192.168.1.18 部署 Kerberos 客户端:
sudo yum install krb5-devel krb5-workstation -y
JDK 1.8.0 安装,这块网上有很多教程,不复述。
将 Kerberos 服务端的配置文件拷贝至 DFSClient:
sudo scp 192.168.1.1:/etc/krb5.conf /etc/
为了支持java的aes256-cts算法,将JCE包解压到${JAVA_HOME}/jre/lib/security
目录下:
wget http://download.oracle.com/otn-pub/java/jce/8/jce_policy-8.zip
unzip jce_policy-8.zip
sudo cp UnlimitedJCEPolicyJDK8/*.jar $JAVA_HOME/jdk1.8.0/jre/lib/security
安装 HDFS 客户端,并进行 HDFS 配置:
tar -zxvf /home/admin/hadoop-2.6.0-cdh5.8.2.tar.gz -C /home/admin/
# 假设 192.168.1.3 是 Active NameNode
scp 192.168.1.3:/etc/hadoop/conf/* /home/admin/hadoop-2.6.0-cdh5.8.2/etc/hadoop/
进行 Kerberos 认证,并执行测试命令:
kinit hdfs/[email protected]
/home/admin/hadoop-2.6.0-cdh5.8.2/bin/hdfs dfs -ls /
Java SDK 访问 HDFS
Active NameNode: 192.168.1.1
Kerberos KDC Server: 192.168.1.1
DFSClient: 192.168.1.18
Cloudera Version: 5.8.2
在 Kerberos KDC Server 的操作
以 kadmin 的身份进行认证,创建测试 principal:
kinit cdh-master/[email protected] # 该管理员 principal 是上一篇定义的
kadmin
> addprinc -randkey hdfs/[email protected] # 使用随机密码新建 principal
> xst -k /tmp/hdfs_test.keytab hdfs/[email protected] # 导出 keytab 文件
kinit -kt /tmp/hdfs_test.keytab hdfs/[email protected] # 验证 keytab 文件是否可用
kdestroy # 销毁本地 ticket 缓存
在 DFSClient端的操作
在 DFSClient 192.168.1.18 上部署 Kerberos 客户端:
sudo yum install krb5-devel krb5-workstation -y
JDK 1.8.0 安装,这块网上有很多教程,不复述。
将 Kerberos 服务端的配置文件拷贝至 DFSClient:
sudo scp 192.168.1.1:/etc/krb5.conf /etc/
为了支持java的aes256-cts算法,将JCE包解压到${JAVA_HOME}/jre/lib/security
目录下:
wget http://download.oracle.com/otn-pub/java/jce/8/jce_policy-8.zip
unzip jce_policy-8.zip
sudo cp UnlimitedJCEPolicyJDK8/*.jar $JAVA_HOME/jdk1.8.0/jre/lib/security
拷贝 keytab 文件至本地,假设存放在 /tmp/keytab/
下。
以下为测试用的 Java 代码TeastKerberosHDFS.java
,假设 192.168.1.3 为 Active NameNode,当然也可以走 NameService 进行访问:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
public class TestKerberosHDFS {
public static final String KEYTAB_FILE_KEY = "hdfs.keytab.file";
public static final String USER_NAME_KEY = "hdfs.kerberos.principal";
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
conf.set(KEYTAB_FILE_KEY, "/tmp/keytab/hdfs_test.keytab");
conf.set(USER_NAME_KEY, "hdfs/[email protected]");
if (UserGroupInformation.isSecurityEnabled()) {
SecurityUtil.login(conf, KEYTAB_FILE_KEY, USER_NAME_KEY);
}
System.out.println(loadHdfsFile("/user/admin/hosts_hed_new/part-m-00000", conf));
}
public static List loadHdfsFile(String filePath, Configuration conf) {
List resultList = new ArrayList();
FileSystem fileSystem = null;
try {
URI uri = new URI("hdfs://192.168.1.3:8020");
fileSystem = FileSystem.get(uri, conf);
FSDataInputStream fs = fileSystem.open(new Path(filePath));
BufferedReader bis = new BufferedReader(new InputStreamReader(fs, "UTF-8"));
String line;
while ((line = bis.readLine()) != null) {
resultList.add(line);
}
fileSystem.close();
} catch (Exception e) {
e.printStackTrace();
}
return resultList;
}
}
进行编译,生成 jar 包,命名为 TestKerberosHDFS.jar。
拷贝HDFS集群的配置文件到 192.168.1.18 这台 DFSClient 上:
scp 192.168.1.3:/etc/hadoop/conf/* /etc/hadoop/conf/
使用 Hadoop 的 RunJar 命令启动 TestKerberosHDFS.jar 工程 :
java -classpath \
/etc/hadoop/conf:/home/admin/TestKerberosHDFS/lib/* \ #注明:/etc/hadoop/conf 为HDFS配置文件所在目录;/home/admin/TestKerberosHDFS/lib/* 为RunJar命令所需的jar包;
org.apache.hadoop.util.RunJar \ #注明:RunJar命令的全类名
/home/admin/TeastKerberosHDFS.jar \ #注明:测试访问安全HDFS集群的工程jar
com.test.TestKerberosHDFS #注明:测试访问安全HDFS集群的工程jar的主类名
#注明:/home/admin/TestKerberosHDFS/lib/目录下包括的jar包:
commons-cli-1.2.jar
commons-codec-1.4.jar
commons-collections-3.2.2.jar
commons-configuration-1.6.jar
commons-lang-2.6.jar
commons-logging-1.1.3.jar
guava-11.0.2.jar
hadoop-auth-2.6.0-cdh5.8.2.jar
hadoop-common-2.6.0-cdh5.8.2.jar
hadoop-hdfs-2.6.0-cdh5.8.2.jar
htrace-core-3.2.0-incubating.jar
htrace-core4-4.0.1-incubating.jar
log4j-1.2.17.jar
protobuf-java-2.5.0.jar
servlet-api-3.0.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar