前言
之前写了许多关于数据迁移的文章,也衍生的介绍了很多HDFS中相关的工具和特性,比如DistCp,ViewFileSystem等等.但是今天本文所要讲的主题转移到了另外一个领域数据安全.数据安全一直是用户非常重视的一点,所以对于数据管理者,务必要做到以下原则:
数据不丢失,不损坏,数据内容不能被非法查阅.
本文所主要描述的方面就是上面原则中最后一点,保证数据不被非法查阅.在HDFS中,就有专门的功能来做这样的事情,Encryption zone,数据加密空间,
Encryption zone综述
HDFS Encryption zone加密空间是一种end-to-end(端到端)的加密模式.其中的加/解密过程对于客户端来说是完全透明的.数据在客户端读操作的时候被解密,当数据被客户端写的时候被加密,所以HDFS本身并不是一个主要的参与者,形象的说,在HDFS中,你看到的只是一堆加密的数据流.
Encryption zone原理介绍
了解HDFS数据加密空间的原理对我们使用Encryption zone有很大的帮助.Encryption zone是HDFS中的一个抽象概念,它表示在此空间的内容在写的时候会被透明的加密,同时在读的时候,被透明的解密.这就是核心所在.具体到细小的细节.
- 1.每个encryption zone 会与每个encryption zone key相关联,而这个key就是会在创建encryption zone的时候同时被指定.
- 2.每个encryption zone中的文件会有其唯一的data encryption key数据加密key,简称就是DEK.
- 3.DEK不会被HDFS直接处理,取而代之的是,HDFS只处理经过加密的DEK, 就是encrypted data encryption key,缩写就是EDEK.
- 4.客户端询问KMS服务去解密EDEK,然后利用解密后得到的DEK去读/写数据.
在第四步骤有一个很重要的过程:
在客户端向KMS服务请求时候,会有相关权限验证,不符合要求的客户端将不会得到解密好的DEK.而且KMS的权限验证是独立于HDFS的,是自身的一套权限验证.
下面是对应的原理展示图:
Key Provider可以理解为是一个key store的保存库,其中KMS是其中的一个实现.
Encryption zone源码实现
这个小节,我们将从源码的层面对上述原理做跟踪分析.这里可以分为2大方向,1个是创建文件,并且写文件数据;2.读文件数据内容.
Encryption zone下的写文件
首先客户端发起createFile请求,到了NameNode这边,会调用startFile方法,里面就会有DEK,EDEK的生成
private HdfsFileStatus startFileInt(final String src,
PermissionStatus permissions, String holder, String clientMachine,
EnumSet<CreateFlag> flag, boolean createParent, short replication,
long blockSize, CryptoProtocolVersion[] supportedVersions,
boolean logRetryCache)
throws IOException {
...
FSDirWriteFileOp.EncryptionKeyInfo ezInfo = null;
// 判断key provider是否为空
if (provider != null) {
readLock();
try {
checkOperation(OperationCategory.READ);
// 不为空,就生成EncryptionKey info.
ezInfo = FSDirWriteFileOp
.getEncryptionKeyInfo(this, pc, src, supportedVersions);
} finally {
readUnlock();
}
// Generate EDEK if necessary while not holding the lock
if (ezInfo != null) {
// 然后根据ezInfo的key名称生成EDEK信息在ezInfo中
ezInfo.edek = FSDirEncryptionZoneOp
.generateEncryptedDataEncryptionKey(dir, ezInfo.ezKeyName);
}
EncryptionFaultInjector.getInstance().startFileAfterGenerateKey();
}
...
try {
// 继续调用startFile方法
stat = FSDirWriteFileOp.startFile(this, pc, src, permissions, holder,
clientMachine, flag, createParent,
replication, blockSize, ezInfo,
toRemoveBlocks, logRetryCache);
...
继续方法的调用
static HdfsFileStatus startFile(