本來要進行HDFS集群的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
IP地址
角色
說明
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。下面對每個文件的修改內容進行依次說明:
在所有的NameNode和DataNode上修改該配置文件,在該配置文件上增加如下配置內容:
<property>
<name>hadoop.security.key.provider.path</name>
<value>kms://http@BJ-PRESTO-TEST-100080.lvxin.com:16000/kms</value>
</property>
在所有的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服務只需要在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服務僅需要在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服務僅需要在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]$
[hadp@BJ-PRESTO-TEST-100080 hadoop]$start-dfs.sh
在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: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都需要執行該命令,並且每組的用戶權限都是獨立的。
在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-
下面的內容同樣精彩
點擊圖片即可閱讀
京東技術 ∣關注技術的公眾號
長按,識別二維碼,加關注