越来越多的用户关注安全问题,都在寻找一种有效的,方便的加密方式。hadoop提供了几种不同形式的加密,最底层的加密,加密所有节点数据,有效地保护了数据,但是却缺乏更细粒度的加密;
kms 透明加密可以做到更细粒度的加密;
加密可以在不同的层级进行,包括软件/软件堆栈,选择不同的加密层级各有优缺点
体系结构
简单使用场景:
前提场景:
人物:管理员s、用户a、用户b、外部无权人c
没有透明加密的时候:
正常情况下,通过hdfs客户端,a只能查看A里的文件;b只能查看B的文件。
但a(或者c)如果通过某种方式,进入hdfs的数据块存储区域,直接把B文件的数据块取出来,那么B文件就泄密了
有透明加密的时候:
管理员用密钥1把A目录设为“加密区”,用密钥2把B目录也设为“加密区”
当a获取了B文件的数据块,由于他他没有A文件的使用权限,kms不会返回给他密钥2。
当c获取了B文件的数据块,由于他也没有A文件的使用权,kms也不会返回给他密钥2。
此时就保证了文件B的安全。
注:加密的是数据块,就是存在磁盘上的东西,在hdfs上直接看是自动解密了,加密的要直接取数据块看。
hadoo-2.10.1集群:节点:node1 node2 node3
配置KMS:由于kms是跟hadoop结合在一起的,故可以直接到hadoop安装目录下的etc/hadoop去配置kms的配置文件,kms-site.xml, kms-env.sh,kms-acls.xml
用默认配置即可,但是要知道每一项的含义,后面方便去做对应的事情.
hadoop.kms.key.provider.uri
可以直接理解成我们生成 key 后存储到的文件位置。后面我们会根据 java 秘钥生成器 keytool -genkey 去生成一个 key.hadoop.security.keystore.java-keystore-provider.password-file
上面那个文件生成的时候,需要指定一个密码,而这个密码,需要 kms 从一个文件中读取。那么这个文件的路径就是这个属性的 value.hadoop.kms.cache.enable
hadoop.kms.cache.timeout.ms
hadoop.kms.current.key.cache.timeout.ms
<property>
<name>hadoop.kms.key.provider.uriname>
<value>jceks://file@/${user.home}/kms.keystorevalue>
<description>
URI of the backing KeyProvider for the KMS.
description>
property>
<property>
<name>hadoop.security.keystore.java-keystore-provider.password-filename>
<value>kms.keystore.passwordvalue>
<description>
If using the JavaKeyStoreProvider, the file name for the keystore password.
description>
property>
<property>
<name>hadoop.kms.cache.enablename>
<value>truevalue>
<description>
Whether the KMS will act as a cache for the backing KeyProvider.
When the cache is enabled, operations like getKeyVersion, getMetadata,
and getCurrentKey will sometimes return cached data without consulting
the backing KeyProvider. Cached values are flushed when keys are deleted
or modified.
description>
property>
<property>
<name>hadoop.kms.cache.timeout.msname>
<value>600000value>
<description>
Expiry time for the KMS key version and key metadata cache, in
milliseconds. This affects getKeyVersion and getMetadata.
description>
property>
<property>
<name>hadoop.kms.current.key.cache.timeout.msname>
<value>30000value>
<description>
Expiry time for the KMS current key cache, in milliseconds. This
affects getCurrentKey operations.
description>
property>
(py38_1.12) lzq@node1 ~ keytool -genkey -alias 'key1';
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
[Unknown]: zhiqiang li
您的组织单位名称是什么?
[Unknown]: xxx
您的组织名称是什么?
[Unknown]: xxx
您所在的城市或区域名称是什么?
[Unknown]: hangzhou
您所在的省/市/自治区名称是什么?
[Unknown]: zhejiang
该单位的双字母国家/地区代码是什么?
[Unknown]: china
CN=zhiqiang li, OU=xxx, O=xxx, L=hangzhou, ST=zhejiang, C=china是否正确?
[否]: yes
您的名字与姓氏是什么?
[zhiqiang li]: zhiqiang li
您的组织单位名称是什么?
[xxx]: xxx
您的组织名称是什么?
[xxx]: xxx
您所在的城市或区域名称是什么?
[hangzhou]: hangzhou
您所在的省/市/自治区名称是什么?
[zhejiang]: zhejiang
该单位的双字母国家/地区代码是什么?
[china]: china
CN=zhiqiang li, OU=xxx, O=xxx, L=hangzhou, ST=zhejiang, C=china是否正确?
[否]: 是
输入 <key1> 的密钥口令
(如果和密钥库口令相同, 按回车):
再次输入新口令:
Warning:
JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore /home/lzq/.keystore -destkeystore /home/lzq/.keystore -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。
密码默认位置是在你的家目录下,默认名为.keystore,为隐藏文件,建议使用默认的方式创建密钥.
注:有两个密码需要设定,这里我都设置为了123456,首先输入第一个密码,其他的随意写,直到出现no的时候写yes,然后输入第二个密码。
注:密码默认位置是在你的家目录下,默认名为.keystore,为隐藏文件,建议使用默认的方式创建密钥。
注:其他方式创建密钥:(指定kms密钥文件名和位置)
keytool-genkey -alias ‘kmskey’ -keystore /kms.jks -dname “CN=localhost,OU=localhost, O=localhost, L=SH, ST=SH, C=CN” -keypass 123456 -storepass123456 -validity 180
注: 生成了keystore后,这个keystore就可以作为kms的密钥存储数据库了,由于这个keystore有访问密码(比如上面所设置的storepass :123456),这个密码是要告诉kms的,否则kms访问不了这个keystore,kms通过读取一个文本文件来获取密码。所以我们需要创建一个文本文件,在里面写上keystore访问密码。
上面
输入密钥库口令:
再次输入新口令:
这两个输入的密码 是 123456 。 放入到一个文件里面 kms.keystore.password
然后把文件放到 kms 服务的 classes 目录下面
这个文件名和上面 kms-site.xml 里面的 hadoop.security.keystore.java-keystore-provider.password-file
的 value 相对应.
# $HADOOP_HOME 需要提前搭建 hadoop 集群的时候就配置好
export KMS_HOME=$HADOOP_HOME
export KMS_LOG=${KMS_HOME}/logs/kms
export KMS_HTTP_PORT=16000
export KMS_ADMIN_PORT=16001
kms.sh start
# 如果没配置环境变量,需要去 Hadoop home 里面 sbin 下面的脚本去启动。
node1 ip 是 192.168.178.101, 也可以配置成 kms://http@node116000/kms
<property>
<name>hadoop.security.key.provider.pathname>
<value>kms://[email protected]:16000/kmsvalue>
property>
<property>
<name>dfs.encryption.key.provider.uriname>
<value>kms://[email protected]:16000/kmsvalue>
property>
hadoop key create key1
创建之后查看一下
hadoop key list
创建一个加密分区
hdfs dfs -mkdir /crypto
hdfs crypto -createZone -keyName key1 -path /crypto
如果报错 RemoteException: Can’t create an encryption zone for /crypto since no key provider is available.
那么是因为可能你没配置对下面的属性,它在 core-site.xml
<property>
<name>hadoop.security.key.provider.pathname>
<value>kms://http@node1:16000/kmsvalue>
property>
然后重启一下 HDFS 就可以了。
我是因为我命名配置了这个属性,但是重启还是不行。 后来源码 debug 到报错的地方,突然又好了。 后面也不再出问题了。
很奇怪。就是一直报错 since no key provider is available
源码在下面
上面异常 110 行的异常就是命令行的报错。
provider 的创建就是这个代码
private static String keyProviderUriKeyName =
CommonConfigurationKeysPublic.HADOOP_SECURITY_KEY_PROVIDER_PATH;
public static final String HADOOP_SECURITY_KEY_PROVIDER_PATH =
"hadoop.security.key.provider.path";
上面的 keyProviderUriKeyName 其实就是我们配置的 hadoop.security.key.provider.path 属性。
一个文件上传到 HDFS 上两个不同文件夹,一个加密 /crypto, 一个不假面 /no_crypto 。
通过命令找到 datanode 上面的文件块,
hdfs fsck /crypto/crypto.txt -files -blocks -locations
hdfs fsck /no_crypto/crypto.txt -files -blocks -locations
我们可以看到, 加密区域的文件无法查看,不加密区域的文件直接用 linux cat 命令就可以看到内容。
直接通过命令查看文件内容
hdfs dfs -ls /.reserved/raw
hdfs dfs -cat /.reserved/raw/crypto/crypto.txt
hdfs dfs -cat /.reserved/raw/no_crypto/crypto.txt