返回

在托管计算上用工作负载证明换取自有身份

RSS Netflix Technology Blog AI 逐段翻译 发布 2026-09-26 00:01

有效阅读仅保存在当前浏览器,用于「为你」推荐;暂停或清除记录。

DataHot 速览

Netflix 工程博客介绍如何在 Amazon EMR 等托管计算上为 Apache Spark 工作负载打通身份体系。组织通常并行运行两套身份系统:云厂商的 IAM 角色/实例配置/执行角色,以及内部服务实际校验的自有身份。文章讲述如何让一个仅有 AWS 身份的工作负载最终获得一等公民的内部身份,并强调交换过程本身简单,难的是让它可信。

原收录理由(待核验):涉及数据平台的身份认证与工作负载证明机制,对在托管云环境上运行数据作业、需要统一内部权限与审计的数据平台工程师有直接参考价值。

本文目录 11 节
  1. 引言
  2. 两套身份系统
  3. 一个身份,一个角色
  4. 组件
  5. 第一步:控制平面做出签名声明
  6. 第二步:工作负载证明它持有云身份
  7. 第三步:佐证
  8. 扇出问题
  9. 生命周期
  10. 为什么这可以推广
  11. 致谢

译文

AI 逐段翻译

引言

存在已久的组织通常会并行运行两套身份系统。一套属于云提供商:IAM 角色、实例配置文件、执行角色。另一套是你自己的,也是你的内部服务在决定是否响应请求时实际检查的那套。

在你自己构建的基础设施上,你可以随意引导自己的身份。在托管计算上则不行。提供商交给你的进程一个云身份,仅此而已。

本文描述了我们如何为运行在 Amazon EMR 上的 Apache Spark 工作负载弥合这一差距。一个仅以 AWS 身份启动的工作负载最终必须持有一等公民的内部身份。进行这种交换本身很直接。使其可信才是需要设计工作的部分。以下内容很少是 Spark 或 EMR 特有的。

两套身份系统

Netflix 的内部服务间身份验证运行在一个名为 Metatron 的私有 PKI 之上。每个工作负载都会获得一张短期的 X.509 证书,服务之间通过双向 TLS 相互验证身份。工作负载不能简单地请求一张证书。只有在身份服务确信请求者确实就是它所声称的工作负载之后,证书才会被签发。这个验证步骤称为证明(attestation)。在我们支持的每种环境(虚拟机、容器、函数)中,证明都依赖于某种环境特定的、平台可以自行核验的证据。

第二个概念是 Data Project,它是我们数据的所有权单位。一个 Data Project 拥有表、拥有一组授权用户,并且拥有自己的身份。作业以 Data Project 的身份运行,而不是以启动它们的人的身份运行。这正是使表级访问控制和审计在计划任务与交互式使用之间保持一致的原因。

所以问题就是这样。托管计算上的 Spark 作业以一个 AWS 执行角色启动,没有内部身份。它从公司内部所需要的一切(读取加密列、评估表 ACL、将会话保持打开的时间超过短期令牌的有效期)都需要那个内部身份。

一个身份,一个角色

该设计依赖于一个完全在 Spark 技术栈之外做出的决定。每个 Data Project 身份与一个专用 IAM 角色一一对应,拥有 Data Project 元数据的服务记录该映射。

映射使转换成为可能。它让一条以提供商词汇表述的陈述(“此进程正以角色 R 运行”)转变为以我们的词汇表述的陈述(“此进程就是工作负载 W”)。没有它就没有可转换的目标,再多的密码学也无济于事。桥接两套身份系统的难点很少在于协议。而在于承诺一个映射,然后让它保持权威。

一个实际的反对意见立刻出现。单个 AWS 账户无法容纳数万个 IAM 角色,而我们预计数据项目数量在万级。我们通过确定性地将数据项目角色分片到一小池专用账户中来解决这个问题,这不仅能够很好地扩展到超出预计项目数量,还有一个有用的副作用:使工作负载角色与启动它们的控制平面之间隔着一个账户边界。

组件

共有五个组件参与。

该控制平面是唯一被允许启动 Spark 作业的服务。它解析 Data Project 的 IAM 角色,构建并签署工作负载元数据负载,并以该角色作为执行角色提交作业。它持有专为此目的签发给它的签名密钥。

该Data Project 服务是身份到角色映射的权威来源。

该身份服务接收证明请求、验证它们并签发证书。

一个Spark 插件提供钩子。Spark 3.0+ 增加了一个插件接口,具有驱动端和执行器端组件,在这些进程引导期间被初始化。

AWS STS充当公证人,这并非它通常的职责。

第一步:控制平面做出签名声明

当作业提交时,控制平面验证调用者,查找 Data Project 的 IAM 角色,并构建一个描述它即将启动的工作负载的小型负载。该负载指明了应用程序身份、映射的角色,以及生成的凭证应限定到的环境、堆栈和细节。控制平面对负载进行签名,并将它和签名作为普通作业配置传递下去。

这一步的两个特性很重要。第一,只有一个服务能产生有效签名,因此能够断言“此工作负载是合法的”的东西集合很小且可审计。第二,该负载是一个声明,而不是一种权威。仅凭它本身什么也证明不了,因为作业配置会经过我们并不完全控制的基础设施,任何能读取它的人都可以重放它。

第二步:工作负载证明它持有云身份

当托管服务启动驱动进程时,它是在一个可访问执行角色凭证的操作系统用户下启动的。驱动端插件初始化并使用这些凭证对一个发往提供商身份端点(sts:GetCallerIdentity)的请求进行签名,但不发送它。结果是一个短期预签名 URL。

该 URL 是一种可转移的持有证明。任何人都可以获取它。只有角色凭证的持有者才能生成它。而响应来自 AWS 而非工作负载,说明是哪个角色签署了该请求。工作负载无法对答案撒谎,因为答案不是由工作负载提供的。

这种模式并不新鲜。它正是 HashiCorp Vault 中的 AWS IAM 身份验证以及 AWS 自身的函数证明流程背后的同一理念。它具有良好的普适性:任何只给进程云凭证而不给其他东西的环境,仍然能够生成关于自身身份的可验证声明。

该插件发送一个证明请求,同时携带两件产物:预签名 URL 和已签名的元数据。

第三步:佐证

身份服务做四件事。

  1. 它用预签名 URL 向 AWS STS 发起请求,并读回签署该 URL 的角色。这是提供方的声明。
  2. 它用签发给控制平面的密钥验证元数据签名。这是平台的声明。
  3. 它对两者进行佐证。AWS 报告的角色,必须是控制平面声称其调度的角色,且对应元数据所指明的身份。
  4. 它为那个身份签发证书,范围限定为来自已签名元数据的环境、栈和细节。

第 3 步是整个设计的关键所在。任何单一声明都不足够,而且它们以互补的方式失效。提供方的声明不可伪造,但描述不足:它给你一个角色,而角色并不等于工作负载。它没有说明这个进程为何存在,或应被允许成为什么。平台的声明描述充分,但如上述原因,其自身无法被验证。合在一起,签名表明该工作负载是被合法调度的,而预签名 URL 表明这确实是它。双方都不必信任工作负载对自身的说法。

这里存在一种张力,我们有意做出了取舍,其他团队也应预期会遇到它。提供方的答案标识的是一个角色,而不是一个应用。从角色名推导应用名是脆弱的字符串匹配,而平台分配的会话标识符不受我们控制。我们选择从已签名元数据中获取应用身份,并仅将提供方的答案用于佐证。这要付出一次网络往返和更严格签名要求的代价,但换来了清晰得多的信任叙事。

扇出问题

一个 Spark 应用是一个 driver 和最多数千个 executor,它们在作业生命周期内不断创建和销毁。围绕每主机一个进程设计的证明机制无法应对这种情况。

有两个站得住脚的答案。

在第一种中,每个 executor 独立进行证明。这很统一,不增加新的信任边界,并将每个进程的身份建立在同一个经提供方验证的证明之上。代价是放大。一个大作业可能在突发中产生数千次 STS 调用和数千次证明请求,这看起来很像攻击,并会造成对提供方侧速率限制的硬依赖。

在第二种中,executor 从 driver 继承凭证。driver 证明一次,并通过 Spark 的内部 RPC 将凭证分发给 executor,我们对该 RPC 配置了身份验证和 AES-GCM 加密,以便只有同一应用中的进程才能参与。身份服务上的负载保持恒定。代价是第二个信任边界,以及 driver 现在成了凭证分发点。

考虑到我们在 Netflix 的规模,我们选择了第二种方法。普遍教训是,身份放大量是一个容量问题,最好有意识地解决它,而不是在事故期间让它替你解决。

生命周期

证书按设计是短期的,因此引导只是工作的一半。在自管理主机上,由系统服务处理续期。在托管计算中则没有等效的钩子,因此 driver JVM 运行一个定时器,以固定间隔提前于过期时间重新进行证明。凭证材料写入一个仅进程所有者可读的临时目录,并在进程退出时删除。

executor 不刷新。它们通常寿命很短,而某个不知为何活过了其凭证的 executor 可以退出并被替换,这比让每个 executor 都成为续期客户端更便宜。

值得带入任何类似系统的规则是:证明必须是一个可重复的操作,而不是一个引导步骤。任何只能在进程启动时发生一次的事情,最终都会成为长时间运行的作业在九小时后死亡的原因。

为什么这可以推广

如果你运行自己的身份系统,并正在将工作负载迁移到托管计算上,那么这里的具体服务不如解决方案的形态重要。

  1. 锚定在一个可交换的原语上。在你的身份与提供方身份之间建立单一权威的 1:1 映射,是使转换成为可能的关键。其余都是管道。
  2. 要求两个独立声明并加以佐证。一个来自提供方,不可伪造但描述不足。一个来自你的控制平面,描述充分且可重放。信任两者的交集,绝不单独信任任一方。
  3. 保持签名者稀缺。如果恰好只有一个服务能做出平台的声明,你的信任叙事就能用一句话说清。
  4. 钩住你仍然拥有的那一层。在托管计算上,你很少能控制主机或其 init 系统,但你几乎总能控制运行时:一个插件、一个代理、一个入口点。证明就属于那里。
  5. 有意识地决定放大量政策。分布式引擎会把每个进程操作乘以其并行度。
  6. 让证明可重复,让凭证短期化。续期是一项要求,而不是后续事项。

使结果值得信赖的是,没有任何单一参与者独自签发身份。不是工作负载,不是控制平面,也不是提供方。而工作负载——最不适合被信任的一方——永远不会被要求为自己担保。

致谢

感谢 Amer Hesson 提出 Data Project 抽象,Nick Siow 实现 Data Project IAM 角色分片,以及 Doug Clark 实现 Metatron 证明。

用你自己的身份体系替代云身份:托管计算上的工作负载证明最初发表于 Netflix TechBlog 在 Medium 上,人们在那里通过高亮和回应继续讨论这个故事。

这篇内容对你有用吗?

反馈只用于改善内容筛选,不等同于收藏

分享这条资讯
分享海报
保存图片
iOS 也可以长按图片保存