简介
HDFS 在kms之上实现了透明的端到端加密
常用操作
创建key
查看key
使用key创建加密区
查看加密区
设置kms acl
kms使用场景验证
验证一: 加密区文件在hdfs上是否真的加密
验证二: 一个用户创建加密区,另一个用户是否可以写文件进去
验证三: 使用kms,设置加密区之后性能影响多大
方式一: 使用hadoop benchmark的TestDFSIO测试kms对hdfs读写的影响
测试方式
读性能
写性能
结论
性能测试-java代码
测试思路
使用只有4个字符的小文件测试
整体测试结论
KMS 的全称是:Hadoop Key Management Server 密钥管理服务器
kms只提供加密、解密算法以及key管理服务,并不提供帮忙去加、解密。用户自己获取到秘钥之后自己去做加、解密操作。
Kms 有一个加密区 这个特殊的区域 对于能够进行操作他的用户 提供有写入和读取的权限。
当加密区被创建的时候,每个加密区有唯一的秘钥, data encryption key (DEK), 秘钥dek不由hdfs直接控制,但是hdfs控制encrypted data encryption key (EDEK),被加密的秘钥;由客户端解密EDEK;
kms server kms 服务器
kms client kms 客户端
kms zone kms 加密区
hdfs的客户端进行了封装。用户通过命令或者代码设置hdfs中某个目录为加密区(如: /data),并且加加密区秘钥赋权给对应用户之后
用户向/data中写文件时,client除了向namenode获取文件位置等信息以外,还会向kms申请数据文件的秘钥,客户端使用秘钥对数据文件进行加密。
用户从/data中读文件时,client除了向namenode获取文件位置等信息以外,还会向kms申请数据文件的秘钥,客户端使用秘钥对数据文件进行解密。
整个过程对用户是透明的。
hdfs在kms做完封装之后,用户只要做如下几种类型的操作:
key管理(管理员操作:创建、删除)
加密区管理(管理员操作:创建、删除)
key赋权 (管理员操作:给需要读取加密区的用户赋予key权限)
# hadoop key create key1
# hadoop key list
# hdfs dfs -mkdir /testkms
# hdfs crypto -createZone -keyName key1 -path /testkms
[admin@dp0652 ~]$ hdfs crypto -listZones
/testkms key1
修改之后点,“操作”-“刷新key manage server”即可生效
测试方式:
在hdfs上创建2个目录/testkms 和 /test/testkms 前者设置成加密区,后者不设置。
[admin@dp0652 ~]$ hdfs crypto -listZones
/testkms key1
在两个目录各自上传一个warnMsg.log文件:
查看加密区文件在datanode目录里是否加密
hadoop fsck /testkms/warnMsg.log -files -locations -blocks
执行结果:
0. BP-291552141-10.57.17.125-1495075521710:blk_1076543087_2807119 len=616 Live_repl=2 [DatanodeInfoWithStorage[10.57.17.88:1004,DS-72479767-055b-410b-9bc1-586ae7f36569,DISK], DatanodeInfoWithStorage[10.57.17.125:1004,DS-ff64c32e-dbe5-4faf-a5e9-428ee530519b,DISK]]
到对应datanode的dn目录下查找相应块:
[root@dp125 ~]# find /dfs/dn -name blk_1076543087*
/dfs/dn/current/BP-291552141-10.57.17.125-1495075521710/current/finalized/subdir42/subdir190/blk_1076543087
/dfs/dn/current/BP-291552141-10.57.17.125-1495075521710/current/finalized/subdir42/subdir190/blk_1076543087_2807119.meta
查看加密区对应数据块:
[root@dp125 ~]# cat /dfs/dn/current/BP-291552141-10.57.17.125-1495075521710/current/finalized/subdir42/subdir190/blk_1076543087
???f??????b???\??v??N{ɚaa?OAs??#?T??????j?x???B???_?V;ԑ?6/_\b??Zm??|???=7?
zO??d?'??X??(??.?d???w?j?<(ъ@?h
可以看到结果是加密过的。
查看非加密区对应数据块(数据块位置查找同上):
[root@dp88 subdir158]# cat /dfs/dn/current/BP-291552141-10.57.17.125-1495075521710/current/finalized/subdir42/subdir225/blk_1076552171
[2018-03-19 09:33:25.927] [INFO] - sendWarnMsg:84 - new hermes addr:http://10.57.17.143
[2018-03-19 11:21:39.525] [INFO] - sendWarnMsg:84 - new hermes addr:http://10.57.17.143
。。。
可以看到数据未加密
使用管理用户admin操作加密区
上传文件到加密区
hdfs dfs -copyFromLocal /home/admin/logs/warnMsg.log /testkms/
从加密区下载文件
hdfs dfs -copyToLocal /testkms/ /home/admin/
都可以成功
使用普通用户xx.tang操作加密区
用xx.tang用户在加密区上上传或者下载或者查看均失败,提示没有权限
从加密区下载
[admin@dp233 ~]$ hdfs dfs -copyToLocal /testkms/warnMsg.log /home/admin/
copyToLocal: User [xx.tang] is not authorized to perform [DECRYPT_EEK] on key with ACL name [key1]!!
对加密区文件执行cat
[admin@dp233 ~]$ hdfs dfs -cat /testkms/warnMsg.log
cat: User [xx.tang] is not authorized to perform [DECRYPT_EEK] on key with ACL name [key1]!!
由于xx.tang用户没有key1的acl权限,获取不到key1,因此无法对加密区进行读、写操作。
下列测试均执行过多次取平均值。
使用hadoop benchmark的TestDFSIO测试kms对hdfs读写的影响。
读、写100个文件,每个文件1M
测试命令:
写测试:
hadoop jar /opt/cloudera/parcels/CDH-5.15.0-1.cdh5.15.0.p0.21/jars/hadoop-test-2.6.0-mr1-cdh5.15.0.jar TestDFSIO -write -nrFiles 100 -fileSize 1
读测试:
hadoop jar /opt/cloudera/parcels/CDH-5.15.0-1.cdh5.15.0.p0.21/jars/hadoop-test-2.6.0-mr1-cdh5.15.0.jar TestDFSIO -read -nrFiles 100 -fileSize 1
未开启加密
19/01/28 18:47:51 INFO fs.TestDFSIO: ----- TestDFSIO ----- : read
19/01/28 18:47:51 INFO fs.TestDFSIO: Date & time: Mon Jan 28 18:47:51 CST 2019
19/01/28 18:47:51 INFO fs.TestDFSIO: Number of files: 100
19/01/28 18:47:51 INFO fs.TestDFSIO: Total MBytes processed: 100.0
19/01/28 18:47:51 INFO fs.TestDFSIO: Throughput mb/sec: 56.46527385657821
19/01/28 18:47:51 INFO fs.TestDFSIO: Average IO rate mb/sec: 81.93286895751953
19/01/28 18:47:51 INFO fs.TestDFSIO: IO rate std deviation: 58.727498217529515
19/01/28 18:47:51 INFO fs.TestDFSIO: Test exec time sec: 64.299
开启加密
19/01/28 18:41:29 INFO fs.TestDFSIO: ----- TestDFSIO ----- : read
19/01/28 18:41:29 INFO fs.TestDFSIO: Date & time: Mon Jan 28 18:41:29 CST 2019
19/01/28 18:41:29 INFO fs.TestDFSIO: Number of files: 100
19/01/28 18:41:29 INFO fs.TestDFSIO: Total MBytes processed: 100.0
19/01/28 18:41:29 INFO fs.TestDFSIO: Throughput mb/sec: 23.234200743494423
19/01/28 18:41:29 INFO fs.TestDFSIO: Average IO rate mb/sec: 47.325496673583984
19/01/28 18:41:29 INFO fs.TestDFSIO: IO rate std deviation: 30.17507105918255
19/01/28 18:41:29 INFO fs.TestDFSIO: Test exec time sec: 69.903
未开启加密
19/01/28 18:45:31 INFO fs.TestDFSIO: ----- TestDFSIO ----- : write
19/01/28 18:45:31 INFO fs.TestDFSIO: Date & time: Mon Jan 28 18:45:31 CST 2019
19/01/28 18:45:31 INFO fs.TestDFSIO: Number of files: 100
19/01/28 18:45:31 INFO fs.TestDFSIO: Total MBytes processed: 100.0
19/01/28 18:45:31 INFO fs.TestDFSIO: Throughput mb/sec: 4.015741707493374
19/01/28 18:45:31 INFO fs.TestDFSIO: Average IO rate mb/sec: 4.63060188293457
19/01/28 18:45:31 INFO fs.TestDFSIO: IO rate std deviation: 1.9163955096086411
19/01/28 18:45:31 INFO fs.TestDFSIO: Test exec time sec: 68.438
开启加密
19/01/28 18:36:33 INFO fs.TestDFSIO: ----- TestDFSIO ----- : write
19/01/28 18:36:33 INFO fs.TestDFSIO: Date & time: Mon Jan 28 18:36:33 CST 2019
19/01/28 18:36:33 INFO fs.TestDFSIO: Number of files: 100
19/01/28 18:36:33 INFO fs.TestDFSIO: Total MBytes processed: 100.0
19/01/28 18:36:33 INFO fs.TestDFSIO: Throughput mb/sec: 2.3070711731456917
19/01/28 18:36:33 INFO fs.TestDFSIO: Average IO rate mb/sec: 3.0367138385772705
19/01/28 18:36:33 INFO fs.TestDFSIO: IO rate std deviation: 1.7698150119390728
19/01/28 18:36:33 INFO fs.TestDFSIO: Test exec time sec: 78.297
开启kms之后,读性能变差8.7%左右,写性能变差14.4%左右。
单个task的时间 = 读取block时间+kms解密时间+数据读取后逻辑处理时间+结果输出时间
由于kms只是读、写数据块时多了一步加、解密动作,benchmark跑mr任务,各个task是并行,因此一次跑任务过程当中相当于只有一次加密或者解密。而mr任务跑的时候本身也有一定的时间上下浮动,因此感觉此方式对比不太准。
因此自己写了java方式测试,每次测试进行串行的10次读、写4个字符的小文件以及1.4G大文件,通过对比感知不同场景下开启kms后的性能损耗。
每次测试读、写 10次小文件(文件中只有4个字符)
读性能
未开启加密
最后一行为平均耗时:2101.8毫秒
开启加密
最后一行为平均耗时:2400毫秒
写性能
未开启加密
最后一行为平均耗时:2448.4毫秒
开启加密
最后一行为平均耗时:2853.4毫秒
结论
打成的jar包放到服务器上使用java -jar命令进行测试。
单次测试串行进行10次文件读、写。测5次取平均值。
开启加密区之后,写性能衰减14.4%左右, 读性能衰减14.2%左右
使用1.4G的大文件测试
读性能
未开启加密
最后一行为平均耗时:142110.8毫秒
开启加密
最后一行为平均耗时:145439.8毫秒
写性能
未开启加密
最后一行为平均耗时:140712毫秒
开启加密
最后一行为平均耗时:146468毫秒
结论
打成的jar包放到服务器上使用java -jar命令进行测试。
单次测试串行进行10次文件读、写。测5次取平均值。
开启加密区之后,写性能衰减4%左右, 读性能衰减2.3%左右
当读取只有几个字符小文件时,开启kms后读写性能衰减百分之十几。读取大文件(1.4G,11个block,平均block大小128M)时,性能衰减只有2%-4%,整体衰减很小。
由于hadoop的kms是端到端加密且粒度到block,因此读、写文件时的总时间=向namenode申请数据块地址时间(时间很短,可以忽略不计)+数据块传输+数据块加、解密+数据块内容读取时间。
因此当读写超小文件时,数据传输+数据块内容读写的时间就很短,因此加解密消耗的一点点时间所占总时间的比重就高一些。
当读取大文件时,数据传输+数据块内容读写的时间相对较长,因此加解密消耗的时间所占总时间的比重就明显降低。
因此,在集群小文件问题不是特别严重的情况下,使用kms后的性能衰减应该在10%以内。