Spark 安全性

Spark 安全性:你需要了解的事项

默认情况下,认证等安全功能并未启用。当部署一个对互联网或不受信任网络开放的集群时,确保集群访问安全以防止未经授权的应用程序在集群上运行至关重要。

Spark 支持多种部署类型,每种类型都支持不同级别的安全性。并非所有部署类型在所有环境中都安全,且默认情况下没有一种是安全的。请务必评估您的环境、Spark 支持的功能,并采取适当措施来保护您的 Spark 部署。

有许多不同类型的安全问题。Spark 不一定能防御所有威胁。下面列出了一些 Spark 支持的功能。此外,请查阅您所使用部署类型的部署文档,以获取特定于部署的设置。任何未记录的功能,Spark 均不支持。

Spark RPC(Spark 进程间通信协议)

认证

Spark 当前支持使用共享密钥对 RPC 通道进行认证。可以通过设置 spark.authenticate 配置参数来开启认证。

生成和分发共享密钥的具体机制取决于部署类型。除非另有说明,否则必须通过设置 spark.authenticate.secret 配置选项来定义密钥。在这种情况下,所有 Spark 应用程序和守护进程共享相同的密钥,这限制了这些部署的安全性,特别是在多租户集群上。

REST 提交服务器通过 JWSFilter 支持带有加密签名的 JSON Web Token 的 HTTP Authorization 头。要启用授权,Spark Master 应配置 spark.master.rest.filters=org.apache.spark.ui.JWSFilterspark.org.apache.spark.ui.JWSFilter.param.secretKey=BASE64URL-ENCODED-KEY,并且客户端应提供包含由共享密钥签名的 JSON Web Token 的 HTTP Authorization 头。

YARN

对于 YARN 上的 Spark,Spark 将自动处理生成和分发共享密钥。每个应用程序将使用一个唯一的共享密钥。在 YARN 的情况下,此功能依赖于 YARN RPC 加密被启用,以确保密钥分发的安全性。

属性名称默认值含义起始版本
spark.yarn.shuffle.server.recovery.disabled false 对于具有更高安全要求且不希望将其密钥保存在数据库中的应用程序,请将其设置为 true。此类应用程序的混洗数据在外部混洗服务重启后将无法恢复。 3.5.0

Kubernetes

在 Kubernetes 上,Spark 也会为每个应用程序自动生成一个唯一的认证密钥。该密钥通过环境变量传播到 Executor Pod。这意味着任何可以在 Spark 应用程序运行的命名空间中列出 Pod 的用户都可以看到其认证密钥。Kubernetes 管理员应正确设置访问控制规则,以确保 Spark 认证安全。

属性名称默认值含义起始版本
spark.authenticate false Spark 是否对其内部连接进行认证。 1.0.0
spark.authenticate.secret 用于认证的密钥。关于何时设置此配置,请参见上文。 1.0.0

或者,可以使用用户挂载到其 Pod 中的文件和 Kubernetes Secrets 来挂载认证密钥。

属性名称默认值含义起始版本
spark.authenticate.secret.file 指向用于保护连接的密钥文件路径。确保文件内容已安全生成。除非其他设置覆盖此项(见下文),否则此文件会在驱动程序和执行程序上加载。 3.0.0
spark.authenticate.secret.driver.file spark.authenticate.secret.file 的值 指定时,会覆盖 Spark 驱动程序读取密钥的位置。在客户端模式下非常有用,因为密钥文件在 Pod 中和驱动程序运行节点上的位置可能不同。当指定此项时,必须指定 spark.authenticate.secret.executor.file,以便驱动程序和执行程序都可以使用文件加载密钥。确保驱动程序上的文件内容与执行程序上的文件内容相同。 3.0.0
spark.authenticate.secret.executor.file spark.authenticate.secret.file 的值 指定时,会覆盖 Spark 执行程序读取密钥的位置。在客户端模式下非常有用,因为密钥文件在 Pod 中和驱动程序运行节点上的位置可能不同。当指定此项时,必须指定 spark.authenticate.secret.driver.file,以便驱动程序和执行程序都可以使用文件加载密钥。确保驱动程序上的文件内容与执行程序上的文件内容相同。 3.0.0

请注意,当使用文件时,Spark 不会为您将这些文件挂载到容器中。您需要确保密钥文件安全地部署到容器中,并且驱动程序的密钥文件与执行程序的密钥文件一致。

网络加密

Spark 支持两种互斥的 RPC 连接加密形式

首选方法是使用通过 Netty 对 SSL 的支持实现的 TLS(即 SSL)加密。启用 SSL 需要正确配置密钥和证书。SSL 是标准化的,被认为更安全。

传统方法是一种基于 AES 的加密机制,依赖于共享密钥。这要求同时启用 RPC 认证。此方法使用了一种定制协议,建议改用 SSL。

在合规性要求使用特定协议的场景中,或者为了利用更标准加密库的安全性,用户可能更倾向于使用基于 SSL 的加密。然而,基于 AES 的加密配置更简单,如果唯一的要求是在传输过程中加密数据,则可能更受青睐。

如果配置中同时启用了这两个选项,则基于 SSL 的 RPC 加密将优先,而基于 AES 的加密将不会被使用(并会发出警告消息)。

SSL 加密(首选)

Spark 支持基于 SSL 的 RPC 连接加密。请参阅下面的 SSL 配置部分,了解如何配置它。UI 和 RPC 的 SSL 设置大多相似,但有一些额外的设置是 RPC 实现特有的。RPC 实现底层使用 Netty(而 UI 使用 Jetty),它支持一组不同的选项。

与 UI 的其他 SSL 设置不同,如果设置了 spark.ssl.enabled,RPC SSL 不会自动启用。它必须显式启用,以确保 Spark 版本升级用户的安全迁移路径。

基于 AES 的加密(传统)

Spark 支持基于 AES 的 RPC 连接加密。要启用加密,RPC 认证也必须启用并正确配置。AES 加密使用 Apache Commons Crypto 库,Spark 的配置系统允许高级用户访问该库的配置。

这个传统协议有两个互不兼容的版本。版本 1 忽略对密钥交换协议的输出应用密钥派生函数 (KDF),而版本 2 应用 KDF 以确保派生会话密钥均匀分布。版本 1 默认为向后兼容。建议使用版本 2 以获得更好的安全属性。可以通过将 spark.network.crypto.authEngineVersion 分别设置为 1 或 2 来配置版本。

还支持基于 SASL 的加密,但应将其视为已弃用。当与 Spark 2.2.0 之前版本的 shuffle 服务通信时,仍然需要它。

下表描述了可用于配置此功能的不同选项。

属性名称默认值含义起始版本
spark.network.crypto.enabled false 启用基于 AES 的 RPC 加密,包括 2.2.0 中添加的新认证协议。 2.2.0
spark.network.crypto.cipher AES/CTR/NoPadding 要使用的密码模式。为了向后兼容,默认为“AES/CTR/NoPadding”,此模式未经认证。建议使用“AES/GCM/NoPadding”,它是一种认证加密模式。 4.0.0, 3.5.2, 3.4.4
spark.network.crypto.authEngineVersion 1 要使用的基于 AES 的 RPC 加密版本。有效版本为 1 或 2。建议使用版本 2。 4.0.0
spark.network.crypto.config.* commons-crypto 库的配置值,例如要使用的密码实现。配置名称应为 commons-crypto 配置的名称,不带 commons.crypto 前缀。 2.2.0
spark.network.crypto.saslFallback true 当使用 Spark 内部机制认证失败时,是否回退到 SASL 认证。这在应用程序连接到不支持 Spark 内部认证协议的旧 shuffle 服务时很有用。在 shuffle 服务端,禁用此功能将阻止旧客户端进行认证。 2.2.0
spark.authenticate.enableSaslEncryption false 启用基于 SASL 的加密通信。 2.2.0
spark.network.sasl.serverAlwaysEncrypt false 禁用使用 SASL 认证的端口的未加密连接。这将拒绝来自已启用认证但未请求基于 SASL 加密的客户端的连接。 1.4.0

本地存储加密

Spark 支持加密写入本地磁盘的临时数据。这包括混洗文件、混洗溢出以及存储在磁盘上的数据块(用于缓存和广播变量)。它不包括使用 saveAsHadoopFilesaveAsTable 等 API 生成的输出数据。它也可能不包括用户明确创建的临时文件。

以下设置涵盖了启用磁盘写入数据加密的功能

属性名称默认值含义起始版本
spark.io.encryption.enabled false 启用本地磁盘 I/O 加密。目前所有模式都支持。强烈建议在使用此功能时启用 RPC 加密。 2.1.0
spark.io.encryption.keySizeBits 128 I/O 加密密钥的位大小。支持的值为 128、192 和 256。 2.1.0
spark.io.encryption.keygen.algorithm HmacSHA1 生成 I/O 加密密钥时使用的算法。支持的算法在 Java 密码体系结构标准算法名称文档的 KeyGenerator 部分中描述。 2.1.0
spark.io.encryption.commons.config.* commons-crypto 库的配置值,例如要使用的密码实现。配置名称应为 commons-crypto 配置的名称,不带 commons.crypto 前缀。 2.1.0

Web UI

认证与授权

Web UI 的认证是通过 jakarta servlet 过滤器 实现的。您需要一个实现您希望部署的认证方法的过滤器。Spark 不提供任何内置认证过滤器。

当存在认证过滤器时,Spark 还支持对 UI 的访问控制。每个应用程序都可以配置自己的单独访问控制列表 (ACL)。Spark 区分“查看”权限(谁被允许查看应用程序的 UI)和“修改”权限(谁可以执行诸如终止运行中的应用程序中的作业等操作)。

ACL 可以为用户或组配置。配置条目接受逗号分隔的列表作为输入,这意味着可以为多个用户或组授予所需的权限。如果您在共享集群上运行,并且有一组管理员或开发人员需要监控他们可能没有自己启动的应用程序,这会很有用。在特定 ACL 中添加通配符 (*) 表示所有用户都将拥有相应的权限。默认情况下,只有提交应用程序的用户会被添加到 ACL 中。

组员关系通过使用可配置的组映射提供者建立。映射器使用 spark.user.groups.mapping 配置选项进行配置,如下表所示。

以下选项控制 Web UI 的认证

属性名称默认值含义起始版本
spark.ui.allowFramingFrom SAMEORIGIN 通过 X-Frame-Options 允许特定命名 URI 的框架嵌入。默认情况下,仅允许来自同源。 1.6.0
spark.ui.filters Spark 通过 org.apache.spark.ui.JWSFilter 支持带有加密签名的 JSON Web Token 的 HTTP Authorization 头。
有关如何配置过滤器,请参阅 Spark UI 配置。
1.0.0
spark.acls.enable false 是否启用 UI ACL。如果启用,它会检查用户是否具有查看或修改应用程序的访问权限。请注意,这要求用户已通过认证,因此如果未安装认证过滤器,此选项将不起作用。 1.1.0
spark.admin.acls 拥有 Spark 应用程序查看和修改权限的用户列表,以逗号分隔。 1.1.0
spark.admin.acls.groups 拥有 Spark 应用程序查看和修改权限的组列表,以逗号分隔。 2.0.0
spark.modify.acls 拥有 Spark 应用程序修改权限的用户列表,以逗号分隔。 1.1.0
spark.modify.acls.groups 拥有 Spark 应用程序修改权限的组列表,以逗号分隔。 2.0.0
spark.ui.view.acls 拥有 Spark 应用程序查看权限的用户列表,以逗号分隔。 1.0.0
spark.ui.view.acls.groups 拥有 Spark 应用程序查看权限的组列表,以逗号分隔。 2.0.0
spark.user.groups.mapping org.apache.spark.security.ShellBasedGroupsMappingProvider 用户的组列表由 org.apache.spark.security.GroupMappingServiceProvider 特性定义的组映射服务确定,该服务可通过此属性配置。
默认情况下,使用基于 Unix shell 的实现,它从主机操作系统收集此信息。
注意:此实现仅支持基于 Unix/Linux 的环境。Windows 环境目前不支持。但是,可以通过实现上述特性来支持新的平台/协议。
2.0.0

在 YARN 上,查看和修改 ACL 在提交应用程序时提供给 YARN 服务,并通过 YARN 接口控制谁拥有相应的权限。

Spark 历史服务器 ACL

SHS Web UI 的认证与普通应用程序相同,使用 servlet 过滤器启用。

要在 SHS 中启用授权,需要使用一些额外的选项

属性名称默认值含义起始版本
spark.history.ui.acls.enable false 指定是否应检查 ACL 以授权用户查看历史服务器中的应用程序。如果启用,无论各个应用程序为 spark.ui.acls.enable 设置了什么,都会执行访问控制检查。应用程序所有者将始终有权查看其自己的应用程序,并且在应用程序运行时通过 spark.ui.view.acls 指定的任何用户以及通过 spark.ui.view.acls.groups 指定的组也将有权查看该应用程序。如果禁用,则不会对通过历史服务器可用的任何应用程序 UI 执行访问控制检查。 1.0.1
spark.history.ui.admin.acls 拥有历史服务器中所有 Spark 应用程序查看权限的用户列表,以逗号分隔。 2.1.1
spark.history.ui.admin.acls.groups 拥有历史服务器中所有 Spark 应用程序查看权限的组列表,以逗号分隔。 2.1.1

SHS 使用与常规应用程序相同的选项来配置组映射提供者。在这种情况下,组映射提供者将应用于 SHS 服务的所有 UI,并且将忽略单个应用程序配置。

SSL 配置

SSL 配置是分层组织的。用户可以配置默认的 SSL 设置,这些设置将用于所有支持的通信协议,除非它们被特定于协议的设置覆盖。这样,用户可以轻松地为所有协议提供通用设置,而不会禁用单独配置每个协议的能力。请注意,所有设置都以这种方式继承,除了 spark.ssl.rpc.enabled 必须显式设置。

下表描述了 SSL 配置命名空间

配置命名空间 组件
spark.ssl 默认的 SSL 配置。这些值将应用于以下所有命名空间,除非在命名空间级别明确覆盖。
spark.ssl.ui Spark 应用程序 Web UI
spark.ssl.standalone Standalone 主节点 / 工作节点 Web UI
spark.ssl.historyServer 历史服务器 Web UI
spark.ssl.rpc Spark RPC 通信

可用 SSL 选项的完整明细可在下文找到。${ns} 占位符应替换为上述命名空间之一。

属性名称默认值含义支持的命名空间
${ns}.enabled false 启用 SSL。启用时,需要 ${ns}.ssl.protocol ui,standalone,historyServer,rpc
${ns}.port SSL 服务将监听的端口。
端口必须在特定的命名空间配置中定义。读取此配置时,默认命名空间将被忽略。
如果未设置,SSL 端口将从同一服务的非 SSL 端口派生。值为“0”将使服务绑定到一个临时端口。
ui,standalone,historyServer
${ns}.enabledAlgorithms 以逗号分隔的密码列表。指定的密码必须受 JVM 支持。
协议参考列表可在 Java 安全指南的“JSSE 密码套件名称”部分找到。Java 17 的列表可在 页面找到。
注意:如果未设置,将使用 JRE 的默认密码套件。
ui,standalone,historyServer,rpc
${ns}.keyPassword 密钥库中私钥的密码。 ui,standalone,historyServer,rpc
${ns}.keyStore 密钥库文件的路径。路径可以是绝对路径,也可以是相对于进程启动目录的相对路径。 ui,standalone,historyServer,rpc
${ns}.keyStorePassword 密钥库的密码。 ui,standalone,historyServer,rpc
${ns}.keyStoreType JKS 密钥库的类型。 ui,standalone,historyServer
${ns}.protocol 要使用的 TLS 协议。该协议必须受 JVM 支持。
协议参考列表可在 Java 安全指南的“附加 JSSE 标准名称”部分找到。对于 Java 17,列表可在 页面找到。
ui,standalone,historyServer,rpc
${ns}.needClientAuth false 是否需要客户端认证。 ui,standalone,historyServer
${ns}.trustStore 信任库文件的路径。路径可以是绝对路径,也可以是相对于进程启动目录的相对路径。 ui,standalone,historyServer,rpc
${ns}.trustStorePassword 信任库的密码。 ui,standalone,historyServer,rpc
${ns}.trustStoreType JKS 信任库的类型。 ui,standalone,historyServer
${ns}.openSSLEnabled false 是否使用 OpenSSL 进行加密操作,而不是 JDK SSL 提供者。此设置要求设置 `certChain` 和 `privateKey`。如果同时指定了 `keyStore` 和 `trustStore`,此设置将优先。如果在运行时 OpenSSL 库不可用,我们将回退到 JDK 提供者。 rpc
${ns}.privateKey PEM 格式私钥文件的路径。路径可以是绝对路径,也可以是相对于进程启动目录的相对路径。使用 OpenSSL 实现时,此设置是必需的。 rpc
${ns}.privateKeyPassword 上述 PEM 格式私钥文件的密码。 rpc
${ns}.certChain PEM 格式证书链文件的路径。路径可以是绝对路径,也可以是相对于进程启动目录的相对路径。使用 OpenSSL 实现时,此设置是必需的。 rpc
${ns}.trustStoreReloadingEnabled false 是否应定期重新加载信任库。此设置主要仅在 Standalone 部署中有用,不适用于 Kubernetes 或 YARN 部署。 rpc
${ns}.trustStoreReloadIntervalMs 10000 重新加载信任库的时间间隔(毫秒)。此设置主要仅在 Standalone 部署中有用,不适用于 Kubernetes 或 YARN 部署。 rpc

Spark 还支持从 Hadoop 凭证提供者 中检索 ${ns}.keyPassword${ns}.keyStorePassword${ns}.trustStorePassword。用户可以将密码存储到凭证文件中,并使其可被不同组件访问,例如

hadoop credential create spark.ssl.keyPassword -value password \
    -provider jceks://hdfs@nn1.example.com:9001/user/backup/ssl.jceks

要配置凭证提供者的位置,请在 Spark 使用的 Hadoop 配置中设置 hadoop.security.credential.provider.path 配置选项,例如

  <property>
    <name>hadoop.security.credential.provider.path</name>
    <value>jceks://hdfs@nn1.example.com:9001/user/backup/ssl.jceks</value>
  </property>

或者通过 SparkConf:“spark.hadoop.hadoop.security.credential.provider.path=jceks://hdfs@nn1.example.com:9001/user/backup/ssl.jceks”。

准备密钥库

密钥库可以通过 keytool 程序生成。此工具在 Java 17 中的参考文档位于 此处。为 Spark Standalone 部署模式配置密钥库和信任库的最基本步骤如下

YARN 模式

要向在集群模式下运行的驱动程序提供本地信任库或密钥库文件,可以使用 --files 命令行参数(或等效的 spark.files 配置)随应用程序分发。文件将放置在驱动程序的工作目录中,因此 TLS 配置只需引用文件名,无需绝对路径。

以这种方式分发本地密钥库可能需要将文件暂存到 HDFS(或集群使用的其他类似分布式文件系统)中,因此建议在配置底层文件系统时考虑安全性(例如,通过启用认证和网络加密)。

Standalone 模式

用户需要为 Master 和 Worker 提供密钥库和配置选项。这些必须通过在 SPARK_MASTER_OPTSSPARK_WORKER_OPTS 环境变量中,或仅在 SPARK_DAEMON_JAVA_OPTS 中附加适当的 Java 系统属性来设置。

用户可以允许执行程序使用从 Worker 进程继承的 SSL 设置。这可以通过将 spark.ssl.useNodeLocalConf 设置为 true 来实现。在这种情况下,用户在客户端提供的设置将不被使用。

HTTP 安全头

Apache Spark 可以配置为包含 HTTP 头,以帮助防止跨站脚本 (XSS)、跨框架脚本 (XFS)、MIME 嗅探,并强制执行 HTTP Strict Transport Security。

属性名称默认值含义起始版本
spark.ui.xXssProtection 1; mode=block HTTP X-XSS-Protection 响应头的值。您可以从以下选项中选择合适的值
  • 0 (禁用 XSS 过滤)
  • 1 (启用 XSS 过滤。如果检测到跨站脚本攻击,浏览器将净化页面。)
  • 1; mode=block (启用 XSS 过滤。如果检测到攻击,浏览器将阻止页面渲染。)
2.3.0
spark.ui.xContentTypeOptions.enabled true 启用时,X-Content-Type-Options HTTP 响应头将设置为“nosniff”。 2.3.0
spark.ui.strictTransportSecurity HTTP Strict Transport Security (HSTS) 响应头的值。您可以从以下选项中选择合适的值,并相应地设置 expire-time。此选项仅在启用 SSL/TLS 时使用。
  • max-age=<expire-time>
  • max-age=<expire-time>; includeSubDomains
  • max-age=<expire-time>; preload
2.3.0

配置网络安全端口

一般来说,Spark 集群及其服务不会部署在公共互联网上。它们通常是私有服务,应仅在部署 Spark 的组织网络内部访问。对 Spark 服务使用的主机和端口的访问应仅限于需要访问服务的源主机。

然而,与 REST 提交端口类似,Spark 也支持所有 UI 端口的 HTTP Authorization 头,其中包含加密签名的 JSON Web Token (JWT)。要使用它,用户需要配置 spark.ui.filters=org.apache.spark.ui.JWSFilterspark.org.apache.spark.ui.JWSFilter.param.secretKey=BASE64URL-ENCODED-KEY

以下是 Spark 用于通信的主要端口以及如何配置这些端口。

仅限 Standalone 模式

来源目标默认端口目的配置设置备注
浏览器 Standalone Master 8080 Web UI spark.master.ui.port /
SPARK_MASTER_WEBUI_PORT
基于 Jetty。仅限 Standalone 模式。
浏览器 Standalone Worker 8081 Web UI spark.worker.ui.port /
SPARK_WORKER_WEBUI_PORT
基于 Jetty。仅限 Standalone 模式。
驱动程序 /
Standalone Worker
Standalone Master 7077 向集群提交作业 /
加入集群
SPARK_MASTER_PORT 设置为“0”以随机选择端口。仅限 Standalone 模式。
外部服务 Standalone Master 6066 通过 REST API 向集群提交作业 spark.master.rest.port 使用 spark.master.rest.enabled 启用/禁用此服务。仅限 Standalone 模式。
Standalone Master Standalone Worker (随机) 调度执行程序 SPARK_WORKER_PORT 设置为“0”以随机选择端口。仅限 Standalone 模式。

所有集群管理器

来源目标默认端口目的配置设置备注
浏览器 应用程序 4040 Web UI spark.ui.port 基于 Jetty
浏览器 历史服务器 18080 Web UI spark.history.ui.port 基于 Jetty
执行程序 /
Standalone Master
驱动程序 (随机) 连接到应用程序 /
通知执行程序状态变化
spark.driver.port 设置为“0”以随机选择端口。
执行程序 / 驱动程序 执行程序 / 驱动程序 (随机) 块管理器端口 spark.blockManager.port 通过 ServerSocketChannel 的原始套接字

Kerberos

Spark 支持在使用 Kerberos 进行认证的环境中提交应用程序。在大多数情况下,当认证 Kerberos 感知服务时,Spark 依赖当前登录用户的凭证。这些凭证可以通过使用 kinit 等工具登录配置的 KDC 来获取。

与基于 Hadoop 的服务通信时,Spark 需要获取委托令牌,以便非本地进程可以进行认证。Spark 内置支持 HDFS 和其他 Hadoop 文件系统、Hive 和 HBase。

当使用 Hadoop 文件系统(例如 HDFS 或 WebHDFS)时,Spark 将为托管用户主目录的服务获取相关令牌。

如果 HBase 在应用程序的 classpath 中,并且 HBase 配置已启用 Kerberos 认证(hbase.security.authentication=kerberos),将获取 HBase 令牌。

类似地,如果 Hive 在 classpath 中,并且配置包含远程元存储服务的 URI(hive.metastore.uris 不为空),将获取 Hive 令牌。

如果应用程序需要与其他的安全 Hadoop 文件系统交互,它们的 URI 需要在启动时明确提供给 Spark。这可以通过在 spark.kerberos.access.hadoopFileSystems 属性中列出它们来完成,该属性在下面的配置部分中描述。

Spark 还支持使用 Java 服务机制(参见 java.util.ServiceLoader)的自定义委托令牌提供者。通过在 jar 的 META-INF/services 目录中的相应文件中列出其名称,可以将 org.apache.spark.security.HadoopDelegationTokenProvider 的实现提供给 Spark。

委托令牌支持目前仅在 YARN 和 Kubernetes 模式下可用。请查阅特定部署页面以获取更多信息。

以下选项为此功能提供了更细粒度的控制

属性名称默认值含义起始版本
spark.security.credentials.${service}.enabled true 控制在启用安全性时是否获取服务的凭证。默认情况下,当配置了支持的服务时,会检索所有这些服务的凭证,但如果这与正在运行的应用程序发生冲突,则可以禁用此行为。 2.3.0
spark.kerberos.access.hadoopFileSystems (无) 您的 Spark 应用程序将要访问的安全 Hadoop 文件系统列表,以逗号分隔。例如,spark.kerberos.access.hadoopFileSystems=hdfs://nn1.com:8032,hdfs://nn2.com:8032, webhdfs://nn3.com:50070。Spark 应用程序必须有权访问列出的文件系统,并且 Kerberos 必须正确配置才能访问它们(无论是在同一领域还是在受信任的领域)。Spark 会为每个文件系统获取安全令牌,以便 Spark 应用程序可以访问这些远程 Hadoop 文件系统。 3.0.0

用户可以排除在资源调度器处续订 Kerberos 委托令牌。目前仅在 YARN 上支持此功能。配置详情请参见在 YARN 上运行 Spark 页面。

长时间运行的应用程序

长时间运行的应用程序如果其运行时间超过所需访问服务中配置的最大委托令牌生命周期,可能会遇到问题。

此功能并非在所有地方都可用。特别是,它仅在 YARN 和 Kubernetes(客户端和集群模式)中实现。

Spark 支持自动为这些应用程序创建新令牌。有两种方法可以启用此功能。

使用 Keytab

通过向 Spark 提供 principal 和 keytab(例如,使用 spark-submit 附带 --principal--keytab 参数),应用程序将保持有效的 Kerberos 登录,可用于无限期地检索委托令牌。

请注意,在集群模式下使用 keytab 时,它将被复制到运行 Spark 驱动程序的机器上。在 YARN 的情况下,这意味着使用 HDFS 作为 keytab 的暂存区域,因此强烈建议 YARN 和 HDFS 至少使用加密进行保护。

使用票据缓存

通过在 Spark 配置中将 spark.kerberos.renewal.credentials 设置为 ccache,本地 Kerberos 票据缓存将用于认证。Spark 将在票据的可续订生命周期内保持票据续订,但过期后需要获取新票据(例如,通过运行 kinit)。

用户有责任维护 Spark 可以使用的最新票据缓存。

可以通过设置 KRB5CCNAME 环境变量来自定义票据缓存的位置。

与 Kubernetes 的安全交互

在与 Kerberos 后面的基于 Hadoop 的服务通信时,需要 Spark 获取委托令牌,以便非本地进程可以进行认证。Kubernetes 中的这些委托令牌存储在 Secrets 中,由驱动程序及其执行程序共享。因此,提交 Kerberos 作业有三种方式

在所有情况下,您都必须定义环境变量:HADOOP_CONF_DIRspark.kubernetes.hadoop.configMapName.

另外值得注意的是,KDC 需要在容器内部可见。

如果用户希望使用包含 Hadoop 配置文件的远程 HADOOP_CONF 目录,可以通过将 spark.kubernetes.hadoop.configMapName 设置为预先存在的 ConfigMap 来实现。

  1. 使用将 TGT 存储在本地票据缓存中的 $kinit 提交
    /usr/bin/kinit -kt <keytab_file> <username>/<krb5 realm>
    /opt/spark/bin/spark-submit \
     --deploy-mode cluster \
     --class org.apache.spark.examples.HdfsTest \
     --master k8s://<KUBERNETES_MASTER_ENDPOINT> \
     --conf spark.executor.instances=1 \
     --conf spark.app.name=spark-hdfs \
     --conf spark.kubernetes.container.image=spark:latest \
     --conf spark.kubernetes.kerberos.krb5.path=/etc/krb5.conf \
     local:///opt/spark/examples/jars/spark-examples_<VERSION>.jar \
     <HDFS_FILE_LOCATION>
    
  2. 使用本地 Keytab 和 Principal 提交
    /opt/spark/bin/spark-submit \
     --deploy-mode cluster \
     --class org.apache.spark.examples.HdfsTest \
     --master k8s://<KUBERNETES_MASTER_ENDPOINT> \
     --conf spark.executor.instances=1 \
     --conf spark.app.name=spark-hdfs \
     --conf spark.kubernetes.container.image=spark:latest \
     --conf spark.kerberos.keytab=<KEYTAB_FILE> \
     --conf spark.kerberos.principal=<PRINCIPAL> \
     --conf spark.kubernetes.kerberos.krb5.path=/etc/krb5.conf \
     local:///opt/spark/examples/jars/spark-examples_<VERSION>.jar \
     <HDFS_FILE_LOCATION>
    
  3. 使用预填充的 secrets 提交,其中包含已存在于命名空间中的委托令牌
    /opt/spark/bin/spark-submit \
     --deploy-mode cluster \
     --class org.apache.spark.examples.HdfsTest \
     --master k8s://<KUBERNETES_MASTER_ENDPOINT> \
     --conf spark.executor.instances=1 \
     --conf spark.app.name=spark-hdfs \
     --conf spark.kubernetes.container.image=spark:latest \
     --conf spark.kubernetes.kerberos.tokenSecret.name=<SECRET_TOKEN_NAME> \
     --conf spark.kubernetes.kerberos.tokenSecret.itemKey=<SECRET_ITEM_KEY> \
     --conf spark.kubernetes.kerberos.krb5.path=/etc/krb5.conf \
     local:///opt/spark/examples/jars/spark-examples_<VERSION>.jar \
     <HDFS_FILE_LOCATION>
    

3b. 提交方式与 (3) 相同,但指定预先创建的 krb5 ConfigMap 和预先创建的 HADOOP_CONF_DIR ConfigMap

/opt/spark/bin/spark-submit \
    --deploy-mode cluster \
    --class org.apache.spark.examples.HdfsTest \
    --master k8s://<KUBERNETES_MASTER_ENDPOINT> \
    --conf spark.executor.instances=1 \
    --conf spark.app.name=spark-hdfs \
    --conf spark.kubernetes.container.image=spark:latest \
    --conf spark.kubernetes.kerberos.tokenSecret.name=<SECRET_TOKEN_NAME> \
    --conf spark.kubernetes.kerberos.tokenSecret.itemKey=<SECRET_ITEM_KEY> \
    --conf spark.kubernetes.hadoop.configMapName=<HCONF_CONFIG_MAP_NAME> \
    --conf spark.kubernetes.kerberos.krb5.configMapName=<KRB_CONFIG_MAP_NAME> \
    local:///opt/spark/examples/jars/spark-examples_<VERSION>.jar \
    <HDFS_FILE_LOCATION>

事件日志

如果您的应用程序使用事件日志,则应手动创建事件日志目录(spark.eventLog.dir)并设置适当的权限。为保护日志文件安全,目录权限应设置为 drwxrwxrwxt。目录的所有者和组应与运行 Spark 历史服务器的超级用户相对应。

这将允许所有用户写入目录,但会阻止无特权用户读取、删除或重命名文件,除非他们拥有该文件。Spark 将创建事件日志文件,其权限仅允许用户和组拥有读写访问权限。

在客户端模式下持久化驱动程序日志

如果您的应用程序通过启用 spark.driver.log.persistToDfs.enabled 在客户端模式下持久化驱动程序日志,则应手动创建驱动程序日志目录(spark.driver.log.dfsDir)并设置适当的权限。为保护日志文件安全,目录权限应设置为 drwxrwxrwxt。目录的所有者和组应与运行 Spark 历史服务器的超级用户相对应。

这将允许所有用户写入目录,但会阻止无特权用户读取、删除或重命名文件,除非他们拥有该文件。Spark 将创建驱动程序日志文件,其权限仅允许用户和组拥有读写访问权限。