加密群集工作器节点之间的流量

重要

本文中引用的示例 init 脚本从存储在 DBFS 中的密钥库的哈希中派生其共享加密密钥。 如果你通过更新 DBFS 中的密钥库文件来轮换密钥,则必须重新启动所有正在运行的群集。 否则,Spark 工作线程可能会由于共享密钥不一致而无法通过 Spark 驱动程序进行身份验证,从而导致作业速度变慢。 此外,由于共享机密存储在 DBFS 中,任何具有 DBFS 访问权限的用户都可以使用笔记本检索该机密。

要求

  • 此功能需要高级计划。 有关详细信息,请联系 Databricks 帐户团队。

init 脚本的工作原理

重要

本文中引用的示例 init 脚本从存储在 DBFS 中的密钥库的哈希中派生其共享加密密钥。 如果你通过更新 DBFS 中的密钥库文件来轮换密钥,则必须重新启动所有正在运行的群集。 否则,Spark 工作线程可能会由于共享密钥不一致而无法通过 Spark 驱动程序进行身份验证,从而导致作业速度变慢。 此外,由于共享机密存储在 DBFS 中,任何具有 DBFS 访问权限的用户都可以使用笔记本检索该机密。

用户查询和转换通常会通过加密通道发送到群集。 但是,在默认情况下,群集中工作器节点之间交换的数据是未加密的。 如果你的环境要求始终对数据进行加密,无论是静态加密还是传输中加密,都可以创建一个初始化脚本,该脚本将群集配置为通过 TLS 1.3 连接使用 AES 256 位加密来加密工作器节点之间的流量。

注意

尽管 AES 使加密例程能够利用硬件加速,但是与未加密的流量相比,仍然存在性能损失。 这种损失可能导致已加密群集上的查询花费更长的时间,具体取决于节点之间随机传输的数据量。

对工作器节点之间流量启用加密需要通过 init 脚本来设置 Spark 配置参数。 如果希望工作区中的所有群集都使用工作器到工作器加密,可以将群集范围内的 init 脚本用于单个群集,或者将群集范围内的 init 脚本添加到你的群集策略。

将密钥存储文件一次性复制到 DBFS 中的目录。 然后创建应用加密设置的 init 脚本。

Init 脚本必须执行以下任务:

  1. 获取 JKS 密钥存储文件和密码。
  2. 设置 Spark 执行程序配置。
  3. 设置 Spark 驱动程序配置。

注意

将为每个工作区动态生成用于启用 SSL/HTTPS 的 JKS 密钥存储文件。 该 JKS 密钥存储文件的密码采用硬编码,并且不是用来保护密钥存储的机密性的。

下面是一个示例 init 脚本,它实现这三个任务以生成群集加密配置。

示例 init 脚本

#!/bin/bash

set -euo pipefail

keystore_dbfs_file="/dbfs/<keystore-directory>/jetty_ssl_driver_keystore.jks"

## Wait till keystore file is available via Fuse

max_attempts=30
while [ ! -f ${keystore_dbfs_file} ];
do
  if [ "$max_attempts" == 0 ]; then
    echo "ERROR: Unable to find the file : $keystore_dbfs_file .Failing the script."
    exit 1
  fi
  sleep 2s
  ((max_attempts--))
done
## Derive shared internode encryption secret from the hash of the keystore file
sasl_secret=$(sha256sum $keystore_dbfs_file | cut -d' ' -f1)

if [ -z "${sasl_secret}" ]; then
  echo "ERROR: Unable to derive the secret.Failing the script."
  exit 1
fi

# The JKS keystore file used for enabling SSL/HTTPS
local_keystore_file="$DB_HOME/keys/jetty_ssl_driver_keystore.jks"
# Password of the JKS keystore file. This jks password is hardcoded and is not intended to protect the confidentiality
# of the keystore. Do not assume the keystore file itself is protected.
local_keystore_password="gb1gQqZ9ZIHS"

## Updating spark-branch.conf is only needed for driver

if [[ $DB_IS_DRIVER = "TRUE" ]]; then
  driver_conf=${DB_HOME}/driver/conf/spark-branch.conf
  echo "Configuring driver conf at $driver_conf"

  if [ ! -e $driver_conf ] ; then
    touch $driver_conf
  fi

cat << EOF >>  $driver_conf
  [driver] {
    // Configure inter-node authentication
  "spark.authenticate" = true
  "spark.authenticate.secret" = "$sasl_secret"
  // Configure AES encryption
  "spark.network.crypto.enabled" = true
  "spark.network.crypto.saslFallback" = false
  // Configure SSL
  "spark.ssl.enabled" = true
  "spark.ssl.keyPassword" = "$local_keystore_password"
  "spark.ssl.keyStore" = "$local_keystore_file"
  "spark.ssl.keyStorePassword" = "$local_keystore_password"
  "spark.ssl.protocol" ="TLSv1.3"
  "spark.ssl.standalone.enabled" = true
  "spark.ssl.ui.enabled" = true
  }
EOF
  echo "Successfully configured driver conf at $driver_conf"
fi

# Setting configs in spark-defaults.conf for the spark master and worker

spark_defaults_conf="$DB_HOME/spark/conf/spark-defaults.conf"
echo "Configuring spark defaults conf at $spark_defaults_conf"
if [ ! -e $spark_defaults_conf ] ; then
  touch $spark_defaults_conf
fi

cat << EOF >>  $spark_defaults_conf
spark.authenticate true
spark.authenticate.secret $sasl_secret
spark.network.crypto.enabled true
spark.network.crypto.saslFallback false

spark.ssl.enabled true
spark.ssl.keyPassword $local_keystore_password
spark.ssl.keyStore $local_keystore_file
spark.ssl.keyStorePassword $local_keystore_password
spark.ssl.protocol TLSv1.3
spark.ssl.standalone.enabled true
spark.ssl.ui.enabled true
EOF

echo "Successfully configured spark defaults conf at $spark_defaults_conf"

驱动程序和工作器节点的初始化完成后,这些节点之间的所有流量均使用密钥存储文件进行加密。

笔记本示例:安装加密 init 脚本

以下笔记本复制密钥存储文件并在 DBFS 中生成 init 脚本。 可以使用该 init 脚本创建启用了加密的新群集。

安装加密 init 脚本笔记本

获取笔记本

禁用工作器节点之间的加密

要禁用工作器节点之间的加密,请从群集配置中删除 init 脚本,然后重新启动群集。