关于HDFS-KMS集群化部署教程,你以前看的都错了!
Posted 京东技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于HDFS-KMS集群化部署教程,你以前看的都错了!相关的知识,希望对你有一定的参考价值。
来这里找志同道合的小伙伴!
吕信,京东商城基础架构部资深架构师,拥有多年数据产品研发及架构经验。在京东及国内主导过多种数据产品的开发及社区建设,积极活跃于数据产品领域,对数据库及大数据领域各个产品具有丰富经验,目前在京东商城主导弹性数据库研发及推广使用。
写在前面
本来要进行HDFS集群的KMS部署的,其实这是很成熟的技术,在网上找了很长,竟然没有靠谱的教程,不是错误的,就是单机自己玩模式的,不知从什么时候起,有个先驱写了一篇错误的教程,然后这些抄袭者们就开始各种复制粘贴,也不去验证对错,着实让我悲愤。
一气之下,决定自己参照官方文档进行部署,然后将部署的过程和结果写下来,来祭奠那些抄袭者们。
本文章仅代表作者自己的实际部署及操作结果,有任何疏漏,望指正。
KMS说明
Hadoop KMS是一个基于 Hadoop的加密管理服务端。Client是一个KeyProvider的实现,使用KMS HTTP REST API与KMS交互。
KMS和它的客户端内置安全验证并且它们支持HTTP SPNEGO Kerberos 身份验证和HTTPS安全转换。
由于本次只是为了说明如何部署KMS,所以本文档就采用simple的身份认证模式,没有采用Kerberos。需要采用Kerberos进行身份认证的同仁可以参考官方文档进行Kerberos认证模式部署。
KMS实际上是一个Java Web应用程序,运行在与Hadoop发行版绑定在一起的预先配置好的Tomcat服务器上。
注意:Kms是一个密钥管理服务器,它并不负责加密文件。
通过KMS可以实现用户无感知的HDFS端到端的透明加密。配置完kms后,用户往hdfs上存储数据的时候,无需用户做任何程序代码的更改(通过调用KeyProvider API ,在数据存入到HDFS上面的时候进行数据加密,解密的过程一样)。数据加密和解密由客户端自动完成。
环境说明
软件名称 |
软件版本 |
Hadoop |
Hadoop 2.6.1 |
JDK |
1.8.0_92 |
操作系统 |
CentOS release 6.5 (Final) |
Hadoop超级用户 |
hadp |
服务器列表
HostName |
角色 |
说明 |
|
BJ-PRESTO-TEST-100080.lvxin.com |
192.168.100.80 |
NameNode,kms |
|
BJ-PRESTO-TEST-100081.lvxin.com |
192.168.100.81 |
NameNode |
|
BJ-PRESTO-TEST-100082.lvxin.com |
192.168.100.82 |
DataNode |
|
BJ-PRESTO-TEST-100083.lvxin.com |
192.168.100.83 |
DataNode |
|
BJ-PRESTO-TEST-100084.lvxin.com |
192.168.100.84 |
DataNode |
|
BJ-PRESTO-TEST-100085.lvxin.com |
192.168.100.85 |
DataNode |
|
BJ-PRESTO-TEST-100086.lvxin.com |
192.168.100.86 |
DataNode |
|
BJ-PRESTO-TEST-100087.lvxin.com |
192.168.100.87 |
DataNode |
|
BJ-PRESTO-TEST-100088.lvxin.com |
192.168.100.88 |
DataNode |
|
BJ-PRESTO-TEST-100089.lvxin.com |
192.168.100.89 |
DataNode |
|
BJ-PRESTO-TEST-100090.lvxin.com |
192.168.100.90 |
DataNode |
|
BJ-PRESTO-TEST-100091.lvxin.com |
192.168.100.91 |
DataNode |
|
BJ-PRESTO-TEST-100092.lvxin.com |
192.168.100.92 |
DataNode |
|
BJ-PRESTO-TEST-100093.lvxin.com |
192.168.100.93 |
HDFS Client |
配置说明
完成KMS的配置共涉及到5个文件的修改,分别是:core-site.xml、hdfs-site.xml、kms-site.xml、kms-env.sh、kms-acls.xml。下面对每个文件的修改内容进行依次说明:
core-site.xml
在所有的NameNode和DataNode上修改该配置文件,在该配置文件上增加如下配置内容:
<property> <name>hadoop.security.key.provider.path</name> <value>kms://http@BJ-PRESTO-TEST-100080.lvxin.com:16000/kms</value> </property> |
hdfs-site.xml
在所有的NameNode和DataNode上修改该配置文件,在该配置文件上增加如下配置内容:
<property> <name>dfs.encryption.key.provider.uri </name> <value>kms://http@BJ-PRESTO-TEST-177080.jd.com:16000/kms</value> </property> |
【注意】上面两个配置文件修改完毕后,需要重启HDFS服务,后面的修改仅重启kms服务即可。
kms-site.xml
由于Kms服务只需要在NameNode:BJ-PRESTO-TEST-100080.lvxin.com上启动,因此仅需要修改BJ-PRESTO-TEST-100080.lvxin.com服务器上的该配置文件,其他服务器上的该配置文件不需要修改。在该配置文件上增加如下配置内容:
<!-- KMS Backend KeyProvider --> <property> <name>hadoop.kms.key.provider.uri</name> <value>jceks://file@/${user.home}/kms.keystore</value> </property> <property> <name>hadoop.security.keystore.java-keystore-provider.password-file</name> <value>kms.keystore.password</value> <!--秘钥密码存储文件,该文件需要手动创建,并且放在kms的tomcat下classes文件夹下--> </property> <!—本文关注与kms部署这里选择simple就可以了--> <property> <name>hadoop.kms.authentication.type</name> <value>simple</value> </property> </configuration> |
使用keytool生成的秘钥密码是123456 将密码直接写入到kms.keystore.password文件:
echo 123456 > ${HADOOP_HOME}/share/hadoop/kms/tomcat/webapps/kms/WEB-INF/classes/kms.keystore.password |
kms-env.sh
由于Kms服务仅需要在NameNode:BJ-PRESTO-TEST-100080.lvxin.com上启动,因此仅需要修改BJ-PRESTO-TEST-100080.lvxin.com服务器上的该配置文件,其他服务器上的该配置文件不需要修改。在该配置文件上增加如下配置内容:
export KMS_HOME=${HADOOP_HOME} export KMS_LOG=${KMS_HOME}/logs/kms export KMS_HTTP_PORT=16000 export KMS_ADMIN_PORT=16001 |
【注】这里可以通过kms-env.sh这个脚本来设置。也可以直接设置在~/.bashrc中。
kms-acls.xml
由于Kms服务仅需要在NameNode:BJ-PRESTO-TEST-100080.lvxin.com上启动,因此仅需要修改BJ-PRESTO-TEST-100080.lvxin.com服务器上的该配置文件:kms-acls.xml,其他服务器上的该配置文件不需要修改。该文件可能会随时改变,主要用来配置key与用户的对应关系。
根据测试需要,我们添加两个用户:user_a和user_b,新增user_a_key对应user_a,user_b_key对应user_b,因此需要在配置文件:$HADOOP_CONF_DIR/kms-acls.xml中添加如下配置项:
<property> <name>key.acl.user_a_key.DECRYPT_EEK</name> <value>user_a</value> </property> <property> <name>key.acl.user_b_key.DECRYPT_EEK</name> <value>user_b</value> </property> |
创建密钥
只需要在NameNode:BJ-PRESTO-TEST-100080.lvxin.com 上创建密钥,创建密钥步骤如下:
Step1:创建user_a_key
[hadp@BJ-PRESTO-TEST-100080 hadoop]$ keytool -genkey -alias 'user_a_key' 输入密钥库口令: ##这里输入的口令是:123456 您的名字与姓氏是什么? [Unknown]: lvxin 您的组织单位名称是什么? [Unknown]: jd 您的组织名称是什么? [Unknown]: jd 您所在的城市或区域名称是什么? [Unknown]: bj 您所在的省/市/自治区名称是什么? [Unknown]: bj 该单位的双字母国家/地区代码是什么? [Unknown]: cn CN=lvxin, OU=jd, O=jd, L=bj, ST=bj, C=cn是否正确? [否]: 是
输入 <user_a_key> 的密钥口令 (如果和密钥库口令相同, 按回车): #这里输入的口令与第一次输入的口令一样,都是:123456 再次输入新口令: [hadp@BJ-PRESTO-TEST-100080 hadoop]$ |
Step2:以相同方式创建user_b_key
[hadp@BJ-PRESTO-TEST-100080 hadoop]$ keytool -genkey -alias 'user_b_key' 输入密钥库口令: 您的名字与姓氏是什么? [Unknown]: lvxin 您的组织单位名称是什么? [Unknown]: jd 您的组织名称是什么? [Unknown]: jd 您所在的城市或区域名称是什么? [Unknown]: bj 您所在的省/市/自治区名称是什么? [Unknown]: bj 该单位的双字母国家/地区代码是什么? [Unknown]: cn CN=lvxin, OU=jd, O=jd, L=bj, ST=bj, C=cn是否正确? [否]: 是
输入 <user_b_key> 的密钥口令 #(如果和密钥库口令相同, 按回车): [hadp@BJ-PRESTO-TEST-100080 hadoop]$ |
Step3:查看刚刚创建完成的密钥
[hadp@BJ-PRESTO-TEST-100080 hadoop]$ keytool -list 输入密钥库口令: #这里输入上面的密码:123456
密钥库类型: JKS 密钥库提供方: SUN
您的密钥库包含 2 个条目
user_a_key, 2018-7-3, PrivateKeyEntry, 证书指纹 (SHA1): 47:5A:5B:09:6F:50:65:8D:9B:5F:5A:E5:48:88:1C:86:63:BB:10:39 user_b_key, 2018-7-3, PrivateKeyEntry, 证书指纹 (SHA1): 71:75:E8:7F:90:57:BE:E1:CD:03:63:D1:7F:28:5D:51:BC:5D:D5:8C [hadp@BJ-PRESTO-TEST-100080 hadoop]$ |
启动hdfs
[hadp@BJ-PRESTO-TEST-100080 hadoop]$start-dfs.sh |
启动KMS
在namenode:BJ-PRESTO-TEST-100080.lvxin.com上执行命令:kms.sh start,此时会启动一个进程:Bootstrap,如下所示:
[hadp@BJ-PRESTO-TEST-100080 ~]$ kms.sh start setting KMS_HOME=${HADOOP_HOME} setting KMS_LOG=${KMS_HOME}/logs/kms setting KMS_HTTP_PORT=16000 setting KMS_ADMIN_PORT=16001 Using CATALINA_BASE: /software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat Using CATALINA_HOME: /software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat Using CATALINA_TMPDIR: /software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat/temp Using JRE_HOME: /software/servers/jdk1.8.0_92 Using CLASSPATH: /software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat/bin/bootstrap.jar Using CATALINA_PID: /tmp/kms.pid Existing PID file found during start. Removing/clearing stale PID file. [hadp@BJ-PRESTO-TEST-100080 ~]$ ps -ef|grep -i "Bootstrap" hadp 14414 1 99 16:12 pts/1 00:00:12 /software/servers/jdk1.8.0_92/bin/java -Djava.util.logging.config.file=/software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dkms.home.dir=/software/servers/hadoop-2.6.1 -Dkms.config.dir=/software/servers/hadoop-2.6.1/etc/hadoop -Dkms.log.dir=/software/servers/hadoop-2.6.1/logs/kms -Dkms.temp.dir=/software/servers/hadoop-2.6.1/temp -Dkms.admin.port=16001 -Dkms.http.port=16000 -Dkms.max.threads=1000 -Dkms.ssl.keystore.file=/home/hadp/.keystore -Dkms.ssl.keystore.pass=password -Djava.endorsed.dirs=/software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat/endorsed -classpath /software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat/bin/bootstrap.jar -Dcatalina.base=/software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat -Dcatalina.home=/software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat -Djava.io.tmpdir=/software/servers/hadoop-2.6.1/share/hadoop/kms/tomcat/temp org.apache.catalina.startup.Bootstrap start hadp 14482 14371 0 16:13 pts/1 00:00:00 grep -i Bootstrap |
创建加密区
创建key
[hadp@BJ-PRESTO-TEST-100080 ~]$ hadoop key create user_a_key user_a_key has been successfully created with options Options{cipher='AES/CTR/NoPadding', bitLength=128, description='null', attributes=null}. KMSClientProvider[http://BJ-PRESTO-TEST-100080.lvxin.com:16000/kms/v1/] has been updated |
【注】user_a_key为上面通过keytool创建的密钥。
查看key详细信息
[hadp@BJ-PRESTO-TEST-100080 ~]$ hadoop key list Listing keys for KeyProvider: KMSClientProvider[http://BJ-PRESTO-TEST-100080.lvxin.com:16000/kms/v1/] user_a_key [hadp@BJ-PRESTO-TEST-100080 ~]$ |
创建文件目录
[hadp@BJ-PRESTO-TEST-100080 ~]$ hadoop fs -mkdir /user_a |
配置user_a目录权限
[hadp@BJ-PRESTO-TEST-100080 ~]$ hadoop fs -chown user_a:test_group /user_a |
设置/user_a为加密区
[hadp@BJ-PRESTO-TEST-100080 ~]$ hdfs crypto -createZone -keyName user_a_key -path /user_a Added encryption zone /user_a [hadp@BJ-PRESTO-TEST-100080 ~]$ |
【注】加密区必须是空目录,几级目录都行,但必须为空。
查看已加密区域
[hadp@BJ-PRESTO-TEST-100080 ~]$ hdfs crypto -listZones /user_a user_a_key
[hadp@BJ-PRESTO-TEST-100080 ~]$ |
【注】以相同方式创建user_b目录并使用user_b_key对目录加密。
验证
我们通过添加三个用户user_a、user_b、user_c对加密结果进行验证。
添加测试用户
NameNode操作
在两个NameNode:BJ-PRESTO-TEST-100080.lvxin.com和BJ-PRESTO-TEST-100081.lvxin.com上的配置文件:hadoop-policy.xml中添加测试用户访问权限。
常用的限制访问hdfs的权限配置,只需要修改security.client.protocol.acl参数即可,此参数用于控制哪些用户可以访问hdfs,配置为“*”时表示任何用户都不受限制,此参数在配置文件:hadoop-policy.xml中。
Step1:修改配置文件
在NameNode:BJ-PRESTO-TEST-100080.lvxin.com的配置文件:$HADOOP_CONF_DIR/Hadoop-policy.xml中添加如下配置项:
<property> <name>security.client.protocol.acl</name> <value>hadp,user_a,user_b,user_c</value> </property> |
修改完成后,将该配置文件scp到另一个NameNode:BJ-PRESTO-TEST-100081.lvxin.com上:
[hadp@BJ-PRESTO-TEST-100080 hadoop]$ scp hadoop-policy.xml 192.168.100.81:$HADOOP_CONF_DIR/ hadoop-policy.xml |
Step2:刷新NameNode用户访问权限
在任意一个NameNode上执行以下命令刷新用户权限:
[hadp@BJ-PRESTO-TEST-100080 hadoop]$ hdfs dfsadmin -refreshServiceAcl Refresh service acl successful for BJ-PRESTO-TEST-100080.lvxin.com/192.168.100.80:8020 Refresh service acl successful for BJ-PRESTO-TEST-100081.lvxin.com/192.168.100.81:8020 [hadp@BJ-PRESTO-TEST-100080 hadoop]$ |
【注】如果启动了Federation的功能,每组NameNode都需要执行该命令,并且每组的用户权限都是独立的。
Client端操作
在HDFS Client端: BJ-PRESTO-TEST-100093.lvxin.com上有三个用户分别是user_a,user_b,user_c,然后在每个新建用户的~/.bashrc中添加如下配置信息:
[user_a@BJ-PRESTO-TEST-100093 ~]$ cat ~/.bashrc # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi export JAVA_HOME=/software/servers/jdk1.8.0_92 export PATH=$JAVA_HOME/bin:$PATH export HADOOP_HOME=/software/servers/hadoop-2.6.1 export HADOOP_MAPRED_HOME=$HADOOP_HOME export HADOOP_COMMON_HOME=$HADOOP_HOME export HADOOP_HDFS_HOME=$HADOOP_HOME export HADOOP_YARN_HOME=$HADOOP_HOME export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop export HDFS_CONF_DIR=$HADOOP_HOME/etc/hadoop export YARN_CONF_DIR=$HADOOP_HOME/etc/hadoop export PATH=$PATH:$HADOOP_HOME/bin:$JAVA_HOME/bin:$HADOOP_HOME/sbin: |
然后执行source:
[user_a@BJ-PRESTO-TEST-100093 ~]$ source ~/.bashrc |
加密验证
在Client端:BJ-PRESTO-TEST-100093.lvxin.com,使用user_c用户上传文件test.txt至user_a及user_b文件目录,均报错没有权限,但是可以上传至/user_c目录:
[root@BJ-PRESTO-TEST-100093 ~]# su - user_c [user_c@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -put test.txt /user_a put: Permission denied: user=user_c, access=WRITE, inode="/user_a":user_a:test_group:drwxr-xr-x [user_c@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -put test.txt /user_b put: Permission denied: user=user_c, access=WRITE, inode="/user_b":user_b:test_group:drwxr-xr-x [user_c@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -put test.txt /user_c user_c@BJ-PRESTO-TEST-100093 ~]$ |
切换至user_a用户,将test.txt文件上传至/user_a文件夹,切换至user_b用户,将test.txt文件上传至/user_b文件夹。
使用user_a用户读取/user_a/test.txt文件可正常显示,读取/user_b/test.txt文件提示没有权限:
[root@BJ-PRESTO-TEST-100093 ~]# su - user_a [user_a@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -put test.txt /user_a [user_a@BJ-PRESTO-TEST-100093 ~]$ logout [root@BJ-PRESTO-TEST-100093 ~]# su - user_b [user_b@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -put test.txt /user_b [user_b@BJ-PRESTO-TEST-100093 ~]$ logout [root@BJ-PRESTO-TEST-100093 ~]# su - user_a [user_a@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -cat /user_a/test.txt this is content!!!! [user_a@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -cat /user_b/test.txt cat: User [user_a] is not authorized to perform [DECRYPT_EEK] on key with ACL name [user_b_key]!! [user_a@BJ-PRESTO-TEST-100093 ~]$ |
由于在hdfs中所有的文件都会在目录/.reserved下面存储一份原始文件,因此我们查看加密区下文件/user_a/test.txt在/.reserved下面的原始文件,从而验证该文件有没有被加密:
[user_a@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -cat /.reserved/raw/user_a/test.txt W�F(�9����N!�r'�:[user_a@BJ-PRESTO-TEST-100093 ~]$ |
由于原始文件没有在加密区中,但是文件的内容是经过kms加密后的内容,所以读取原始文件的过程没有kms解密阶段,所以读出来的内容是密文。
然后查看/user_c/test.txt对应的的原始文件:
[user_a@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -cat /.reserved/raw/user_c/test.txt this is content!!!! [user_a@BJ-PRESTO-TEST-100093 ~]$
|
由于/user_c不是加密区,所以文件/user_c/test.txt的内容是没有经过加密的因此该目录下的所有文件都是非加密的,因此读到的原始文件的内容就是明文。
因此,可以证明加密区的文件确实经过了kms的透明加密。
总结
通过KMS可以实现hdfs文件的透明加密,并且验证通过。
问题及解决方案
1、Access denied for user user_a. Superuser privilege is require
在使用user_a查看/.reserved/raw下面的文件的时候,报出错误,说没有权限,现象如下:
[user_a@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -cat /.reserved/raw/user_a/test.txt
cat: Access denied for user user_a. Superuser privilege is required
[user_a@BJ-PRESTO-TEST-100093 ~]$
原因:user_a,user_b,user_c不是超级用户权限。由于hdfs中没有配置超级用户组,因此hdfs的的默认超级用户组就是:supergroup,由于hdfs的用户权限验证过程是:根据客户端的用户名,验证在NameNode上的操作系统中该用户名所属的用户组是否为超级用户:supergroup,若是supergroup,则该用户就是超级用户;否则就不是超级用户。因此需要在两个NameNode上都执行下面的操作可以解决该问题:
useradd -g supergroup user_a useradd -g supergroup user_b useradd -g supergroup user_c |
2、can't be moved from an encryption zone
当从加密区删除透明加密过的文件时报出此错误,如下:
[user_a@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -rm /user_a/test.txt 18/07/04 13:04:25 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 1440 minutes, Emptier interval = 0 minutes. rm: Failed to move to trash: hdfs://ns1/user_a/test.txt: /user_a/test.txt can't be moved from an encryption zone. |
解决:
删除的时候加上-skipTrash。
[user_a@BJ-PRESTO-TEST-100093 ~]$ hdfs dfs -rm -skipTrash /user_a/test.txt Deleted /user_a/test.txt |
---------------------END---------------------
下面的内容同样精彩
点击图片即可阅读
以上是关于关于HDFS-KMS集群化部署教程,你以前看的都错了!的主要内容,如果未能解决你的问题,请参考以下文章
必须收藏别再乱找TiDB 集群部署教程了,这篇保姆级教程来帮你!!| 博学谷狂野架构师