用受Kerberos保护的Hadoop集群启用gphdfs认证
通过使用外部表和gphdfs协议,Greenplum数据库能够读写Hadoop文件系统(HDFS)上的文件。为了更快的性能,Greenplum的Segment会并行地从HDFS读写文件。
当Hadoop集群受到Kerberos保护(“Kerberos化”)时,Greenplum数据库必须配置为允许Greenplum数据库的gpadmin角色(拥有HDFS中的外部表)通过Kerberos认证。这一主题提供配置Greenplum数据库与Kerberos化HDFS配合工作的步骤,包括验证配置和在配置中排查问题。
上级主题: 安全性配置指南
先决条件
确认下列组件正常工作并且在网络上可访问:
- Greenplum数据库集群
- Kerberos保护的Hadoop集群。支持的Hadoop版本请见Greenplum数据库发行注记。
- Kerberos密钥发行中心(KDC)服务器。
配置Greenplum集群
Greenplum集群中的主机必须安装有Java JRE、Hadoop客户端文件以及Kerberos客户端。
按下列步骤准备Greenplum集群。
在所有的Greenplum集群主机上安装Java 1.6或者之后的JRE。
要匹配Hadoop集群运行的JRE版本。用户可以在Hadoop节点上通过运行java —version来找到JRE版本。
(可选)确认Java加密扩展(JCE)存在。
JCE库的默认位置是JAVA_HOME/lib/security。如果安装了JDK,该目录是JAVA_HOME/jre/lib/security。文件local_policy.jar以及US_export_policy.jar应该出现在JCE目录中。
Greenplum集群和Kerberos服务器最好应该使用相同版本的JCE库。如果需要,用户可以从Kerberos服务器把JCE文件拷贝到Greenplum集群。
为gpadmin账户在.bashrc或.bash_profile文件中将JAVA_HOME环境变量设置为JRE的位置。例如:
export JAVA_HOME=/usr/java/default
引入.bashrc或.bash_profile文件将改动应用到用户的环境。例如:
$ source ~/.bashrc
在所有集群主机上安装Kerberos客户端工具。在安装它们之前,确保共享库匹配KDC服务器上的版本。
例如,下面的命令在Red Hat或者CentOS Linux上安装Kerberos客户端文件:
$ sudo yum install krb5-libs krb5-workstation
使用kinit命令确认Kerberos客户端被安装并且正确地配置。
在Greenplum集群中的所有主机上安装Hadoop客户端文件。其指令请参考所使用的Hadoop的文档。
为Hadoop设置Greenplum数据库的服务器配置参数。gp_hadoop_target_version参数指定Hadoop集群的版本。与所使用的Hadoop相对应的目标版本值请见Greenplum数据库发行注记。gp_hadoop_home参数指定Hadoop安装目录。
$ gpconfig -c gp_hadoop_target_version -v "hdp2"
$ gpconfig -c gp_hadoop_home -v "/usr/lib/hadoop"
更多信息请见Greenplum数据库参考指南。
为Master和Segment重载更新后的postgresql.conf文件:
gpstop -u
用户可以用下面的命令确认更改:
$ gpconfig -s gp_hadoop_target_version
$ gpconfig -s gp_hadoop_home
为拥有HDFS中外部表的角色授予Greenplum数据库的gphdfs协议特权,这些角色包括gpadmin和其他超级用户角色。授予SELECT特权会让角色能够创建HDFS中的可读外部表。授予INSERT特权会让角色能够创建HDFS中的可写外部表。
#= GRANT SELECT ON PROTOCOL gphdfs TO gpadmin;
#= GRANT INSERT ON PROTOCOL gphdfs TO gpadmin;
为外部表拥有者角色授予Greenplum数据库的外部表特权:
ALTER ROLE HDFS_USER CREATEEXTTABLE (type='readable');
ALTER ROLE HDFS_USER CREATEEXTTABLE (type='writable');
注意: 一种最佳实践是,至少每年都重新审查数据库特权,包括gphdfs外部表特权。
创建并安装Keytab文件
- 作为root登入KDC服务器。
使用kadmin.local命令为gpadmin用户创建一个新的主体:
# kadmin.local -q "addprinc -randkey gpadmin@LOCAL.DOMAIN"
使用kadmin.local为Greenplum数据库集群中的每一台主机产生一个Kerberos服务主体。服务主体应该是下列形式之一name/role@REALM,其中
- name是gphdfs服务的用户名。这个例子使用了gphdfs。
- role是一台Greenplum集群主机的DNS可解析的主机名(hostname -f命令的输出)。
- REALM是Kerberos的realm,例如LOCAL.DOMAIN。
例如,下面的命令为四台Greenplum数据库主机mdw.example.com、smdw.example.com、sdw1.example.com以及sdw2.example.com增加服务主体:
# kadmin.local -q "addprinc -randkey gphdfs/mdw.example.com@LOCAL.DOMAIN"
# kadmin.local -q "addprinc -randkey gphdfs/smdw.example.com@LOCAL.DOMAIN"
# kadmin.local -q "addprinc -randkey gphdfs/sdw1.example.com@LOCAL.DOMAIN"
# kadmin.local -q "addprinc -randkey gphdfs/sdw2.example.com@LOCAL.DOMAIN"
为每一台Greenplum集群主机创建一个主体。使用相同的主体名称和realm,为每台主机替换完全限定的域名。
为刚创建的每一个主体(gpadmin和每一个gphdfs主体)生成一个keytab文件。用户可以在任意方便的位置存放keytab文件(这个例子使用了目录/etc/security/keytabs)。在后面的步骤中,用户将把服务主体的keytab文件部署到它们相应的Greenplum主机上:
# kadmin.local -q “xst -k /etc/security/keytabs/gphdfs.service.keytab gpadmin@LOCAL.DOMAIN”
# kadmin.local -q “xst -k /etc/security/keytabs/mdw.service.keytab gpadmin/mdw gphdfs/mdw.example.com@LOCAL.DOMAIN”
# kadmin.local -q “xst -k /etc/security/keytabs/smdw.service.keytab gpadmin/smdw gphdfs/smdw.example.com@LOCAL.DOMAIN”
# kadmin.local -q “xst -k /etc/security/keytabs/sdw1.service.keytab gpadmin/sdw1 gphdfs/sdw1.example.com@LOCAL.DOMAIN”
# kadmin.local -q “xst -k /etc/security/keytabs/sdw2.service.keytab gpadmin/sdw2 gphdfs/sdw2.example.com@LOCAL.DOMAIN”
# kadmin.local -q “listprincs”
按下面的方式更改gphdfs.service.keytab上的拥有关系和权限:
# chown gpadmin:gpadmin /etc/security/keytabs/gphdfs.service.keytab
# chmod 440 /etc/security/keytabs/gphdfs.service.keytab
为gpadmin@LOCAL.DOMAIN把keytab文件拷贝到Greenplum的Master主机:
# scp /etc/security/keytabs/gphdfs.service.keytab mdw_fqdn:/home/gpadmin/gphdfs.service.keytab
为每一个服务主体将keytab文件拷贝到相应的Greenplum主机:
# scp /etc/security/keytabs/mdw.service.keytab mdw_fqdn:/home/gpadmin/mdw.service.keytab
# scp /etc/security/keytabs/smdw.service.keytab smdw_fqdn:/home/gpadmin/smdw.service.keytab
# scp /etc/security/keytabs/sdw1.service.keytab sdw1_fqdn:/home/gpadmin/sdw1.service.keytab
# scp /etc/security/keytabs/sdw2.service.keytab sdw2_fqdn:/home/gpadmin/sdw2.service.keytab
为Kerberos配置gphdfs
在所有Greenplum集群主机上编辑Hadoop的core-site.xml客户端配置文件。通过把hadoop.security.authorization属性设置为true来启用服务级授权。例如:
<property>
<name>hadoop.security.authorization</name>
<value>true</value>
</property>
在所有的集群主机上编辑yarn-site.xml客户端配置文件。设置资源管理器地址以及yarn的Kerberos服务主体。例如:
<property>
<name>yarn.resourcemanager.address</name>
<value>hostname:8032</value>
</property>
<property>
<name>yarn.resourcemanager.principal</name>
<value>yarn/hostname@DOMAIN</value>
</property>
在所有的集群主机上编辑hdfs-site.xml客户端配置文件。设置属性以标识NameNode的Kerberos主体、Kerberos的keytab文件位置以及其主体:
- dfs.namenode.kerberos.principal - gphdfs协议将为NameNode使用的Kerberos主体名,例如gpadmin@LOCAL.DOMAIN。
- dfs.namenode.https.principal - gphdfs将用于NameNode的安全HTTP服务器的Kerberos主体名。例如gpadmin@LOCAL.DOMAIN。
- com.emc.greenplum.gpdb.hdfsconnector.security.user.keytab.file - 用于Kerberos保护的HDFS服务的keytab文件路径,例如 /home/gpadmin/mdw.service.keytab。
- com.emc.greenplum.gpdb.hdfsconnector.security.user.name - the 主机的gphdfs服务主体,例如 gphdfs/mdw.example.com@LOCAL.DOMAIN。
例如:
<property>
<name>dfs.namenode.kerberos.principal</name>
<value>gphdfs/gpadmin@LOCAL.DOMAIN</value>
</property>
<property>
<name>dfs.namenode.https.principal</name>
<value>gphdfs/gpadmin@LOCAL.DOMAIN</value>
</property>
<property>
<name>com.emc.greenplum.gpdb.hdfsconnector.security.user.keytab.file</name>
<value>/home/gpadmin/gpadmin.hdfs.keytab</value>
</property>
<property>
<name>com.emc.greenplum.gpdb.hdfsconnector.security.user.name</name>
<value>gpadmin/@LOCAL.DOMAIN</value>
</property>
测试Greenplum数据库对HDFS的访问
确认在Greenplum集群中所有主机上都能通过Kerberos认证访问HDFS。例如,输入下列命令列出一个HDFS目录:
hdfs dfs -ls hdfs://namenode:8020
在HDFS中创建一个可读外部表
按照这些步骤验证能够在Kerberos化的Hadoop集群中创建可读外部表。
创建一个逗号分隔的文本文件test1.txt,其内容如下:
25, Bill
19, Anne
32, Greg
27, Gloria
将示例文本文件放在HDFS中:
hdfs dfs -put test1.txt hdfs://namenode:8020/tmp
登入Greenplum数据库,并且创建一个指向Hadoop中test1.txt文件的可读外部表:
CREATE EXTERNAL TABLE test_hdfs (age int, name text)
LOCATION('gphdfs://namenode:8020/tmp/test1.txt')
FORMAT 'text' (delimiter ',');
从该外部表读取数据:
SELECT * FROM test_hdfs;
在HDFS中创建一个可写外部表
按照这些步骤验证能够在Kerberos化的Hadoop集群中创建可写外部表。这些步骤使用之前创建的可读外部表test_hdfs。
登入Greenplum数据库,并且创建一个可写外部表指向一个HDFS中的文本文件:
CREATE WRITABLE EXTERNAL TABLE test_hdfs2 (LIKE test_hdfs)
LOCATION ('gphdfs://namenode:8020/tmp/test2.txt'
FORMAT 'text' (DELIMITER ',');
装载数据到可写外部表中:
INSERT INTO test_hdfs2
SELECT * FROM test_hdfs;
检查该文件在HDFS中存在:
hdfs dfs -ls hdfs://namenode:8020/tmp/test2.txt
验证外部文件的内容:
hdfs dfs -cat hdfs://namenode:8020/tmp/test2.txt
排查带有Kerberos的HDFS的故障
强制Classpath
如果用户在执行来自gphdfs的外部表上的SELECT语句时遇到“class not found”错误,可编辑$GPHOME/lib/hadoop-env.sh文件并且把下面的行加在该文件的末尾,但是要放在设置JAVA_LIBRARY_PATH之前。在所有集群主机上都更新该脚本。
if [ -d "/usr/hdp/current" ]; then
for f in /usr/hdp/current/**/*.jar; do
CLASSPATH=${CLASSPATH}:$f;
done
fi
启用Kerberos客户端调试消息
要查看来自Kerberos客户端的调试消息,可在所有集群主机上编辑$GPHOME/lib/hadoop-env.sh客户端shell脚本,并且将HADOOP_OPTS变量设置为如下:
export HADOOP_OPTS="-Djava.net.prefIPv4Stack=true -Dsun.security.krb5.debug=true ${HADOOP_OPTS}"
在Segment主机上调整JVM进程内存
在读写HDFS中的外部表时,每个Segment会启动一个JVM进程。要更改为每个JVM进程分配的内存量,可以配置GP_JAVA_OPT环境变量。
在所有集群主机上编辑$GPHOME/lib/hadoop-env.sh客户端shell脚本。
例如:
export GP_JAVA_OPT=-Xmx1000m
验证Kerberos的安全性设置
检查/etc/krb5.conf文件:
- 如果AES256加密没有被禁用,确保所有集群主机都安装了JCE Unlimited Strength Jurisdiction Policy Files。
确保Kerberos的keytab文件中的所有加密类型匹配krb5.conf文件中的定义。
cat /etc/krb5.conf | egrep supported_enctypes
在单个Segment主机上测试连通性
按这些步骤测试单个Greenplum数据库主机能够读取HDFS数据。这种测试方法在命令行中执行Greenplum的HDFSReader Java类,并且能够有助于排查数据库之外的连通性问题。
在HDFS中保存一份示例数据文件。
hdfs dfs -put test1.txt hdfs://namenode:8020/tmp
在要测试的Segment主机上,按下面的内容创建一个环境脚本env.sh:
export JAVA_HOME=/usr/java/default
export HADOOP_HOME=/usr/lib/hadoop
export GP_HADOOP_CON_VERSION=hdp2
export GP_HADOOP_CON_JARDIR=/usr/lib/hadoop
引入所有环境脚本:
source /usr/local/greenplum-db/greenplum_path.sh
source env.sh
source $GPHOME/lib/hadoop-env.sh
测试Greenplum数据库的HDFS读取器:
java com.emc.greenplum.gpdb.hdfsconnector.HDFSReader 0 32 TEXT hdp2 gphdfs://namenode:8020/tmp/test1.txt