本章探讨了 SPIFFE 和 SPIRE 如何与环境集成。
SPIFFE 从一开始就被设计成可插拔和可扩展的,所以将 SPIFFE 和 SPIRE 与其他软件系统集成的话题是一个广泛的话题。一个特定的集成的架构超出了本书的范围。相反,本章意在捕捉一些可能的常见集成,以及一个高层次的概述,以及进行集成工作的策略。
使软件能够使用 SVID
在考虑如何调整软件以使用 SVID 时,有许多选项可供选择。本节介绍了其中的几个选项,以及与之相关的注意事项。
本地 SPIFFE 支持
这种方法需要修改现有的服务,以使它们能够感知 SPIFFE。当所需的修改最小,或者可以在跨应用服务使用的通用库或框架中引入时,它是首选。对于那些对延迟敏感的数据平面服务,或希望在应用层利用身份的服务,本地集成是最好的方法。SPIFFE 提供了一些库,如用于 Go 编程语言的 GO-SPIFFE 和用于 Java 编程语言的 JAVA-SPIFFE,它们有助于开发支持 SPIFFE 的工作负载。
当用支持 SPIFFE 库的语言构建软件时,这通常是利用 SPIFFE 最直接的方式。上面提到的 Go 和 Java 库有使用 SPIFFE 与 gRPC 和 HTTPS 客户端和服务器的例子。
也就是说,应该注意的是,你并不局限于 Java 和 Go 语言的选择。这些库是在开放规范的基础上实现的。在撰写本文时,社区正在努力开发 Python、Rust 和 C 编程语言的 SPIFFE 库。
SPIFFE 感知代理
通常情况下,重构的成本太高,或者服务正在运行一个不能被修改的第三方代码。在这些情况下,用一个支持 SPIFFE 的代理来前置应用,往往是一个务实的选择。根据应用程序的部署模式,它可以是一个独立的代理或一组集中的代理。共用代理的优点是代理和不安全的服务之间的追踪仍然是本地的 —— 如果使用独立的代理,代理和应用之间的安全问题仍然必须得到考虑。
Envoy 是一个受欢迎的选择,Ghostunnel 是另一个不错的选择。虽然其他代理,如 NGINX 和 Apache 也可以工作,但它们与 SPIFFE 相关的功能是有限的。
Ghostunnel 是一个 L3/L4 代理,享有对整个 SPIFFE 规范集的完全本地支持,包括对 SPIFFE Workload API 和联邦的支持。对于需要 L7 功能的应用,建议使用 Envoy。虽然 Envoy 不支持 SPIFFE Workload API,但 SPIRE 实现了 Secret Discovery Service API(或 SDS API),这是一个 Envoy API,用于检索和维护证书和私钥。
通过实施 SDS API,SPIRE 可以将 TLS 证书、私钥和可信 CA 证书直接推送到 Envoy。然后,SPIRE 会根据需要轮换短命的秘钥和证书,将更新推送到 Envoy,而不需要重新启动。
服务网格
L7 代理(如 Envoy)可以执行 SPIFFE 安全以上的许多功能。例如,服务发现、请求授权和负载均衡都是 Envoy 带来的功能。在使用共享库比较困难的环境中(例如,当应用程序是用许多不同的语言编写的,或者不能被修改),将这种功能加载到代理上,可能特别有吸引力。这种方法也将代理的部署推向了集中的模式,即每个应用实例都有一个专门的代理运行在它旁边。
然而,这又产生了一个问题:如何管理所有这些代理?
服务网格是一个代理机群和相关代理控制平面的部署。它们通常允许在部署工作负载时自动注入和配置集中的代理,并提供对这些代理的持续管理。通过将许多平台关注点加载到服务网格中,可以使应用程序与这些功能不相干。
迄今为止,大多数服务网格的实现都是利用 SPIFFE 认证来实现服务间的追踪。有些使用 SPIRE 来实现这一目标,有些则实现了特定产品的 SPIFFE 身份提供者。
辅助程序
于工作负载不支持 SPIFFE 工作负载 API,但仍然支持使用证书进行认证的情况,与工作负载一起运行的辅助程序可以弥补这一差距。SPIFFE Helper 就是一个例子。SPIFFE 辅助程序从 SPIFFE Workload API 中获取 SVID,并将其写入磁盘,以便应用程序能够接收它们。SPIFFE 辅助程序可以继续运行,确保磁盘上的证书在轮换时不断地被更新。当更新发生时,辅助程序可以向应用程序发出信号(或运行一个可配置的命令),这样,运行中的应用程序就可以接收到这些变化。
许多支持 TLS 的现成的应用程序可以被配置成这样使用 SPIFFE。SPIFFE 辅助库有配置 MySQL 和 PostgreSQL 的例子。许多 Web 服务器,如 Apache HTTPD 和 NGINX 都可以进行类似的配置。这对客户端软件也很有用,它只能被配置为利用磁盘上的证书。
- openssl
- x509curl
- grpcurl
需要注意的是,这比本地 SPIFFE 集成的灵活性要低,因为特别是,它可能不允许相同的信任配置粒度。例如,当使用 SPIFFE Helper 来配置 Apache HTTPD 的相互 TLS 时,不可能将 mod_ssl
配置为只接受具有特定 SPIFFE ID 的客户端。
在无 SPIFFE 感知的软件中使用 SVID
由于 SVID 是基于众所周知的文档类型,所以相对来说,遇到支持文档类型的软件是很常见的,但其本身并不一定能识别 SPIFFE。好消息是,这是一个相对预期的情况,而且 SPIFFE/SPIRE 已经被设计成可以很好地处理这种情况。
X509-SVID 双重用途
许多非 SPIFFE 系统支持使用 TLS(或相互 TLS),但依赖于证书在证书主体的通用名称(CN)或主体替代名称(SAN)扩展的 DNS 名称中具有身份信息。SPIRE 支持签发具有特定 CN 和 DNS SAN 值的 X.509 证书,这些值可以在每个工作负载的基础上指定(作为注册条目的一部分)。
这一功能是一个重要的细节,因为它允许在不直接理解如何使用 SPIFFE ID 的软件中使用 X509-SVID。例如,HTTPS 客户端往往希望所出示的证书与请求的 DNS 名称相匹配。在另一个例子中,MySQL 和 PostgreSQL 可以使用通用名称来识别相互的 TLS 客户端。通过利用这个 SPIRE 功能,以及 SPIFFE 总体上赋予的灵活性,这些用例可以用 SPIFFE 用例所使用的同样的 SVID 来适应。
JWT-SVID 双重用途
与 X509-SVID 可用于 SPIFFE 认证以及更传统的 X.509 用例的方式相似,JWT- SVID 也支持这种双重性。虽然 JWT-SVID 确实使用标准的主体(sub
)声明来存储 SPIFFE ID,但验证方法与 OpenID Connect(或 OIDC)类似并兼容。
更具体地说,SPIFFE Federation API 通过由 HTTPS 端点提供的 JWKS 文档公开密钥,这与用于获取 OIDC 验证的公开密钥的机制相同。因此,任何支持 OIDC 身份联盟的技术也将支持接受 JWT-SVID,无论它们是否具有 SPIFFE 感知。
支持这种身份联盟的集成的一个例子是亚马逊网络服务(AWS)身份和访问管理(IAM)。通过配置 AWS 账户中的 IAM,以接受来自 SPIRE 作为 OIDC 身份供应商的身份,就有可能使用 SPIFFE 工作负载 API 的 JWT-SVID 来承担 AWS IAM 的角色。当需要访问 AWS 资源的工作负载不在 AWS 中运行时,这一点特别强大,有效地否定了存储、共享和管理长期的 AWS 访问密钥的需要。关于如何实现这一目标的详细例子,请参见 SPIFFE 网站上的 AWS OIDC 认证教程。
可以在 SPIFFE 的基础上建立什么
一旦 SPIFFE 作为一个通用的身份基础存在于你的生态系统中,并与你的应用程序集成,这可能是一个考虑在上面建立什么的好时机。在本节中,我们想介绍一下在 SPIFFE 和 SPIRE 的基础上可以建立什么。并不是说这个项目有所有的构件,可以让一切都开箱即用。有些集成件需要实施才能实现,而具体如何实现的细节会因部署而异。
日志、监测、可观测性和 SPIFFE
SPIFFE 可以向其他系统提供可验证的身份证明,这对以下组件来说是一个优势:
- 基础设施度量
- 基础设施日志
- 可观测性
- 计量
- 分布式追踪
你可以使用 SVID 来确保这些系统的客户端 - 服务器通信安全。然而,你也可以扩展所有这些组件,用 SPIFFE ID 来充实数据。这样做有多种好处,例如,能够在多种类型的平台和运行时之间对事件进行关联。它甚至可以帮助识别仍然不使用 SPIFFE 身份的应用和服务,或者发现运行异常和攻击,而不管它们可能发生在基础设施的哪个角落。
审计
对于任何安全系统,如你在 SPIRE 基础上建立的系统,日志不仅仅是帮助开发人员和操作员了解系统发生了什么的信息。任何安全系统的日志都是正在发生的事情的证据,所以有一个集中的位置来存储日志是一个好主意。在发生任何安全事件时,这些信息对取证分析非常有价值。
SPIFFE 可以帮助增强审计数据,通过使用对集中式审计系统的认证调用来提供不可抵赖性。例如,在与审计系统建立会话时,通过使用 X509-SVID 和相互 TLS,我们可以确定日志行的来源 —— 攻击者不能简单地操纵正在发送的标签或其他数据。
证书透明化
证书透明化(Certificate Transparency)通过提供一个开放的框架,几乎实时地监控和审计 X.509 证书,帮助发现对证书基础设施的攻击。证书透明化允许检测从被破坏的证书颁发机构恶意获取的证书。它还可以识别那些已经变质并恶意签发证书的证书颁发机构。要了解更多关于证书透明化的信息,请阅读介绍文件。
SPIRE 与证书透明度的整合有不同的可能性。通过这种整合,可以记录你的系统颁发的所有证书的信息,并用一种称为 Merkle Tree Hashes 的特殊加密机制来保护它,以防止篡改和不当行为。
你可以考虑的另一个方法是在你的所有系统中强制执行证书透明化。这将防止与那些没有在证书透明化服务器中记录证书信息的应用程序和服务建立 TLS 和相互 TLS 连接。
与证书透明化的整合已经超出了本书的范围。请查看 SPIFFE/SPIRE 社区,了解更多信息和最新更新。
供应链安全
大部分关于 SPIFFE 预期用途的报道都是关于在运行时保护软件系统之间的通信安全。然而,在软件部署前的各个阶段保护软件也是至关重要的。供应链妥协是一个潜在的攻击媒介。为此,最好能保护软件供应链的完整性,以防止恶意行为者在代码中引入后门或脆弱的库。验证软件工件的出处和管道中执行的一系列步骤是验证软件没有被篡改的一种方式。
你可以考虑使用 SPIFFE 来提供签名的信任根。它也可用于向供应链系统的软件组件发放身份。有几种方法可以让它与更新框架(TUF)等补充软件或公证处等人工制品签署服务一起工作,或者与 In-Toto 等供应链日志一起利用。
有可能在两个层面上将 SPIRE 与供应链组件整合。
首先,你可以用它来识别这个供应链系统的不同元素,以确保机械和控制平面的安全。其次,通过定制选择器来确保只有已知出处的二进制文件被发出身份。作为后者的一个例子,在一个非常初级的水平上,这种属性可以作为标签传递到使用现有 docker 选择器的容器镜像中,或者通过开发一个可以检查供应链元数据的工作负载验证器。
为用户集成 SPIFFE
SPIFFE 和 SPIRE 架构的主要重点是软件身份。它没有考虑到用户的身份,因为这个问题已经被认为得到了很好的解决,而且在如何向人类与软件发放身份方面存在重大差异。也就是说,这并不意味着你不能向用户分发 SPIFFE 的身份。
为用户提供可验证的身份
用户应该如何在一个支持 SPIFFE 的生态系统中交互?请记住,SPIFFE 是 Secure Production Identity Framework for Everyone 的缩写。虽然本书的大部分内容都集中在软件的身份上,但将 SPIFFE 可验证的身份(SVID)赋予用户也同样有效,甚至是可取的。这样一来,工作负载可以用 SVID 做的所有事情,人们也可以做,比如相互 TLS 访问服务。这对于正在构建软件并需要访问其软件部署后将使用的相同资源的开发者来说,可能特别有用。
正如 SPIFFE 规范对 SPIFFE ID 的方案没有限制一样,你可以自行决定如何表示人类。把你的用户名作为 SPIFFE ID 路径可能就足够了,例如 spiffe://example.com/users/zero_the_turtle
。或者,你可以为用户与工作负载创建一个不同的信任域,例如 spiffe://users.example.com/zero_the_turtle
。
在一个理想的情况下,你现有的 SSO 提供商能够为你的用户产生 JWT,就像 OIDC 身份提供商的情况一样。在这种情况下,如果你能将你的 SSO 提供商配置为使用 SPIFFE ID 来进行 sub
声明,你可能不需要做任何额外的工作来为你的用户产生 SVID。
如果你无法直接从你的身份提供者那里获得 SPIFFE JWT,但你有办法获得可验证的身份令牌,你可以利用一个自定义的 SPIRE 验证器,接受来自你的提供者的身份令牌作为基本的证明手段。
如果上述情况都不适用,你总是可以建立一个独特的服务,集成到你现有的 SSO 解决方案中,它可以根据用户的认证会话为他们产生 SVID。请查看 SPIFFE 网站上的示例项目。
利用 SSH 使用 SPIFFE 和 SPIRE
OpenSSH 支持使用证书颁发机构(CA)和证书进行认证。尽管 OpenSSH 证书的格式与 X.509 不同,但人们可以建立一个使用 SVID 作为认证的 SSH 证书的服务。这使得你也可以利用你的 SPIFFE 身份进行 SSH。
对于需要 SSH 访问你的生态系统中的工作负载的用户来说,这种模式为 SSH 访问提供了短暂的、短期的、可审计的凭证,也提供了一个单一的控制点,你可以用它来执行访问控制策略或多因素认证。
这也允许工作负载检索服务器端(又称 “主机”)的 SSH 证书,允许工作负载向用户认证自己。使用这个证书,用户不再需要在第一次连接时被信任服务器的主机密钥的问题打断 SSH 连接。
微服务 UI
虽然本书的大部分内容都是关于工作负载之间的认证,但通常也需要用户对工作负载进行认证。如果用户是通过 CLI 或其他桌面工具进行认证,那么可以使用带有用户 SVID 的相互 TLS。然而,许多微服务也希望承载某种基于浏览器的用户界面。这可能是因为开发者正在为他们的服务访问一个专门的管理或管理界面,或者消费者可能正在使用像 Swagger UI 这样的工具来探索和试验服务的 API。
为具有基于浏览器的用户界面的服务提供良好的体验,需要在浏览器友好的认证形式和 SPIFFE 相互 TLS 认证之间架起桥梁。实现这一目标的最简单方法是有一个使用相互 TLS 的 API 端口和另一个接受浏览器友好认证方法的 API 端口,如现有的基于 Web 的 SSO 机制或 OAuth2/OIDC。
对二级端口上的请求进行认证后过滤,应该在基于浏览器的认证主体和相应的 SPIFFE ID 之间提供一个转换层。如果你已经建立了一个机制让用户直接获得 SVID,如上所述,那么这里也应该使用同样的转换。这样一来,底层应用就与所使用的特定认证机制无关了,所以由某个用户提出的基于网络的请求在功能上等同于通过相互 TLS 使用该用户的 SVID 提出的相同请求。