Skip to content

本文为 SPIFFE 官方规范 The SPIFFE Identity and Verifiable Identity Document 的中文译本,仅供学习参考;若与英文原文有出入,以英文版为准。

SPIFFE 身份与可验证身份文档 ​

稳定性:稳定(Stable) - 参见 STABILITY.md。

本备忘录的状态 ​

本文档为互联网社区规定了一项身份及身份签发标准,并征求各方的讨论与改进建议。本文档的分发不受限制。

摘要 ​

SPIFFE 标准提供了一份规范,用于描述一种能够跨异构环境与组织边界为服务引导(bootstrap)并签发身份的框架。它涵盖了多份规范,每份规范都定义了 SPIFFE 某一特定功能子集的运作方式。

本文档尤其充当着 SPIFFE 标准的核心规范。尽管在 SPIFFE 旗下还有其他规范,但符合本文档即足以达成 SPIFFE 合规性,并获得 SPIFFE 标准本身所带来的互操作性收益。

有关 SPIFFE 的更多概括性信息,请参阅 面向所有人的生产环境安全身份框架(SPIFFE) 标准。

1. 引言 ​

本文档阐述了官方的 SPIFFE 规范。它定义了 SPIFFE 标准中最基础的两个组件:SPIFFE 身份与 SPIFFE 可验证身份文档。

第 2 节概述了 SPIFFE 身份(SPIFFE ID)及其命名空间。SPIFFE ID 是一个用于标识资源或调用方的结构化字符串,是 SPIFFE 标准的基石。所有其他 SPIFFE 组件都聚焦于 SPIFFE ID 本身的签发与验证。

第 3 节描述了 SPIFFE 可验证身份文档(即 SVID)。SVID 是一种机制,计算端点可借助它以一种可通过密码学验证并被认定为可信的方式来呈现自己的 SPIFFE ID。SVID 可以引用一个与之关联的非对称密钥对,因此还可用于构建安全通信信道。

就 SPIFFE 合规性而言,符合本文档即已足够。

2. SPIFFE 身份 ​

为了传达一个身份,我们必须首先定义一个身份命名空间。SPIFFE 身份(即 SPIFFE ID)被定义为一个符合 RFC 3986 的 URI,由一个“信任域名称(trust domain name)”和一个与之关联的路径构成。信任域名称充当 URI 的 authority(授权)组件,用于标识签发某一给定身份的系统。以下示例演示了 SPIFFE ID 的构造方式:

spiffe://trust-domain-name/path

有效的 SPIFFE ID 必须(MUST)将 scheme 设为 spiffe,必须包含一个非零长度的信任域名称,并且禁止(MUST NOT)包含查询(query)或片段(fragment)组件。换言之,一个 SPIFFE ID 完全由 spiffe scheme 以及一个站点特定的 hier-part(其中包含一个 authority 组件和一个可选路径)所定义。

2.1. 信任域 ​

信任域对应于一个系统的信任根(trust root)。一个信任域可以代表运行着自己独立 SPIFFE 基础设施的个人、组织、环境或部门。

信任域名称名义上是自行注册的;与公共 DNS 不同,这里没有一个委派机构(delegating authority)去负责将某个基础域名断言并注册给现实世界中某个真实的法律实体,也不会去断言该法律实体对任何特定信任域名称拥有公平且应有的权利。

信任域名称被定义为 URI 的 authority 组件,并施加以下限制:

  • authority 的 host 部分禁止(MUST NOT)为空。
  • authority 组件的 userinfo 与 port 部分必须(MUST)为空。
  • authority 的 host 部分必须为小写。
  • authority 的 host 部分必须仅包含字母、数字、点、连字符和下划线([a-z0-9.-_])。
  • authority 的 host 部分禁止包含百分号编码(percent-encoded)字符。

请注意,此定义并不排除点分四段(dotted-quad)记法的 IPv4 地址,但确实排除了 IPv6 地址。DNS 名称是有效信任域名称的一个严格子集。无论信任域名称是否为有效的 IP 地址和/或有效的 DNS 名称,实现都禁止(MUST NOT)对其进行区别处理。

2.1.1. 信任域名称冲突 ​

信任域运营者可以自由选择他们认为合适的任意信任域名称:并不存在对信任域名称进行监管或注册的中心化机构。因此,既无法保证全局唯一性,也没有任何技术手段能够阻止不同的信任域使用完全相同的信任域名称。

为防止意外冲突(两个信任域选取了完全相同的名称),建议运营者选择极有可能全局唯一的信任域名称。尽管信任域名称并非 DNS 名称,但在条件允许时,将一个已注册的域名用作信任域名称的后缀,将会降低意外冲突的概率;例如,如果某信任域运营者拥有域名 example.com,那么使用诸如 trust_domain_name.example.com 这样的信任域名称,很可能就不会产生冲突。当信任域名称在没有运营者输入的情况下自动生成时,强烈建议随机生成一个唯一名称(例如 UUID)。

当冲突确实发生时,这些信任域仍将各自独立运作,但将无法进行联邦(即相互连接)。由于每个信任域都使用各自唯一的密码学信任根,由某一信任域签发的身份声明将在另一信任域中验证失败。有关 SPIFFE 认证的更多细节,请参见 第 3.1 节。

2.2. 路径 ​

SPIFFE ID 的路径组件用于对某一给定工作负载进行唯一标识。路径背后的含义是开放的,由管理员负责定义。

有效的 SPIFFE ID 路径组件需遵守以下规则:

  • 路径组件禁止(MUST NOT)包含百分号编码字符。
  • 路径组件禁止包含空段或相对路径修饰符(即 .、..)。
  • 路径组件禁止以尾随的 / 结尾。
  • 各个路径段必须(MUST)仅包含字母、数字、点、连字符和下划线([a-zA-Z0-9.-_])。

路径可以(MAY)是分层的——类似于文件系统路径。路径的具体含义留给实现者自行处理,不在 SVID 规范的范围之内。下面给出一些示例与约定。

  • 直接标识服务

    直接标识服务往往很有价值。例如,管理员可以规定:运行在某一特定节点集合上的任何进程都应能够将自己呈现为某个特定身份。例如:

    spiffe://staging.example.com/payments/mysql 或 spiffe://staging.example.com/payments/web-fe

    上述两个 SPIFFE ID 指代运行在预演(staging)环境中的某个支付服务的两个不同组件——mysql 数据库服务和一个 Web 前端。将“staging”作为一个环境、将“payments”作为一个高层服务集合的含义,由实现者自行定义。

  • 标识服务所有者

    更高层的编排器与平台往往内建了自己的身份概念(例如 Kubernetes 服务账户,或 AWS/GCP 服务账户),而能够将 SPIFFE 身份直接映射到这些身份上会很有帮助。例如:

    spiffe://k8s-west.example.com/ns/staging/sa/default

    在此示例中,example.com 的管理员运行着一个 Kubernetes 集群 k8s-west.example.com,该集群有一个“staging”命名空间,其中有一个名为“default”的服务账户(sa)。这些都是由 SPIFFE 管理员定义的约定,而非本规范所保证的断言。

  • 不透明的 SPIFFE 身份

    上述示例仅作说明之用;在最一般的情况下,SPIFFE 路径可以保持不透明,不携带任何可见的分层信息。诸如地理位置、逻辑系统分区和/或服务名称等元数据,可以由一个次级系统提供,身份及其属性都注册在该系统中。可以查询该系统以检索与该 SPIFFE 标识符关联的任何元数据。例如:

    spiffe://example.com/9eebccd2-12bf-40a6-b262-65fe0487d453

2.3. SPIFFE ID 的最大长度 ​

根据 RFC 3986 的定义,URI 没有最大长度限制。出于互操作性考虑,SPIFFE 实现必须(MUST)支持长度不超过 2048 字节的 SPIFFE URI,并且不应(SHOULD NOT)生成长度超过 2048 字节的 URI。RFC 3986 仅允许 ASCII 字符,因此 SPIFFE ID 的推荐最大长度为 2048 字节。

所有 URI 组件都会计入 URI 长度,包括 “spiffe” scheme、“😕/” 分隔符、信任域名称以及路径组件。请注意,RFC 3986 为 URI 的 “host” 组件定义了 255 个字符的最大长度;因此,信任域名称的最大长度为 255 字节。

2.4. SPIFFE ID 解析 ​

SPIFFE ID 遵循 RFC 3986 所定义的 URI 规范。SPIFFE ID 的 scheme 与信任域名称不区分大小写;路径则区分大小写。

3. SPIFFE 可验证身份文档 ​

SPIFFE 可验证身份文档(SVID)是工作负载向资源或调用方传达其身份所借助的机制。如果一个 SVID 已由该 SPIFFE ID 所属信任域内的某个权威机构(authority)签名,则该 SVID 被视为有效。

3.1. SVID 信任 ​

正如第 2.1 节所述,SPIFFE 的信任植根于某一给定 ID 所属的信任域。每个信任域中都必须(MUST)存在一个签名权威机构(signing authority),且该签名权威机构必须持有其自身的 SVID。签名权威机构的 SPIFFE ID 应当(SHOULD)位于其作为权威的那个信任域中,并且不应(SHOULD NOT)带有路径组件。签名权威机构的 SVID 随即构成某一给定信任域的信任基础。

如有需要,可以通过使用某个外部信任域的权威机构的私钥来对本权威机构的 SVID 进行签名,从而实现信任的链式串联。如果不进行信任的链式串联,则该权威机构的 SVID 为自签名(self-signed)。

3.2. SVID 组成部分 ​

SVID 是一个相当简单的构造,由三个基本组成部分构成:

  • 一个 SPIFFE ID
  • 一个有效的签名
  • 一个可选的公钥

SPIFFE ID 和公钥(如果存在)必须(MUST)包含在负载(payload)中被签名的那一部分内。如果包含了公钥,则相应的私钥由 SVID 所签发给的实体保留,并用于证明对该 SVID 本身的所有权。

各个 SVID 规范可以(MAY)要求或以其他方式允许在 SVID 中包含超出此处所述范围的信息。所包含信息的性质可能会、也可能不会被相关 SPIFFE 规范严格定义——例如,JWT-SVID 规范允许用户在 SVID 本身内部包含任意信息。在相关 SVID 规范并未明确规定此类附加信息的情况下,运营者在将这些信息用作安全决策的输入时应保持谨慎,尤其当被验证的 SVID 属于另一个信任域时。更多信息请参阅安全考量一节。

3.3. SVID 格式 ​

SVID 本身并不是一种文档类型。已经存在许多能够满足 SPIFFE SVID 需求的文档格式,而我们并不希望重新发明这些格式。相反,我们定义了一组特定于格式的规范,用以标准化 SVID 信息的编码方式。

为使一个 SVID 被视为有效,它必须(MUST)采用某种已定义相应规范的文档类型。目前已定义以下文档类型:

请注意,特定于格式的 SVID 规范可以在本文档所设定要求的基础上作出更为严格的规定(upgrade)。

4. 安全考量 ​

本节列出了实现者与用户在使用 SPIFFE ID 和 SVID 时应予以考虑的安全事项。

4.1. SVID 断言 ​

SVID 内部始终携带着一组数据——至少包含一个 SPIFFE ID。有时,这些数据代表着信任域权威机构针对该 SVID 主体(subject)所作出的断言。在从这些数据中解读含义时,必须谨慎行事,以确保所有相关方都充分理解所使用信息的含义与重要性。

在考量任何给定断言的相对安全性时,存在四大关切点。第一是时间准确性(temporal accuracy)——SVID 在过期之前会有效一段时间,那么 SVID 中的断言在该 SVID 的整个生命周期内是否都为真?第二是断言的范围与影响(scope and influence)——该断言最初是在何种上下文下作出的,其影响又应波及多远?第三是解读与含义(interpretation and meaning)的问题——该断言对权威机构和消费者而言是否具有相同的含义,还是存在产生歧义解读的空间?最后,在某些情况下,断言本身的真实性(veracity)也可能受到质疑。

本节将探讨上述全部四个关切领域,并提供一些准则,供运营者据以评估任何给定 SVID 断言的相对安全性。一般而言,运营者应保持审慎,仅纳入那些对其安全性有着极高信心的断言。

应当指出的是,虽然由 SPIFFE 规范直接形式化定义的断言通常不易受到解读与含义相关问题的影响,但它们仍可能受到真实性相关问题的影响。然而,由于 SPIFFE 所定义断言具有严格限定范围的特性,此方面的真实性顾虑往往意味着围绕相关信任域安全态势的更为重大的隐忧;到了这一地步,运营者就应当认真反思,究竟是否一开始就该与这些系统交换数据。

4.1.1. 时间准确性 ​

SVID 的有效期是有限的,其主要目的在于降低密钥泄露的可能性以及与之相关的损害。虽然通常情况下 SVID 中的断言在签发时为真,但这并不必然意味着它们在使用时也为真。

某些类型的断言比其他类型更容易受到此问题的影响。服务所有者的名称、角色或组成员身份、以及访问策略,都属于在 SVID 签发时刻与验证或使用时刻之间更有可能发生变化的断言的例子。相比之下,工作负载及其运行时的天然属性(例如 SPIFFE ID,或工作负载所运行的区域)通常与工作负载的生命周期绑定,因而不太可能发生变化,这意味着它们较少受到时间准确性问题的影响。

在决定某个断言是否应被纳入 SVID 时,考虑这一点非常重要。SVID 中作出的断言在该 SVID 的整个生命周期内都将被视为有效,而在一个运行中的系统上对该断言进行变更(或撤销)将会是一个漫长的过程,因为所有携带旧断言的 SVID 都必须先行过期。如果对相关断言的易变性不甚明确,运营者应保持审慎,将其排除在 SVID 之外。

4.1.2. 范围与影响 ​

SVID 由其所在信任域中的一个权威机构签名。验证其所签名 SVID 中的全部信息是签名权威机构的职责,而 SVID 中所包含的断言实际上就是由该签名权威机构作出的断言。

该权威机构的影响力,以及它所作断言的范围,天然是受限的。一个信任域的权威机构不应针对其他信任域中的实体作出断言(即,其断言的范围仅限于其掌控之下的实体)。同样地,在消费 SVID 数据时,消费者应将其中所包含的全部断言都视为受该 SVID 所在信任域所限定(qualified)。

示例:如果信任域 A 和信任域 B 都使用一个名为“role”的属性,那么在信任域 A 中角色为“admin”的实体,并不能被认定为在信任域 B 的上下文中也是“admin”。

4.1.3. 解读 ​

出于灵活性考虑,大多数 SVID 规范都允许包含任意信息,而 SPIFFE 及其任何底层规范均未对这类信息的行为作出定义。一旦包含此类信息,不同各方对其语义的解读可能各不相同。正因如此,在 SVID 中包含并采信任意信息很难做到安全,但在审慎与用心之下仍是可行的。

当任意 SVID 信息被用作安全决策的一部分(例如是否允许某个请求或连接)时,至关重要的一点是:签发该 SVID 的权威机构与消费该 SVID 的实体对该信息具有相同的含义或解读。

认真考量究竟是谁在运营签发该 SVID 的权威机构,是明智之举。通过带外协调,信任域运营者之间也许能够就某一特定信息的含义达成一致。例如,如果某组织出于管理原因运营着多个信任域,那么在该组织内部就 SVID 信息的解读达成一致也许并不困难(即便该信息的性质并未被公开标准化)。然而,运营者应将对该数据的处理仅限于那些已就其含义达成一致的信任域;两个信任域运营者之间就含义达成的约定,不应自动延伸至所有信任域运营者。

示例:如果信任域 A 和信任域 B 就“environment”属性的含义达成了一致,该语义约定并不会延伸至信任域 C——后者也可能恰好包含一个同名为“environment”的属性。

4.1.4. 真实性 ​

与所消费 SVID 处于同一信任域的 SVID 消费者,通常可以假定该 SVID 中的断言为真,因为该消费者很可能认为签发此 SVID 的权威机构是完全受信任的。然而,这并不必然意味着:当形式与性质相似的断言源自另一个不同的信任域时,也可以假定其为真。

运营者应逐案审慎考量:在某个特定断言的上下文中,某个给定的外部权威机构是否应被视为可信。

举例来说,设想信任域 A 与信任域 B 的运营者拥有一位共同客户,且彼此存在业务关系。在信任域 A 的正常运作过程中,一个专门的进程对该客户进行认证,随后该信任域的权威机构创建一个 SVID,其中嵌入了一个表明该客户身份的断言。此进程的目的在于:通过证明该客户确实经过了认证并且的确发起了此请求,从而在信任域内某个中间服务遭到攻陷时,降低对客户数据的未授权访问风险。

现在再设想:信任域 A 中的存储服务收到了一个针对该客户数据的请求,只不过调用方出示的是一个来自信任域 B 的 SVID。即便所出示的 SVID 可能带有必要的断言,表明这位共同客户已通过认证并授权了此请求,但盲目假定信任域 B 确实认证过你的客户仍是不明智的。如果信任域 B 遭到攻陷,或者其内部存在恶意行为者,它就可以声称已认证任何它想要认证的用户,从而恰恰造成了这项措施当初旨在防范的那种情形。