任何编写 YARN 应用程序的人都需要了解此过程,以便编写短期应用程序或长期服务。他们还需要在早期开发阶段开始在安全集群上进行测试,以便编写实际可用的代码。
YARN 资源管理器 (RM) 和节点管理器 (NM) 协同工作,以使用该用户的身份(因此具有该用户的访问权限)来执行用户的应用程序。
(活动)资源管理器
在集群中查找空间来部署应用程序的核心部分,即应用程序主控 (AM)。
请求该节点上的 NM 分配一个容器并在其中启动 AM。
与 AM 通信,以便 AM 可以请求新容器并操作/释放当前容器,以及提供有关已分配和正在运行的容器的通知。
节点管理器
本地化资源:从 HDFS 或其他文件系统下载到本地目录。这是使用附加到容器启动上下文的委派令牌完成的。(对于非 HDFS 资源,使用其他凭据,例如群集配置文件中的对象存储登录详细信息)
以用户身份启动应用程序。
监控应用程序并向 RM 报告故障。
要在群集中执行代码,YARN 应用程序必须
具有一个客户端应用程序,该应用程序设置 ApplicationSubmissionContext,详细说明要启动的内容。这包括
具有一个应用程序主控,该主控在启动时向 YARN RM 注册并侦听事件。任何希望在其他容器中执行工作的 AM 都必须向 RM 请求这些容器,并在分配时创建一个 ContainerLaunchContext,其中包含要执行的命令、执行命令的环境、要本地化的二进制文件和所有相关安全凭据。
即使 NM 处理本地化过程,AM 本身也必须能够检索启动时提供的安全凭据,以便它本身可以与 HDFS 和任何其他服务一起工作,并将部分或全部这些凭据传递给已启动的容器。
YARN 应用程序所需的委派令牌必须从以经过身份验证的用户身份执行的程序中获取。对于 YARN 应用程序,这意味着启动应用程序的用户。这是 YARN 应用程序的客户端部分必须执行的操作
UserGroupInformation 登录。ApplicationSubmissionContext 中的 ContainerLaunchContext。需要哪些令牌?通常,至少需要一个令牌来访问 HDFS。
应用程序必须从它打算与其交互的每个文件系统请求委派令牌,包括群集的主 FS。FileSystem.addDelegationTokens(renewer, credentials) 可用于收集这些令牌;对于不颁发令牌的文件系统(包括未经过 Kerberos 认证的 HDFS 群集),它是一个空操作。
与其他服务(例如 Apache HBase 和 Apache Hive)通信的应用程序必须使用这些服务的库从这些服务请求令牌以获取委派令牌。所有令牌都可以添加到同一组凭据中,然后保存到字节缓冲区以供提交。
应用程序时间线服务器还需要一个委派令牌。这在 AM 启动时会自动处理。
当应用程序主控启动并且触发用户登录的任何 UGI/Hadoop 操作被调用时,UGI 类会自动加载环境变量 HADOOP_TOKEN_FILE_LOCATION 指定的文件中保存的所有令牌。
这发生在不安全的集群和安全集群中,并且在安全集群中,即使应用程序使用密钥表也是如此。为什么?因为始终通过这种方式提供用于使用 YARN RM 对应用程序进行身份验证的 AM/RM 令牌。
这意味着您在安全和不安全集群中具有相对类似的工作流。
在 AM 启动期间,登录到 Kerberos。调用 UserGroupInformation.isSecurityEnabled() 将触发此操作。
通过调用 UserGroupInformation.getCurrentUser().getCredentials() 枚举当前用户的凭据。
过滤掉 AMRM 令牌,从而产生一组新的凭据。在不安全的集群中,凭据列表现在将为空;在安全集群中,它们将包含
将要启动的所有容器的凭据设置为此(可能为空)凭据列表。
如果要续订的令牌的过滤列表不为空,则启动一个线程来续订它们。
令牌会过期:它们具有有限的寿命。希望在该到期日期后使用令牌的应用程序必须在令牌过期之前续订令牌。
Hadoop 在需要时会自动设置委派令牌续订线程,即 DelegationTokenRenewer。
应用程序有责任续订除 AMRM 和时间线令牌之外的所有令牌。
以下是不同的策略
不要依赖于应用程序的寿命如此之短,以至于不需要令牌续订。对于其生命周期始终以分钟或几十分钟为单位的应用程序,这是一个可行的策略。
启动后台线程/执行器以定期续订令牌。这是大多数 YARN 应用程序所做的。
AM/RM 令牌会自动续订;RM 会在 allocate 消息中向 AM 发送一个新令牌。请参阅 AMRMClientImpl 类以了解该流程。您的 AM 代码无需担心此流程
即使应用程序定期续订令牌,如果 AM 出现故障并重新启动,它也会从该原始 ApplicationSubmissionContext 重新启动。那里的令牌可能已过期,因此即使在向其他服务提供凭据之前,本地化也可能会失败。
如何解决此问题?YARN 资源管理器会根据需要为节点管理器获取一个新令牌。
更准确地说
这主要是长期服务的相关问题(见下文)。
非托管应用程序主控不会在 RM 和 NM 设置的容器中启动,因此无法在启动时自动获取 AM/RM 令牌。YarnClient.getAMRMToken() API 允许非托管 AM 请求 AM/RM 令牌。请参阅 UnmanagedAMLauncher 以了解具体信息。
HADOOP_USER_NAME在不安全的集群中,应用程序将以节点管理器帐户的身份运行,例如 yarn 或 mapred。默认情况下,应用程序将以该用户身份访问 HDFS,并具有不同的主目录,并且在审计日志和文件系统所有者属性中标识不同的用户。
可以通过让客户端识别出应用程序预期运行在其下的 HDFS/Hadoop 用户的身份来避免这种情况。这不会影响操作系统级用户或应用程序对本地计算机的访问权限。
当 Kerberos 被禁用时,用户身份首先由 Hadoop 从环境变量 HADOOP_USER_NAME 中获取,然后从操作系统级用户名(例如系统属性 user.name)中获取。
YARN 应用程序应该通过设置此环境变量来传播启动应用程序的用户的用户名。
Map<String, String> env = new HashMap<>(); String userName = UserGroupInformation.getCurrentUser().getUserName(); env.put(UserGroupInformation.HADOOP_USER_NAME, userName); containerLaunchContext.setEnvironment(env);
请注意,此环境变量在通过 hadoop 库与 HDFS 通信的所有应用程序中都会被获取。也就是说,如果设置了此环境变量,则它是在此环境变量被设置的 YARN 容器的环境中获取的身份,并且是 HBase 和其他应用程序获取的身份。
HADOOP_TOKEN_FILE_LOCATIONApache Oozie 可以通过获取所有相关凭据、将它们保存到本地文件系统中的一个文件中,然后在环境变量 HADOOP_TOKEN_FILE_LOCATION 中设置此文件的路径,在安全集群中启动应用程序。当然,这是 YARN 在启动的容器中传递下来的相同环境变量,并且内容相似:包含凭据的字节数组。
然而,此处在执行 YARN 客户端的环境中设置环境变量。此客户端必须使用已命名的文件中保存的令牌信息,而不是获取其自己的任何令牌。
加载令牌文件是自动的:UGI 在用户登录期间执行此操作。
然后,客户端负责将相同的凭据传递到 AM 启动上下文中。这可以通过简单地传递当前凭据来完成。
credentials = new Credentials(
UserGroupInformation.getCurrentUser().getCredentials());
应用程序时间线服务器可以部署为安全服务——在这种情况下,应用程序将需要相关令牌来对其进行身份验证。如果在安全集群中启用了 ATS,则此过程将在 YarnClientImpl 中自动处理。类似地,AM 端 TimelineClient YARN 服务类通过 ATS 的 SPNEGO 身份验证的 REST API 自动管理令牌续订。
如果您需要为通过 Oozie 启动的 YARN 应用程序准备一组委派令牌,可以通过时间线客户端 API 完成此操作。
try(TimelineClient timelineClient = TimelineClient.createTimelineClient()) {
timelineClient.init(conf);
timelineClient.start();
Token<TimelineDelegationTokenIdentifier> token =
timelineClient.getDelegationToken(rmprincipal));
credentials.addToken(token.getService(), token);
}
应用程序在终止其 AM 时可能会希望取消其持有的令牌。这可确保令牌不再有效。
这不是强制性的,并且由于无法保证 YARN 应用程序的干净关闭,因此无法保证在应用程序终止期间始终会取消令牌。但是,它确实减少了令牌被盗的漏洞窗口。
所有令牌续订都有时间限制,在此之后令牌将不会续订,导致应用程序停止工作。这在 72 小时到 7 天之间。
任何打算长期运行的 YARN 服务必须制定续订凭证的策略。
以下是策略
为应用程序在每个节点上使用提供了一个 Keytab。
这是通过以下方式完成的
UserGroupInformation.loginUserFromKeytab() 加载凭证。Keytab 必须位于安全的目录路径中,只有服务(和其他受信任的帐户)才能读取它。分发成为集群运营团队的责任。
这实际上是所有静态 Hadoop 应用程序获取其安全凭证的方式。
将 Keytab 上传到 HDFS。
启动 AM 时,Keytab 被列为要本地化到 AM 容器的资源。
应用程序主服务器配置为 Keytab 的相对路径,并使用 UserGroupInformation.loginUserFromKeytab() 登录。
当 AM 启动容器时,它将 Keytab 的 HDFS 路径列为要本地化的资源。
它将 HDFS 委派令牌添加到容器启动上下文中,以便可以本地化 Keytab 和其他应用程序文件。
启动的容器必须通过 UserGroupInformation.loginUserFromKeytab() 自行登录。UGI 处理登录,并计划一个后台线程定期重新登录用户。
Hadoop IPC 和 REST API 中会自动处理令牌创建,容器会通过 Kerberos 在整个持续时间内保持登录状态。
这避免了在整个集群中为特定服务安装密钥表的管理任务。
它确实要求客户端有权访问密钥表,并且由于它已上传到分布式文件系统,因此必须通过适当的路径权限/ACL 进行保护。
由于所有容器都可以访问密钥表,因此在容器中执行的所有代码都必须是可信的。恶意代码(或逃逸某种沙箱的代码)可以读取密钥表,因此在密钥过期或被吊销之前可以访问集群。
这是 Apache Slider(孵化版)实施的策略。
客户端将密钥表上传到 HDFS。
启动 AM 时,Keytab 被列为要本地化到 AM 容器的资源。
应用程序主节点配置为密钥表的相对路径,并使用 UserGroupInformation.loginUserFromKeytab() 登录。UGI 代码路径仍会自动加载通过 $HADOOP_TOKEN_FILE_LOCATION 引用文件,这就是 AMRM 令牌被选中的方式。
当 AM 启动容器时,它会获取该容器所需的所有委派令牌,并将它们添加到容器的容器启动上下文中。
已启动的容器必须从 $HADOOP_TOKEN_FILE_LOCATION 加载委派令牌,并在它们无法再续订之前使用它们(包括续订)。
AM 必须实现一个 IPC 接口,允许容器请求一组新的委派令牌;此接口本身必须使用身份验证,理想情况下还使用有线加密。
在委派令牌即将过期之前,在容器中运行的进程必须通过 IPC 通道向应用程序主节点请求新令牌。
当容器需要新令牌时,AM(使用密钥表登录)会向各种集群服务请求新令牌。
(请注意,刷新操作还有另一种方向:从 AM 到容器,同样通过 AM 和容器之间实现的任何 IPC 通道)。算法的其余部分:通过 IPC 将 AM 再生令牌传递给容器。
这是 Apache Spark 1.5+ 使用的策略,容器和 AM 之间使用基于 Netty 的协议进行令牌更新。
由于只有 AM 可以直接访问密钥表,因此它的暴露程度较低。在容器中运行的代码只能访问委派令牌。
但是,这些容器将能够从容器启动时传入的令牌访问 HDFS,因此将能够访问用于启动 AM 的密钥表的副本。虽然 AM 可以在启动时删除该密钥表,但这样做会阻止 YARN 在任何故障后成功重新启动 AM。
对于严格的操作团队来说,此策略可能是唯一可接受的策略:在持有 Kerberos TGT 的帐户上运行的客户端进程与所有需要的集群服务协商新的委派令牌,然后通过某些 RPC 接口将令牌推送到应用程序主控程序。
这确实要求定期重新执行客户端进程;cron 或 Oozie 作业可以执行此操作。应用程序主控程序需要实现一个 IPC API,通过该 API 可以提供更新的令牌。(请注意,由于 Oozie 可以自行收集令牌,因此更新程序应用程序在每次执行时需要做的所有操作就是设置与应用程序主控程序的 IPC 连接并传递当前用户的凭据)。
YARN 提供了一种简单的方法,可为每个 YARN 应用程序提供 SPNEGO 认证的网页:资源管理器在资源管理器代理中实现 SPNEGO 认证,并将对 Yarn 应用程序 Web UI 的访问限制为仅限资源管理器代理。有两种方法可以做到这一点
在设置其 Web UI 时,YARN 应用程序的 Web 服务器应加载应用程序主控程序代理过滤器(请参阅 AmFilterInitializer 类);此过滤器会将来自除资源管理器代理主机之外的任何主机的 HTTP 请求全部重定向到资源管理器代理,客户端应用程序/浏览器必须向其重新发出请求。客户端将针对资源管理器代理的主体(通常为 yarn)进行身份验证,并且一旦通过身份验证,其请求就会被转发。
此选项中已知的弱点是
应用程序主控程序代理过滤器仅检查资源管理器代理的 IP/主机,因此在这些主机上运行的任何应用程序都可以不受限制地访问 YARN 应用程序的 Web UI。这就是为什么在安全集群中,代理主机必须在不运行最终用户代码的集群节点上运行(即不运行 YARN 节点管理器,因此不调度 YARN 容器;也不支持最终用户登录)。
资源管理器代理和 Yarn 应用程序之间的 HTTP 请求当前未加密。也就是说:不支持 HTTPS。
默认情况下,YARN 应用程序 Web UI 未加密(即 HTTPS)。应用程序需要提供对 HTTPS 的支持。这可以通过使用来自公共 CA 或资源管理器或 JVM 配置为信任的来源的有效 HTTPS 证书完全独立地完成。或者,资源管理器可以充当有限的 CA,并为应用程序提供它可以使用且仅被资源管理器代理接受的证书,而不会被其他客户端(例如 Web 浏览器)接受。这一点很重要,因为应用程序不一定可信,不会窃取任何已颁发的证书或执行其他恶意行为。资源管理器颁发的证书将(a)过期,(b)有一个包含 CN=<application-id> 的主题,而不是典型的 CN=<hostname|domain>,以及(c)由资源管理器生成的自签名 CA 证书颁发。
要让应用程序利用此功能,它只需将提供的密钥库加载到其选择的 Web 服务器中。密钥库的位置可以在 KEYSTORE_FILE_LOCATION 环境变量中找到,其密码在 KEYSTORE_PASSWORD 环境变量中。只要 yarn.resourcemanager.application-https.policy 未设置为 NONE(请参阅下表),并且它提供了 HTTPS 跟踪 URL,它都将可用。
此外,应用程序可以通过 HTTPS 相互认证来验证 RM 代理实际上是 RM。除了提供的密钥库之外,RM 代理的客户端证书中还有一个提供的信任库。通过加载此信任库并在其选择的 Web 服务器中启用 needsClientAuth(或等效项),AM 的 Web 服务器应自动要求客户端(即 RM 代理)提供受信任的证书,否则将失败连接。这可确保只有客户端经过身份验证的 RM 代理才能访问它。
yarn.resourcemanager.application-https.policy |
行为 |
|---|---|
NONE |
RM 不会执行任何特殊操作。 |
LENIENT |
RM 将生成密钥库和信任库并将其提供给 AM,AM 可以自由地将其用于跟踪 URL Web 服务器中的 HTTPS。RM 代理仍将允许与选择不使用 HTTPS 的 AM 建立 HTTP 连接。 |
STRICT |
这与 LENIENT 相同,只是 RM 代理只允许与 AM 建立 HTTPS 连接;HTTP 连接将被阻止,并向用户显示警告页面。 |
默认值为 OFF。
在与 YARN 应用程序的已注册 Web UI 相同的端口上运行的 YARN REST API 会通过 RM 代理中的 SPNEGO 身份验证自动进行身份验证。
在不同端口上启动的任何 REST 端点(以及任何 Web UI)都不支持 SPNEGO 身份验证,除非在 YARN 应用程序本身中实施。
以下是 YARN 应用程序在 YARN 集群中成功启动必须执行的核心操作清单。
[ ] 客户端通过 UserGroupInformation.isSecurityEnabled() 检查是否启用了安全性
在安全集群中
[ ] 如果未设置 HADOOP_TOKEN_FILE_LOCATION,客户端将获取本地文件系统的委派令牌,并设置 RM 主体为更新者。
[ ] 如果 HADOOP_TOKEN_FILE_LOCATION 未设置,客户端将获取将在 YARN 应用程序中使用的所有其他服务的委派令牌。
[ ] 如果 HADOOP_TOKEN_FILE_LOCATION 已设置,客户端将使用当前用户的凭据作为要添加到容器启动上下文的令牌的来源。
[ ] 客户端在 AM ContainerLaunchContext.setTokens() 上设置所有令牌。
[ ] 建议:如果在客户端环境中设置,客户端在 AM 的容器启动上下文中设置环境变量 HADOOP_JAAS_DEBUG=true。
在不安全的集群中
[ ] 将本地用户名传播到 YARN AM,因此通过 HADOOP_USER_NAME 环境变量传播 HDFS 标识。
[ ] 在安全集群中,AM 从 HADOOP_TOKEN_FILE_LOCATION 环境变量中检索安全令牌(由 UGI 自动完成)。
[ ] 令牌集的副本经过筛选,以移除 AM/RM 令牌和任何时间线令牌。
[ ] 启动线程或执行器以定期续订线程。
[ ] 建议:应用程序完成后,AM 取消令牌。
[ ] 要传递给容器的令牌通过 ContainerLaunchContext.setTokens() 传递。
[ ] 在不安全的集群中,传播 HADOOP_USER_NAME 环境变量。
[ ] 建议:如果在 AM 的环境中设置,AM 在容器启动上下文中设置环境变量 HADOOP_JAAS_DEBUG=true。
[ ] 调用 UserGroupInformation.isSecurityEnabled() 以触发安全设置。
[ ] 启动线程或执行器以定期续订线程。
[ ] 应用程序开发人员已选择并实施了令牌续订策略:共享密钥表、AM 密钥表或客户端令牌刷新。
[ ] 在安全集群中,密钥表要么已在 HDFS 中(并已检查),要么在客户端的本地 FS 中,在这种情况下,必须上传该密钥表并将其添加到要本地化的资源列表中。
[ ] 如果存储在 HDFS 中,应检查密钥表权限。如果除当前用户之外的其他主体可以读取密钥表,请发出警告,并考虑实际失败启动(类似于正常的 ssh 应用程序)。
[ ] 客户端获取 HDFS 委派令牌并附加到 AM 容器启动上下文,
[ ] AM 通过 loginUserFromKeytab() 以密钥表中的主体身份登录。
[ ] (AM 从 HADOOP_TOKEN_FILE_LOCATION 环境变量中提取 AM/RM 令牌)。
[ ] 对于已启动的容器,要么传播密钥表,要么 AM 获取/附加所有必需的委派令牌到容器启动上下文,以及 NM 所需的 HDFS 委派令牌。
确信 YARN 应用程序在安全集群中运行非常简单。执行此操作的过程是:在安全集群中进行测试。
即使单个 VM 集群也可以启用安全功能进行设置。如果这样做,我们建议将安全性调到最严格,使用 SPNEGO 认证的 Web UI(因此还有 RM 代理),以及 IPC 线路加密。将 Kerberos 令牌到期时间设置为低于一小时将及早发现 Kerberos 到期问题,因此也建议这样做。
[ ] 在安全集群中启动应用程序。
[ ] 启动的应用程序以提交作业的用户身份运行(提示:在 AM 中记录 user.name 系统属性)。
[ ] 在安全集群中验证 Web 浏览器交互。
[ ] 测试 REST 客户端交互(GET 操作)。
[ ] Kerberos 令牌到期后,应用程序继续运行。
[ ] 如果用户没有 Kerberos 凭据,则应用程序不会启动。
[ ] 如果应用程序支持时间线服务器,请验证它在安全集群中发布事件。
[ ] 如果应用程序与其他应用程序(如 HBase 或 Hive)集成,请验证交互在安全集群中运行。
[ ] 如果应用程序与远程 HDFS 集群通信,请验证它可以在安全集群中进行通信(即客户端在启动时为此提取了任何委派令牌)
如果您没有在安全 Hadoop 集群中测试 YARN 应用程序,则它将无法运行。
如果没有这些测试:您的用户将发现您的应用程序无法在安全集群中运行。
在考虑将多少开发工作投入到 Kerberos 支持时,请牢记这一点。