启用 SSL
概述
为了完全支持使用 SSL 的安全通信,我们需要多个 SSL 证书。
- 用于与 HivePlus 内部组件(Metastore、HiveServer2、Ranger)安全通信的自签名 SSL 证书。
- Metastore 的 MySQL 数据库的 SSL 证书
- Ranger 的 MySQL 数据库的 SSL 证书
- 使用加密(启用 Kerberos 的)HDFS 时,Hadoop KMS(密钥管理服务器)的 SSL 证书
对于 MySQL,SSL 证书应由管理员提供。如果 Metastore 和 Ranger 共享一个 MySQL 数据库,则一个 SSL 证书就足够了。对于使用加密 HDFS 的情况,KMS 的 SSL 证书应由管理员提供。
KMS 仅在使用加密 HDFS 时才需要。当使用 S3 进行存储时,我们不需要 KMS。
下面我们将在 Kubernetes 集群中配置 SSL。Kerberos KDC(密钥分发中心)通常是 Hadoop 集群的一部分,但可以位于任何位置。
为了构建启用 SSL 的 Kubernetes 集群,用户需要以下证书文件:

最终,用户将创建多个 KeyStore 文件(用于 Beeline 和 HivePlus 的所有组件),并配置 Ranger 的 MySQL、Metastore 的 MySQL 和 KMS,如下图所示:

这里我们假设没有使用模拟,因此我们不会将 Metastore MySQL 的证书添加到 KMS 的 KeyStore 文件中。
生成自签名证书
第一步是生成用于 SSL 的自签名证书。我们使用脚本generate-hivemr3-ssl.sh来生成自签名证书。在执行之前,用户应更新config-run.sh。
- 通过将
ENABLE_SSL和ENABLE_SSL_RANGER设置为 true 来启用 SSL。 - 指定私钥 KeyStore 文件(
mr3-ssl.jks)。 - 指定 KeyStore 的凭据文件(
mr3-ssl.jceks)。 - 为 HiveServer2 服务(其 IP 地址在
yaml/hiveserver2-service.yaml中设置)、Ranger 服务(其 IP 地址在yaml/ranger-service.yaml中设置)、Metastore Pod、KMS 和可选的 MySQL 数据库指定主机名。
vi config-run.sh
ENABLE_SSL=true
ENABLE_SSL_RANGER=true
MR3_SSL_KEYSTORE=/home/hive/mr3/kubernetes/mr3-ssl.jks
MR3_SSL_CREDENTIAL_PROVIDER=/home/hive/mr3/kubernetes/mr3-ssl.jceks
MR3_SSL_CREDENTIAL_PROVIDER_CHECKSUM=/home/hive/mr3/kubernetes/.mr3-ssl.jceks.crc
HIVE_SERVER2_HOST=indigo20
ATS_HOST=indigo20
RANGER_HOST=indigo20
HIVE_METASTORE_HOST=hivemr3-metastore-0.metastore.hivemr3.svc.cluster.local
KMS_HOST=red0
MYSQL_HOST=red0
需要注意的是,Metastore Pod 的主机名在中间包含命名空间(hivemr3)(而不是在其前缀中)。
MR3_SSL_KEYSTORE、MR3_SSL_CREDENTIAL_PROVIDER和MR3_SSL_CREDENTIAL_PROVIDER_CHECKSUM必须使用完整路径。
在执行脚本generate-hivemr3-ssl.sh之前,请在函数generate_keystore中更改私钥 KeyStore 文件的 Common Name,使其与env.sh中HIVE_SERVER2_KERBEROS_PRINCIPAL指定的服务主体中的主机名匹配。例如,如果HIVE_SERVER2_KERBEROS_PRINCIPAL设置为root/mr3@PL,则 Common Name 应设置为mr3。
vi generate-hivemr3-ssl.sh
function generate_keystore {
echo -e "\n# Generating a keystore ($MR3_SSL_KEYSTORE) #" >&2
keytool -genkeypair -alias ssl-private-key -keyalg RSA -dname "CN=mr3" -keypass $PASSWORD -ext san=$SUBJECT_ALTERNATIVE_NAME -validity $VALID_DAYS -storetype jks -keystore $MR3_SSL_KEYSTORE -storepass $PASSWORD
此步骤是使用 Python 客户端连接启用 SSL 的 HiveServer2 所必需的。
执行脚本generate-hivemr3-ssl.sh生成私钥 KeyStore 文件和凭据文件。
$ ./generate-hivemr3-ssl.sh
Generated keystore password: 4b41c3e6-7614-4d92-8a4b-d38b1a58831d
...
# Generating a keystore (/home/hive/mr3/kubernetes/mr3-ssl.jks) #
...
# Generating a credential file (/home/gla/mr3-run/kubernetes/mr3-ssl.jceks) #
...
现在用户可以列出三个新文件。
ls mr3-ssl.* .mr3-ssl.jceks.crc
.mr3-ssl.jceks.crc mr3-ssl.jceks mr3-ssl.jks
脚本打印出新 KeyStore 文件的唯一密码(上面的示例中为4b41c3e6-7614-4d92-8a4b-d38b1a58831d)。用户应在以下文件中将该密码设置为一些变量。
-
用于生成 TrustStore 文件的
config-run.shvi config-run.shMR3_SSL_KEYSTORE_PASSWORD=4b41c3e6-7614-4d92-8a4b-d38b1a58831d -
用于 HiveServer2 的
env.shvi env.shHIVE_SERVER2_SSL_TRUSTSTOREPASS=4b41c3e6-7614-4d92-8a4b-d38b1a58831dexport HADOOP_CREDSTORE_PASSWORD=4b41c3e6-7614-4d92-8a4b-d38b1a58831d此外,将
HADOOP_CREDSTORE_PASSWORD附加到conf/mr3-site.xml中配置键mr3.am.launch.env和mr3.container.launch.env的值中。需要注意的是,出于安全目的,**用户不应写入密码本身。**仅附加字符串就足够了,因为 MR3 会通过从系统环境读取来自动设置环境变量。vi conf/mr3-site.xml<property><name>mr3.am.launch.env</name><value>LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/mr3-run/hadoop/apache-hadoop/lib/native,HADOOP_CREDSTORE_PASSWORD,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION</value></property><property><name>mr3.container.launch.env</name><value>LD_LIBRARY_PATH=/opt/mr3-run/hadoop/apache-hadoop/lib/native,HADOOP_CREDSTORE_PASSWORD,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION</value></property> -
用于 Ranger 的
ranger-key/install.propertiesvi ranger-key/install.propertiesjavax_net_ssl_keyStorePassword=4b41c3e6-7614-4d92-8a4b-d38b1a58831djavax_net_ssl_trustStorePassword=4b41c3e6-7614-4d92-8a4b-d38b1a58831d -
用于 Ranger 的
ranger-key/solr.in.shvi ranger-key/solr.in.shSOLR_SSL_KEY_STORE_PASSWORD=4b41c3e6-7614-4d92-8a4b-d38b1a58831dSOLR_SSL_TRUST_STORE_PASSWORD=4b41c3e6-7614-4d92-8a4b-d38b1a58831d
最后,使用私钥 KeyStore 文件mr3-ssl.jks和generate-hivemr3-ssl.sh生成的密码创建新的证书文件mr3-ssl.pem,该文件可以安全地分发到所有其他组件。
keytool -export -keystore mr3-ssl.jks -alias ssl-private-key -file mr3-ssl.cert -storepass 4b41c3e6-7614-4d92-8a4b-d38b1a58831d
Certificate stored in file <mr3-ssl.cert>
...
openssl x509 -inform der -in mr3-ssl.cert -out mr3-ssl.pem
使用 SSL 的 Ranger

Ranger 不支持默认认证的 SSL。
使用 SSL 运行 Ranger 有以下先决条件。
-
带有 SSL 的 MySQL 数据库。MySQL 数据库应与
env.sh中HIVE_MYSQL_DRIVER指定的 MySQL 连接器 jar 文件兼容。为了测试目的,用户可以快速创建这样的 MySQL 数据库(自动启用 SSL):docker run -d --name mysql-server -p 3306:3306 -e MYSQL_ROOT_PASSWORD=passwd mysql:5.7 -
用于连接 MySQL 数据库的证书文件。证书文件通常是 MySQL 运行节点上的
/var/lib/mysql/ca.pem或/var/lib/mysql/ssl/ca.pem。 -
用户应该能够编辑 MySQL 的证书文件并重启 MySQL。
用于 SSL 的证书
用户应复制用于连接 Ranger 的 MySQL 数据库的证书文件,并在config-run.sh中将MR3_RANGER_MYSQL_CERTIFICATE设置为指向该副本。
vi config-run.sh
MR3_RANGER_MYSQL_CERTIFICATE=/home/hive/mr3/kubernetes/mr3-ranger-mysql.cert

现在 Ranger 已准备好安全地连接到 MySQL 数据库。
然后用户应扩展 MySQL(运行 MySQL 的节点上)的证书文件,以便 MySQL 可以信任 Ranger 的自签名证书。将mr3-ssl.pem的内容追加到 MySQL 的证书文件中(运行 MySQL 的节点上)。
cat >> /var/lib/mysql/ca.pem
-----BEGIN CERTIFICATE-----
MIIC4DCCAcigAwIBAgIEApwQbTANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwto...
tO1G8uO6bz/AOExeN3nrxMpuTzw=
-----END CERTIFICATE-----
通常,仅在双向认证时才需要追加mr3-ssl.pem的内容,但根据 MySQL 的版本,即使对于单向认证也可能需要。
用于 SSL 的配置
配置 Ranger 使用 SSL 需要用户编辑多个文件。新配置涉及:1)启用 SSL;2)指定密码;3)指定 HTTPS 地址。
在ranger-key/install.properties中,启用 SSL。db_ssl_auth_type可以设置为1-way以使用单向认证。audit_solr_urls应设置为 Solr 的 HTTPS 地址,policymgr_external_url应设置为 Ranger 的 HTTPS 地址。
vi ranger-key/install.properties
db_ssl_enabled=true
db_ssl_required=true
db_ssl_verifyServerCertificate=true
db_ssl_auth_type=2-way
audit_solr_urls=https://indigo20:6083/solr/ranger_audits
policymgr_external_url=https://indigo20:6182
policymgr_http_enabled=false
在ranger-key/solr.in.sh中,为 Solr 启用 SSL。
vi ranger-key/solr.in.sh
SOLR_SSL_ENABLED=true
SOLR_SSL_KEY_STORE=/opt/mr3-run/ranger/key/hivemr3-ssl-certificate.jks
SOLR_SSL_TRUST_STORE=/opt/mr3-run/ranger/key/hivemr3-ssl-certificate.jks
SOLR_SSL_NEED_CLIENT_AUTH=false
SOLR_SSL_WANT_CLIENT_AUTH=false
SOLR_SSL_CHECK_PEER_NAME=true
SOLR_SSL_KEY_STORE_TYPE=JKS
SOLR_SSL_TRUST_STORE_TYPE=JKS
由于 Ranger 现在使用 SSL,HiveServer2 也应该重新配置以便与 Ranger 安全通信。在conf/ranger-hive-security.xml中,指定 Ranger 的 HTTPS 地址。
vi conf/ranger-hive-security.xml
<property>
<name>ranger.plugin.hive.policy.rest.url</name>
<value>https://indigo20:6182</value>
</property>
在conf/ranger-hive-audit.xml中,指定 Solr 的 HTTPS 地址。
vi kubernetes/conf/ranger-hive-audit.xml
<property>
<name>xasecure.audit.destination.solr.urls</name>
<value>https://indigo20:6083/solr/ranger_audits</value>
</property>
使用 SSL 的 Metastore

在conf/core-site.xml中,应指定持有私钥的 KeyStore 文件。
vi conf/core-site.xml
<property>
<name>hadoop.security.credential.provider.path</name>
<value>localjceks://file/opt/mr3-run/key/hivemr3-ssl-certificate.jceks</value>
</property>
用户应复制用于连接 Metastore 的 MySQL 数据库的证书文件,并在config-run.sh中将MR3_METASTORE_MYSQL_CERTIFICATE设置为指向该副本。
vi config-run.sh
MR3_METASTORE_MYSQL_CERTIFICATE=/home/hive/mr3/kubernetes/mr3-metastore-mysql.cert

与 Ranger 类似,用户应扩展 MySQL 的证书文件,以便 MySQL 可以信任 Metastore 的自签名证书。将上一步创建的mr3-ssl.pem的内容追加到 MySQL 的证书文件中。如果 Ranger 和 Metastore 共享同一个 MySQL 数据库,则此步骤不必要。
在conf/hive-site.xml中,用户指定用于连接 MySQL 数据库的 URL(通过追加;useSSL=true&verifyServerCertificate=true)并启用 SSL。自签名证书的 KeyStore 文件已经指定。
vi conf/hive-site.xml
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://${hive.database.host}/${hive.database.name}?createDatabaseIfNotExist=true&useSSL=true&verifyServerCertificate=true</value>
</property>
<property>
<name>hive.metastore.use.SSL</name>
<value>true</value>
</property>
<property>
<name>hive.metastore.keystore.path</name>
<value>/opt/mr3-run/key/hivemr3-ssl-certificate.jks</value>
</property>
<property>
<name>hive.metastore.truststore.path</name>
<value>/opt/mr3-run/key/hivemr3-ssl-certificate.jks</value>
</property>
由于我们构建的 Kubernetes 集群中只有 Beeline(和 JDBC 客户端)可以连接到 HiveServer2,普通用户不能直接访问数据源,因此可以禁用 Metastore 端的安全性,仅依赖 Ranger 来保护 HiveServer2。用户可以通过取消设置conf/hive-site.xml中的两个配置键hive.metastore.pre.event.listeners和metastore.pre.event.listeners来禁用 Metastore 端的安全性。
vi conf/hive-site.xml
<property>
<name>hive.metastore.pre.event.listeners</name>
<value></value>
</property>
<property>
<name>metastore.pre.event.listeners</name>
<value></value>
</property>
然后配置键hive.security.metastore.authorization.manager会自动被忽略。
需要注意的是,conf/hive-site.xml中hive.metastore.uris指定的 Thrift Metastore URI 不会暴露在 Kubernetes 集群外部,因为env.sh中的HIVE_METASTORE_HOST使用 Metastore Pod 的主机名。如果出于某些原因需要将 Thrift Metastore URI 暴露给外部(引入 Kubernetes Service 后),我们也应在 Metastore 端启用安全性。
如果 Thrift Metastore URI 被暴露给外部,可以利用HIVE-21753使用相同的 Ranger 实例作为 Metastore 的授权管理器。
用户可以通过更新kubernetes/mr3-ssl.jceks来隐藏连接 MySQL 的密码。以下是当密码为passwd时更新kubernetes/mr3-ssl.jceks的示例。
hadoop credential create javax.jdo.option.ConnectionPassword -provider jceks://file//home/hive/mr3/kubernetes/mr3-ssl.jceks -value passwd
javax.jdo.option.ConnectionPassword has been successfully created
org.apache.hadoop.security.alias.JavaKeyStoreProvider has been updated.
$ keytool -list -storetype jceks -storepass none -keystore kubernetes/mr3-ssl.jceks
Keystore type: JCEKS
Keystore provider: SunJCE...
现在conf/hive-site.xml中的配置键javax.jdo.option.ConnectionPassword可以设置为_。
vi conf/hive-site.xml
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>_</value>
</property>
使用 SSL 的 HiveServer2

在conf/core-site.xml中,应指定持有私钥的 KeyStore 文件。
vi conf/core-site.xml
<property>
<name>hadoop.security.credential.provider.path</name>
<value>localjceks://file/opt/mr3-run/key/hivemr3-ssl-certificate.jceks</value>
</property>
在conf/hive-site.xml中,用户启用 SSL。自签名证书的 KeyStore 文件已经指定。
vi conf/hive-site.xml
<property>
<name>hive.server2.use.SSL</name>
<value>true</value>
</property>
<property>
<name>hive.server2.keystore.path</name>
<value>/opt/mr3-run/key/hivemr3-ssl-certificate.jks</value>
</property>
<property>
<name>hive.server2.keystore.password</name>
<value>_</value>
</property>
为了使 HiveServer2 与 KMS 安全通信,用户应复制用于连接 KMS 的证书文件,并在config-run.sh中将MR3_KMS_CERTIFICATE设置为指向该副本。
vi config-run.sh
MR3_KMS_CERTIFICATE=/home/hive/mr3/kubernetes/mr3-kms.cert
在yaml/hive.yaml中,spec.hostAliases字段应包含运行 KMS 的主机。
vi yaml/hive.yaml
spec:
template:
spec:
hostAliases:
- ip: "10.1.91.4"
hostnames:
- "red0"
在conf/core-site.xml中,用户指定带 SSL 的 KMS 地址。
vi conf/core-site.xml
<property>
<name>dfs.encryption.key.provider.uri</name>
<value>kms://https@red0:9393/kms</value>
</property>