HDFS 透明加密使用、Keystore和Hadoop KMS、加密区域
HDFS中的数据会以block的形式保存在各台数据节点的本地磁盘中,但这些block都是明文的,如果在操作系统下,直接访问block所在的目录,通过Linux的cat命令是可以直接查看里面的内容的,而且是明文。
下面我们直接去DataNode本地存储block的目录,直接查看block内容:
/export/data/hadoop-3.1.4/dfs/data/current/BP-1748151750-192.168.227.1511608259905540/current/finalized/subdir0/subdir0/
1.2 背景和应用
1.2.1 常见的加密层级
- Ø 应用层加密
这是最安全也是最灵活的方式。加密内容最终由应用程序来控制,并且可以精确的反映用户的需求。但是,编写应用程序来实现加密一般都比较困难。 - Ø 数据库层加密
类似于应用程序加密。大多数数据库厂商都提供某种形式的加密,但是可能会有性能问题,另外比如说索引没办法加密。 - Ø 文件系统层加密
这种方式对性能影响不大,而且对应用程序是透明的,一般也比较容易实施。但是应用程序细粒度的要求策略,可能无法完全满足。 - Ø 磁盘层加密
易于部署和高性能,但是相当不灵活,只能防止用户从物理层面盗窃数据。
HDFS的透明加密属于数据库层和文件系统层的加密。拥有不错的性能,且对于现有的应用程序是透明的。HDFS加密可以防止在文件系统或之下的攻击,也叫操作系统级别的攻击(OS-level attacks)。操作系统和磁盘只能与加密的数据进行交互,因为数据已经被HDFS加密了。
1.2.2 应用场景
数据加密对于全球许多政府,金融和监管机构都是强制性的,以满足隐私和其他安全要求。例如,卡支付行业已采用“支付卡行业数据安全标准”(PCI DSS)来提高信息安全性。其他示例包括美国政府的《联邦信息安全管理法案》(FISMA)和《健康保险可移植性和责任法案》(HIPAA)提出的要求。加密存储在HDFS中的数据可以帮助您的组织遵守此类规定。
1.3 透明加密介绍
HDFS透明加密(Transparent Encryption)支持端到端的透明加密,启用以后,对于一些需要加密的HDFS目录里的文件可以实现透明的加密和解密,而不需要修改用户的业务代码。端到端是指加密和解密只能通过客户端。对于加密区域里的文件,HDFS保存的即是加密后的文件,文件加密的秘钥也是加密的。让非法用户即使从操作系统层面拷走文件,也是密文,没法查看。
HDFS透明加密具有以下功能特点:
- 只有HDFS客户端可以加密或解密数据。
- 密钥管理在HDFS外部。HDFS无法访问未加密的数据或加密密钥。HDFS的管理和密钥的管理是独立的职责,由不同的用户角色(HDFS管理员,密钥管理员)承担,从而确保没有单个用户可以不受限制地访问数据和密钥。
- 操作系统和HDFS仅使用加密的HDFS数据进行交互,从而减轻了操作系统和文件系统级别的威胁。
- HDFS使用高级加密标准计数器模式(AES-CTR)加密算法。AES-CTR支持128位加密密钥(默认),或者在安装Java Cryptography Extension(JCE)无限强度JCE时支持256位加密密钥。
1.4 透明加密关键概念和架构
1.4.1 加密区域和密钥
HDFS的透明加密有一个新的概念,加密区域(the encryption zone)。加密区域是一个特殊的目录,写入文件的时候会被透明加密,读取文件的时候又会被透明解密。
当加密区域被创建时,都会有一个加密区域秘钥(EZ密钥,encryption zone key)与之对应,EZ密钥存储在HDFS外部的备份密钥库中。加密区域里的每个文件都有其自己加密密钥,叫做数据加密秘钥(DEK,data encryption key)。DEK会使用其各自的加密区域的EZ密钥进行加密,以形成加密数据加密密钥(EDEK)HDFS不会直接处理DEK,HDFS只会处理EDEK。客户端会解密EDEK,然后用后续的DEK来读取和写入数据。
关于EZ密钥、DEK、EDEK三者关系如下所示:
1.4.2 Keystore和Hadoop KMS
存储密钥(key)的叫做密钥库(keystore),将HDFS与外部企业级密钥库(keystore)集成是部署透明加密的第一步。这是因为密钥(key)管理员和HDFS管理员之间的职责分离是此功能的非常重要的方面。但是,大多数密钥库都不是为Hadoop工作负载所见的加密/解密请求速率而设计的。
为此,Hadoop进行了一项新服务的开发,该服务称为Hadoop密钥管理服务器(Key Management Server,简写KMS),该服务用作HDFS客户端与密钥库之间的代理。密钥库和Hadoop KMS相互之间以及与HDFS客户端之间都必须使用Hadoop的KeyProvider API进行交互。
KMS主要有以下几个职责:
1.提供访问保存的加密区域秘钥(EZ key)
2.生成EDEK,EDEK存储在NameNode上
3.为HDFS客户端解密EDEK
1.4.3 访问加密区域内的文件
1.4.3.1 写入加密文件过程
前提:创建HDFS加密区时会创建一个HDFS加密区(目录),同时会在KMS服务里创建一个key及其EZ Key,及两者之间的关联。
1.Client向NN请求在HDFS某个加密区新建文件;
2.NN向KMS请求此文件的EDEK,KMS用对应的EZ key生成一个新的EDEK发送给NN;
3.这个EDEK会被NN写入到文件的metadata中;
4.NN发送EDEK给Client;
5.Client发送EDEK给KMS请求解密,KMS用对应的EZ key将EDEK解密为DEK发送给Client;
6.Client用DEK加密文件内容发送给datanode进行存储。
DEK是加解密一个文件的密匙,而KMS里存储的EZ key是用来加解密所有文件的密匙(DEK)的密匙。**所以,EZ Key是更为重要的数据,只在KMS内部使用(DEK的加解密只在KMS内存进行),不会被传递到外面使用,而HDFS服务端只能接触到EDEK,所以HDFS服务端也不能解密加密区文件。
1.4.3.2 读取解密文件过程
读流程与写流程类型,区别就是NN直接读取加密文件元数据里的EDEK返回给客户端,客户端一样把EDEK发送给KMS获取DEK。再对加密内容解密读取。
EDEK的加密和解密完全在KMS上进行。更重要的是,请求创建或解密EDEK的客户端永远不会处理EZ密钥。仅KMS可以根据要求使用EZ密钥创建和解密EDEK。
1.5 KMS配置
1.5.1 关闭HDFS集群
在node1上执行stop-dfs.sh。
1.5.2 key密钥生成
[root@node1 ~]# keytool -genkey -alias 'yida'
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]:
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]:
What is the name of your City or Locality?
[Unknown]:
What is the name of your State or Province?
[Unknown]:
What is the two-letter country code for this unit?
[Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: yes
Enter key password for <yida>
(RETURN if same as keystore password):
Re-enter new password:
1.5.3 配置kms-site.xml
配置文件路径:/export/server/hadoop-3.1.4/etc/hadoop/kms-site.xml
<configuration>
<property>
<name>hadoop.kms.key.provider.uri</name>
<value>jceks://file@/${user.home}/kms.jks</value>
</property>
<property>
<name>hadoop.security.keystore.java-keystore-provider.password-file</name>
<value>kms.keystore.password</value>
</property>
<property>
<name>dfs.encryption.key.provider.uri</name>
<value>kms://http@node1:16000/kms</value>
</property>
<property>
<name>hadoop.kms.authentication.type</name>
<value>simple</value>
</property>
</configuration>
密码文件通过类路径在Hadoop的配置目录中查找。
1.5.4 kms-env.sh
export KMS_HOME=/export/server/hadoop-3.1.4
export KMS_LOG=${KMS_HOME}/logs/kms
export KMS_HTTP_PORT=16000
export KMS_ADMIN_PORT=16001
1.5.5 修改core|hdfs-site.xml
core-site.xml
<property>
<name>hadoop.security.key.provider.path</name>
<value>kms://http@node1:16000/kms</value>
</property>
hdfs-site.xml
<property>
<name>dfs.encryption.key.provider.uri</name>
<value>kms://http@node1:16000/kms</value>
</property>
同步配置文件到其他节点
1.5.5.1 KMS服务启动
hadoop --daemon start kms
1.5.5.2 HDFS集群启动
start-dfs.sh
1.6 透明加密使用
1.6.1 创建key
切换成普通用户allenwoon操作
# su allenwoon # hadoop key create yida # hadoop key list -metadata
1.6.2 创建加密区
使用root超级用户操作
#作为超级用户,创建一个新的空目录,并将其设置为加密区域
hadoop fs -mkdir /zone
hdfs crypto -createZone -keyName itcast -path /zone
#将其chown给普通用户
hadoop fs -chown allenwoon:allenwoon /zone
1.6.3 测试加密效果
以普通用户操作
#以普通用户的身份放入文件,然后读出来
echo helloitcast >> helloWorld
hadoop fs -put helloWorld /zone
hadoop fs -cat /zone /helloWorld
#作为普通用户,从文件获取加密信息
hdfs crypto -getFileEncryptionInfo -path /zone/helloWorld
`
1.6.3 测试加密效果
以普通用户操作
#以普通用户的身份放入文件,然后读出来
echo helloitcast >> helloWorld
hadoop fs -put helloWorld /zone
hadoop fs -cat /zone /helloWorld
#作为普通用户,从文件获取加密信息
hdfs crypto -getFileEncryptionInfo -path /zone/helloWorld
直接下载文件的block 发现是无法读取数据的。