HDFS数据开启透明加密

  安装
内容纲要

概要描述


数据加密是安全级别要求较高企业所必须的,比如说金融行业,医疗行业或者政府。我们知道HDFS中的数据会以block的形式保存在各台数据节点的本地磁盘中,但这些block都是明文的,如果在操作系统下,直接访问block所在的目录,通过Linux的cat命令是可以直接查看里面的内容的,而且是明文。

我们知道在Hadoop集群中,可以通过开启Kerberos/LDAP来实现用户身份的认证,通过Guardian实现数据访问的权限控制。但是这些其实无法控制非法用户在操作系统层面直接访问数据,比如直接拷走disk里的所有block文件,这些都是明文,是可以直接查看的。这个时候我们就需要对关键数据进行加密,让非法用户即使从操作系统层面拷走文件,也是密文,没法查看。

HDFS支持端到端的透明加密,启用以后,对于一些需要加密的HDFS目录里的文件可以实现透明的加密和解密,而不需要修改用户的业务代码。端到端是指加密和解密只能通过客户端。对于加密区域里的文件,HDFS保存的即是加密后的文件,文件加密的秘钥也是加密的,HDFS不会存储和直接访问秘钥。

传统数据管理软件或者硬件的加密包含了不同的层级,在不同的层级加密有不同的优点和缺点。

1.应用层加密,这是最安全也是最灵活的方式。加密内容最终由应用程序来控制,并且可以精确的反映用户的需求。但是,编写应用程序来实现加密一般都比较困难,而且有些应用程序可能不支持加密。
2.数据库层加密,类似于应用程序加密。大多数数据库厂商都提供某种形式的加密,但是可能会有性能问题,另外比如说索引没办法加密。
3.文件系统层加密,这种方式对性能影响不大,而且对应用程序是透明的,一般也比较容易实施。但是应用程序细粒度的要求策略,可能无法完全满足。比如,多租户应用程序可能需要对最终用户进行加密,数据库可能需要对单个文件里的每个列进行不同的加密设置。
4.磁盘层加密,易于部署和高性能,但是相当不灵活,只能防止用户从物理层面盗窃数据。

HDFS的透明加密属于数据库层和文件系统层的加密。它有很多好处,比如不错的性能,对于现有的应用程序是透明的。在制定策略时,HDFS也比传统的文件系统有更多的选择。

HDFS加密可以防止在文件系统或之下的攻击,也叫操作系统级别的攻击(OS-level attacks)。操作系统和磁盘只能与加密的数据进行交互,因为数据已经被HDFS加密了。

架构说明


HDFS的透明加密有一个新的概念,加密区域(the encryption zone)。加密区域是一个特殊的目录,写入文件的时候会被透明加密,读取文件的时候又会被透明解密。当加密区域被创建时,都会有一个加密区域秘钥(encryption zone key)与之对应。加密区域里的每个文件都有一个唯一的数据加密秘钥(DEK,data encryption key)。HDFS不会直接处理DEK,HDFS只会处理加密后的DEK(encrypted data encryption key,EDEK)。客户端会解密EDEK,然后用后续的DEK来读取和写入数据。HDFS的DataNode只能看到一串加密字节。

HDFS支持嵌套的加密区域,从而能在文件系统的不同部分使用不同的加密区域秘钥。在创建加密区域之后,比如是根目录/,用户可以用不同的秘钥在子目录比如/home/fayson上创建更多的加密区域。文件的EDEK会使用最近的(the closet ancestor)加密区的秘钥生成。

如果要启用HDFS的透明加密,你需要安装一个额外的服务,KMS(Hadoop Key Management Server),用来管理秘钥。KMS主要有以下几个职责:

1.提供访问保存的加密区域的秘钥
2.生成存储在NameNode上的加密后的数据加密秘钥(EDEK)
3.为HDFS客户端解密EDEK

详细说明


1. 安装KMS

1.1 安装Guardian并整体开启Kerberos
1.2 Guardian中创建keyadmin用户作为KMS秘钥管理员

一般在企业来说,Hadoop平台的管理员可能是HDFS超级用户,但是后端的秘钥存储库可能是另外的DBA管理员,至少要两个人一起联合起来干坏事,才能解密它不该看的数据。这也是为什么KMS默认使用keyadmin用户作为密钥管理员的原因。权限分离来保证数据的最终安全。

1.3 安装KMS组件
1.4 HDFS新增自定义参数

新增如下2个自定义参数,其中ip和port分别为KMS组件的KMS Server IP 和 kms.http.port参数

参数:hadoop.security.key.provider.path
配置文件:core-site.xml
值格式为:code>kms://http@tdh-test1:16000/kms

参数:dfs.encryption.key.provider.uri
配置文件:hdfs-site.xml
值格式为:code>kms://http@tdh-test1:16000/kms

file

1.5 HDFS配置服务并重启

2. inceptor数据开启透明加密

由于inceptor上hdfs的数据都是有hive用户来操作的,所以我们只需要对hive租户添加对加密域的支持即可。

2.1 在KMS配置页面添加以下参数到 kms-acls.xml 中

参数:key.acl.inceptor1-key.READ
配置文件:kms-acls.xml
值为:hive

参数:key.acl.inceptor1-key.DECRYPT_EEK
配置文件:kms-acls.xml
值为:hive

file

2.2 以 keyadmin 身份登录,执行以下命令创建 inceptor 加密秘钥
> hadoop key create inceptor1-key

注意:在创建秘钥时,发现无论是hdfs超级用户还是其他用户都无法创建成功,必须使用我们在安装配置KMS的时候设置的秘钥管理员keyadmin。

KMS参数配置中,hadoop.kms.acl.CREATE,也就是ACL for create-key operations,默认为keyadmin。

2.3 以 hdfs 身份登录,执行以下命令创建加密区
> hadoop fs -mkdir /inceptor1-encrypt
> hadoop fs -chown hive:hive /inceptor1-encrypt
> hdfs crypto -createZone -keyName inceptor1-key -path /inceptor1-encrypt

注意:这里需要使用hdfs超级用户

2.4 停止 inceptor 服务或者确保 inceptor 没有新的数据写入
2.5 以 hive 身份登录,将 Inceptor 数据拷贝到加密区
> hadoop fs -cp -p /inceptor1/* /inceptor1-encrypt
2.6 备份原始数据,并将加密数据目录移动到加密区
> hadoop fs -mv /inceptor1 /inceptor1-bak
> hadoop fs -mv /inceptor1-encrypt /inceptor1
2.7 测试 Inceptor 数据是否完整能访问,确认后删除备份的Inceptor数据 (/inceptor1-bak)

3. 验证方法

3.1 不同用户上传下载操作
## hive租户上传下载,并查看文件,Sucess
[root@tdh-test1~]$ cat test
test is successful !

[root@tdh-test1~]$ kinit hive
Password for hive@TDH:

[root@tdh-test1~]$ hadoop fs -put ./test /inceptor1
2021-01-12 05:49:24,678 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST

[root@tdh-test1~]$ hadoop fs -ls /inceptor1
2021-01-12 05:49:34,656 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
Found 3 items
-rw-r--r--   3 hive hive         21 2021-01-12 05:49 /inceptor1/test
drwxr-xr-x   - hive hive          0 2021-01-12 01:45 /inceptor1/tmp
drwxr-xr-x   - hive hive          0 2021-01-12 01:45 /inceptor1/user

[root@tdh-test1~]$ hadoop fs -get /inceptor1/test ./testout
2021-01-12 06:06:23,277 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST

[root@tdh-test1~]$ ll
总用量 1338628
-rw-r--r--.  1 root root        270 1月  11 02:55 cookies.txt
drwxr-xr-x. 13 root root       4096 1月  11 09:30 TDH-Client
-rw-r--r--.  1 root root 1370736640 1月  11 02:57 tdh-client 1.tar
-rw-r--r--.  1 root root         21 1月  12 05:45 test
-rw-r--r--.  1 root root         21 1月  12 06:06 testout

[root@tdh-test1~]$ cat testout
test is successful !
## guardian新建testuser租户上传下载,Failed(配置testuser租户对目录的admin/access权限)
[root@tdh-test1~]$ kinit testuser
Password for testuser@TDH:

[root@tdh-test1~]$ hadoop fs -put ./test /inceptor1
2021-01-12 05:47:52,578 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
put: User [testuser] is not authorized to perform [DECRYPT_EEK] on key with ACL name [inceptor1-key]!!
2021-01-12 05:47:54,624 ERROR hdfs.DFSClient: Failed to close inode 21360
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.namenode.LeaseExpiredException): No lease on /inceptor1/test._COPYING_ (inode 21360): File does not exist. Holder DFSClient_NONMAPREDUCE_-978982774_1 does not have any open files.
    at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkLease(FSNamesystem.java:3503)
    at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.completeFileInternal(FSNamesystem.java:3580)
    at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.completeFile(FSNamesystem.java:3557)
    at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.complete(NameNodeRpcServer.java:784)
    at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.complete(ClientNamenodeProtocolServerSideTranslatorPB.java:537)
    at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
    at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616)
    at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:969)
    at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2225)
    at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2221)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:415)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:2197)
    at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2219)
    at org.apache.hadoop.ipc.Client.call(Client.java:1485)
    at org.apache.hadoop.ipc.Client.call(Client.java:1422)
    at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:229)
    at com.sun.proxy.$Proxy10.complete(Unknown Source)
    at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.complete(ClientNamenodeProtocolTranslatorPB.java:462)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:191)
    at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:102)
    at com.sun.proxy.$Proxy11.complete(Unknown Source)
    at org.apache.hadoop.hdfs.DFSOutputStream.completeFile(DFSOutputStream.java:2539)
    at org.apache.hadoop.hdfs.DFSOutputStream.closeImpl(DFSOutputStream.java:2516)
    at org.apache.hadoop.hdfs.DFSOutputStream.close(DFSOutputStream.java:2481)
    at org.apache.hadoop.hdfs.DFSClient.closeAllFilesBeingWritten(DFSClient.java:946)
    at org.apache.hadoop.hdfs.DFSClient.closeOutputStreams(DFSClient.java:978)
    at org.apache.hadoop.hdfs.DistributedFileSystem.close(DistributedFileSystem.java:1076)
    at org.apache.hadoop.fs.FileSystem$Cache.closeAll(FileSystem.java:2775)
    at org.apache.hadoop.fs.FileSystem$Cache$ClientFinalizer.run(FileSystem.java:2792)
    at org.apache.hadoop.util.ShutdownHookManager$1.run(ShutdownHookManager.java:54)

[root@tdh-test1~]$ hadoop fs -get /inceptor1/test
2021-01-12 06:10:29,319 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
get: User [testuser] is not authorized to perform [DECRYPT_EEK] on key with ACL name [inceptor1-key]!!
3.2 查看数据文件内容

检查非加密区文件内容:

这里可以选择通过HDFS的50070页面,查看block分布在哪台DataNode上:

file

也可以通过hdfs命令的方式获取:

[root@tdh-test1~]$ hdfs fsck /tmp/test -files -blocks -locations
2021-01-12 05:58:45,860 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
Connecting to namenode via http://tdh-test3:50070/fsck?ugi=hdfs&files=1&blocks=1&locations=1&path=%2Ftmp%2Ftest
FSCK started by hdfs (auth:KERBEROS_SSL) from /172.22.16.18 for path /tmp/test at Tue Jan 12 05:58:47 CST 2021
/tmp/test 21 bytes, 1 block(s):  OK
0. BP-958374365-172.22.16.19-1608257603692:blk_1073745675_4860 len=21 repl=3 [DatanodeInfoWithStorage[172.22.16.20:50010,DS-1d8f9111-d978-4d65-9d8a-f67bed172ca0,DISK], DatanodeInfoWithStorage[172.22.16.18:50010,DS-aade77ae-f970-4835-99e2-59de4b349565,DISK], DatanodeInfoWithStorage[172.22.16.19:50010,DS-add9827c-d1bc-452e-9589-152f9072b016,DISK]]

Status: HEALTHY
Total size:    21 B
Total dirs:    0
Total files:    1
Total symlinks:        0
Total blocks (validated):    1 (avg. block size 21 B)
Minimally replicated blocks:    1 (100.0 %)
Over-replicated blocks:    0 (0.0 %)
Under-replicated blocks:    0 (0.0 %)
Mis-replicated blocks:        0 (0.0 %)
Default replication factor:    3
Average block replication:    3.0
Corrupt blocks:        0
Missing replicas:        0 (0.0 %)
Number of data-nodes:        3
Number of racks:        1
FSCK ended at Tue Jan 12 05:58:47 CST 2021 in 1 milliseconds

The filesystem under path '/tmp/test' is HEALTHY

[root@tdh-test1~]$ find /mnt/disk* -name 'blk_1073745675*'
/mnt/disk2/hadoop/data/current/BP-958374365-172.22.16.19-1608257603692/current/finalized/subdir0/subdir15/blk_1073745675
/mnt/disk2/hadoop/data/current/BP-958374365-172.22.16.19-1608257603692/current/finalized/subdir0/subdir15/blk_1073745675_4860.meta
[root@tdh-test1~]$ cat /mnt/disk2/hadoop/data/current/BP-958374365-172.22.16.19-1608257603692/current/finalized/subdir0/subdir15/blk_1073745675
test is successful !

检查加密区文件内容:

这里可以选择通过HDFS的50070页面,查看block分布在哪台DataNode上:

file

也可以通过hdfs命令的方式获取:

[root@tdh-test1~]$ hdfs fsck /inceptor1/test -files -blocks -locations
2021-01-12 06:01:25,620 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
Connecting to namenode via http://tdh-test3:50070/fsck?ugi=hdfs&files=1&blocks=1&locations=1&path=%2Finceptor1%2Ftest
FSCK started by hdfs (auth:KERBEROS_SSL) from /172.22.16.18 for path /inceptor1/test at Tue Jan 12 06:01:27 CST 2021
/inceptor1/test 21 bytes, 1 block(s):  OK
0. BP-958374365-172.22.16.19-1608257603692:blk_1073745670_4855 len=21 repl=3 [DatanodeInfoWithStorage[172.22.16.18:50010,DS-9f0d79c6-557c-46b4-84d9-c6ad8e038c8d,DISK], DatanodeInfoWithStorage[172.22.16.19:50010,DS-2b035d2f-0569-44fb-968a-d29f073b678f,DISK], DatanodeInfoWithStorage[172.22.16.20:50010,DS-52e720e1-fc4f-4778-a891-92c0a070264e,DISK]]

Status: HEALTHY
Total size:    21 B
Total dirs:    0
Total files:    1
Total symlinks:        0
Total blocks (validated):    1 (avg. block size 21 B)
Minimally replicated blocks:    1 (100.0 %)
Over-replicated blocks:    0 (0.0 %)
Under-replicated blocks:    0 (0.0 %)
Mis-replicated blocks:        0 (0.0 %)
Default replication factor:    3
Average block replication:    3.0
Corrupt blocks:        0
Missing replicas:        0 (0.0 %)
Number of data-nodes:        3
Number of racks:        1
FSCK ended at Tue Jan 12 06:01:27 CST 2021 in 1 milliseconds

The filesystem under path '/inceptor1/test' is HEALTHY

[root@tdh-test1~]$ find /mnt/disk* -name 'blk_1073745670*'
/mnt/disk1/hadoop/data/current/BP-958374365-172.22.16.19-1608257603692/current/finalized/subdir0/subdir15/blk_1073745670
/mnt/disk1/hadoop/data/current/BP-958374365-172.22.16.19-1608257603692/current/finalized/subdir0/subdir15/blk_1073745670_4855.meta
[root@tdh-test1~]$ cat /mnt/disk1/hadoop/data/current/BP-958374365-172.22.16.19-1608257603692/current/finalized/subdir0/subdir15/blk_1073745670
󛁆˿&+¬Ձ    3͢4X
3.2 /.reserved/raw方式查看数据文件内容

为了在使用HDFS加密时启用相同的工作流程,我们引入了一个新的虚拟路径前缀/.reserved/raw/,它允许超级用户直接访问文件系统中的底层块数据。

# 以Superuser用户hdfs登录,查看加密文件和非加密文件
[root@tdh-test1~]$ kinit hdfs
Password for hdfs@TDH:

[root@tdh-test1~]$ hdfs dfs -ls /.reserved/raw
2021-01-12 06:12:52,165 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
Found 7 items
drwx--x--x   - hbase hbase           0 2021-01-10 13:51 /.reserved/raw/hyperbase1
drwxr-xr-x   - hive  hive            0 2021-01-12 06:08 /.reserved/raw/inceptor1
drwx--x--x   - hive  hive            0 2020-12-25 07:46 /.reserved/raw/inceptor1-bak
drwxr-xr-x   - hive  hbase           0 2021-01-12 01:59 /.reserved/raw/inceptor1-encrypt
drwxrwxrwt   - hdfs  hadoop          0 2021-01-12 05:56 /.reserved/raw/tmp
drwxrwxrwt   - hdfs  hadoop          0 2021-01-12 05:53 /.reserved/raw/user
drwxr-xr-x   - hdfs  hbase           0 2020-12-18 10:17 /.reserved/raw/yarn1

[root@tdh-test1~]$ hadoop fs -cat /.reserved/raw/inceptor1/test
2021-01-12 06:13:25,513 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
󛁆˿&+¬Ձ    3͢4X

[root@tdh-test1~]$ hadoop fs -cat /.reserved/raw/tmp/test
2021-01-12 06:14:16,814 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
test is successful !

4. FAQ

4.1 重命名和垃圾桶的考虑

关于trash的话,“Hadoop 2.8.0之前的crypto命令不会自动配置.Trash目录”,目前的版本应该是没有自动配置当前路径trash目录,所以会去找主目录,但是因为权限问题其实是移动不了的,因此可以认为是加密区trash功能暂不支持。

4.2 关闭透明加密

暂时还没看到有提供逆向工程的方法,关闭kms并不会对加密区进行解密的。加密区中的文件会处于加密的状态,只是缺少了kms会取不到密钥来读取。

这篇文章对您有帮助吗?

平均评分 5 / 5. 次数: 1

尚无评价,您可以第一个评哦!

非常抱歉,这篇文章对您没有帮助.

烦请您告诉我们您的建议与意见,以便我们改进,谢谢您。