第 3 章 身份背后的通用概念
原书:Chapter 3. General Concepts Behind Identity(p.38–51) 翻译策略:技术直译 + 段落重排;专有项目名、协议名、API 名、CLI 命令、配置字段、证书/加密术语一律保留英文;首次出现的关键概念以"中文(English)"形式给出,后续沿用英文。术语对照见
TERMS.md。
章节导言
本章解释"身份"是什么,以及身份的分发、管理与使用的基本概念。这些是理解 SPIFFE 和 SPIRE 工作原理的基础。
什么是身份?
对人类来说,身份很复杂。每个人都是独特的个体,无法被克隆、不能被"换一段代码替代",而且一生中还可能拥有多个社会身份。软件服务同样复杂。
一个程序可能扩缩到上千个节点,也可能因构建系统推送新版本而一天之内多次变更代码。在这种快速变化的环境里,身份必须能代表该服务的特定逻辑用途(例如"客户计费数据库"),并且要把它与某个权威或信任根(root of trust)关联起来(比如 my-company.example.org,或者你的生产工作负载所属的签发机构)。
一旦为组织里的所有服务签发了身份,这些身份就可以用于认证:证明一个服务就是它声称的那个服务。服务之间能够相互认证后,就能用这些身份去做授权——控制谁能访问这些服务,以及保密性(confidentiality)——保证它们之间传输的数据不外泄。SPIFFE 自身并不包含认证、授权、保密这些功能,但它签发的身份可以被用于这些目的。
为组织设计服务身份,与设计组织基础设施的其他部分类似:它紧密依赖组织的具体需求。当一个服务扩缩、变更代码或迁移位置时,逻辑上它可能应该保持同一个身份。
值得信赖的身份
既然我们已经定义了"身份",那如何表示这个身份呢?我们又怎么知道:当一个软件(或工作负载)声明自己的身份时,这个声明是值得信赖的?要开始探索这些问题,我们必须先讨论身份是如何被建立起来的。
人类的身份
让我们用一个大家都熟悉的东西来解释这些概念:现实世界中的身份。
身份文档
如果"姓名"是一个人的身份,那么对该身份的证明就是身份文档(identity document)。护照就是一种允许个人证明自己身份的文件,所以它就是一份身份文档。不同国家签发的护照看起来都不一样,承载的信息也不见得总是一样。但要"有用",它们至少都得包含一些公共信息,比如"姓名"。
那么"护照"和"在餐巾纸上随手写了你名字的纸巾"有什么区别?
图 3.1 Bob 向 CA 申请证书并用其向 Alice 证明身份的示意图(见
assets/pages/page-043.png)。
最大的差别在来源。对护照,我们信任签发机构(Issuing Authority)已经核验过你的身份,并且我们能够验证这本护照就是那个可信机构签发的(这就是"验证 / validation")。对那张餐巾纸,我们不知道它从哪来,也没办法验证它来自你声称的那家餐厅。我们同样不能相信那家餐厅写对了你的名字,或者在你报出名字时核验过。
信任签发机构
我们之所以信任护照,是因为我们隐含地信任签发护照的那个机构。我们信任它签发身份文档的整套流程:他们有记录、有控制,确保只把身份签发给正确的个体。我们信任这个流程的治理,所以由该机构签发的护照能被视为对某人身份的"忠实表达"。
验证身份文档
有了这些,我们怎么区分一本真护照和一本假护照?这就是验证(verification)登场的地方。组织需要一种办法来判断"这份身份文档是不是由我们信任的那个机构签发的"。这通常借助"难复制、易验证"的水印来完成。
认证"拿着身份文档的这个人"
护照把关于"被代表的那个人"的多项信息编码在内。首先,它包含一张照片,可以用来验证"出示护照的人"与"护照上可见的人"是同一个人。它还可能包含这个人其他的物理特征——比如身高、体重、虹膜颜色等。
关键洞察:所有这些属性都可以用来认证一个出示护照的人。
简单回顾一下:护照就是我们的身份文档,我们之所以用它来互相识别,是因为我们信任签发机构,并且我们能验证这份文档就是来自该机构。最后,我们通过"护照上记录的内容"与"持证人的物理特征"做交叉比对,从而认证出示护照的人。
数字世界中的身份:加密身份
回到工作负载身份的话题:上面这些概念如何映射到计算机系统?这里用的是数字身份文档(Digital Identity Document)。X.509 证书、签名的 JSON Web Token(JWT)、Kerberos ticket,都是数字身份文档的例子。数字身份文档可以用密码学技术进行验证。随后,计算机系统就可以像"拿着护照的真人"一样被认证。
最常用也最有用的技术之一就是公钥基础设施(Public Key Infrastructure,PKI)。PKI 的定义是:用于创建、管理、分发、使用、存储、撤销数字证书并管理公钥加密所需的一组角色、策略、硬件、软件与流程。借助 PKI,数字身份文档可以离线、本地地与一个小型、静态的根信任包(root trust bundle)做校验。
X.509 简述
1988 年,国际电信联盟电信标准化部门(ITU-T,参考 www.itu.int/en/ITU-T/about)首次发布用于 PKI 的 X.509 标准时,它当时的雄心就已经令人惊叹——到今天也依然如此。最初的标准设想把证书发放给人类、服务器和各种设备,构建一个庞大的、全球集成的安全通信系统。尽管 X.509 始终没有达到最初设想的那种范围,但它已经成为几乎所有安全通信协议的事实基础。
图 3.2 PKI "一图流"(见
assets/pages/page-043.png)。
X.509 与"单一 CA"的工作方式
- Bob 的电脑需要一张证书。 他生成一个随机的私钥,并生成一个证书签名请求(Certificate Signing Request,CSR)——里面包含他电脑的基础信息(比如名字
bobsbox)。CSR 有点像一份"护照申请表"。 - Bob 把 CSR 发送给证书颁发机构(Certificate Authority,CA)。 CA 验证"Bob 真的是 Bob"。具体怎么验证要看场景——可能需要人工核对 Bob 的文件,也可能是一个自动化的检查。
- CA 用 CSR 里的信息生成一份证书,并加上自己的数字签名——这个签名就是 CA 在声明"我已核验其中信息为真"。CA 把证书发回给 Bob。
- Bob 想和 Alice 建立安全通信时,他的电脑可以出示这张证书,并用密码学方法证明自己拥有对应的私钥——但绝不需要把私钥内容告诉任何人。
- Alice 的电脑可以检查 Bob 的证书是不是真的是 Bob 的:通过检查这张证书是不是被那个她信任的 CA 签的。她相信 CA 在签发之前已妥善核验过 Bob 的身份。
图 3.3 中间 CA(intermediate CA)的示意图(见
assets/pages/page-044.png)。
带中间 CA 的 X.509
很多情况下,签发某张证书的 CA 并不是"广为人知"的 CA。它自己有自己的密钥和证书,而它的证书又是被另一个 CA 签的。父 CA 签发子 CA 的证书,就等于在宣告:"我授权这个下级 CA 去签发数字身份。"下级 CA 接受上级 CA 的授权这种机制,叫做委托(delegation)。
委托可以层层发生,下级 CA 继续把自己的权力下委托,从而形成一棵任意高度的 CA 树。最顶层的 CA 叫做根 CA(root CA),它的证书必须是众所周知的。链路中的其他 CA 都叫做中间 CA(intermediate CA)。这样做的好处是:需要被广泛知晓的密钥更少,对应的列表变动也少。
关键洞察:这也带来了 X.509 的一个关键弱点——任何 CA 都可以签发任何证书,没有任何限制。如果黑客自己起一个中间 CA,并能让任何一个现有中间 CA 同意签它,那么她实际上就能签出任意身份。所以"被广泛信任的 CA"以及"被它委托出去的中间 CA",每一个都必须完全可信。
证书与身份的生命周期
PKI 里有几项额外的特性,让数字身份的管理和认证更简单、更安全。授权委托、身份撤销、有限的文档寿命是其中几个。
身份签发
总有那么一个时点——一份新身份必须被签发出来。人类出生,新的软件服务被编写出来,在这些场景下,我们都要在一个"之前并不存在身份"的地方签发一个身份。
首先,服务要请求一份新身份。对人类来说,这可能是一张纸质表格。对软件来说,这是一份 X.509 文档,叫做证书签名请求(CSR)——它和一份证书类似,只不过它没被任何 CA 签过,所以没人会承认它有效。服务把 CSR 安全地发给 CA。
接着,CA 核对 CSR 里的每一项细节。最初这一步设计为人工过程:人工核对纸质材料、逐案决策。如今,核对与签发流程往往完全自动化。如果你用过 Let's Encrypt 这家广为人知的 CA,那你就已经熟悉了一种完全自动化的 CA 签发流程。
CA 满意之后,会把它的数字签名附加到 CSR 上,把它变成一份完整的证书,并把证书发回给服务。配合服务早先生成的私钥,就能安全地向外声明自己的身份。
证书撤销
那如果一个服务被入侵了呢?如果 Bob 的笔记本被黑了,或者 Bob 离职了、不应该再拥有访问权呢?
这种"撤销信任"的过程叫做证书撤销(Certificate Revocation)。CA 维护一份证书撤销列表(Certificate Revocation List,CRL)——里面是已撤销证书的唯一 ID,并把这份带签名的列表分发给任何请求它的人。
撤销这件事之所以棘手,有几个原因:
- CRL 必须托管在某个端点、并对外提供访问,这意味着要保证端点在线、可达。当它不可达时,PKI 是不是就该停止工作?实践中,大多数软件会"失败开放(fail open)"——在 CRL 不可达时依然信任证书——结果让 CRL 实际上失去了作用。
- CRL 可能变得又大又笨重。 一份被撤销的证书必须一直待在 CRL 里,直到它过期;而证书通常是长期有效的(数量级是年)。这会让 CRL 的服务、下载、处理出现性能问题。
为了让证书撤销更简单、更可靠,已经有多种不同的技术被开发出来,比如在线证书状态协议(Online Certificate Status Protocol,OCSP)。这些方案的丰富性,反而让证书撤销变成一个持续存在的挑战。
证书过期
每张证书都内置了一个过期时间。出于多种原因,过期时间对 X.509 的安全至关重要:管理陈旧、限制证书所代表身份发生变化的可能性、限制 CRL 的大小、降低密钥被盗的可能性。
证书已经存在很久了。早期很多 CA 使用 1989 年发布的 MD2 哈希算法,而该算法很快就被发现是不安全的。如果那些证书今天依然有效,攻击者就能伪造它们。
证书有限生命期的另一个重要维度:CA 只有一次机会去验证请求者的身份,但这些信息并不保证在时间推移下依然正确。比如,域名的归属经常变更,而它恰恰是证书里最关键的信息之一。
如果使用证书撤销列表,那么每一张仍然有效的证书都有可能被撤销。如果证书永远有效,那么 CRL 就会无限增长。要把 CRL 控制在小规模,证书必须过期。
最后,证书有效期越长,证书的私钥(或通向根的任意证书私钥)被盗的风险就越大。
频繁证书续期
应对"撤销"挑战的一个折衷方案,就是加重对过期的依赖。如果证书的生命期非常短(比如只有几个小时),那么 CA 就可以频繁地重新执行它原本做过的那些核验。如果证书续期足够频繁,
那么 CRL 或许根本就不需要了——等证书过期就行。
表 3.1 身份寿命的权衡(参考
assets/pages/page-048.png)
更短的寿命 更长的寿命 如果文档被偷,它只在一段更短的时间内是有效的(对人和程序都适用) CA 负载更小 CRL 更短,甚至可能不需要 网络负载更小 同时存在的有效身份文档更少(更易于跟踪) 当某节点因网络故障无法续期时,仍能撑更久
另一种加密身份:JWT
另一种基于公钥的身份文档——JSON Web Token(RFC 7519)——其行为也类似 PKI。它用 JSON token 替代证书,并且用一种叫做 JSON Web Key Set(JWKS) 的结构作为 CA Bundle 来认证这些 JSON token。证书与 JWT 之间的差异已经超出了本书的范围,不过和 X.509 证书一样,JWT 的真实性也可以用 PKI 验证。
外部身份的"可信度"
不管你用哪种身份,总得有一个可信机构来签发它。很多情况下,并不是所有人都信任同一个签发机构或它的签发流程。Alice 的纽约州驾照在纽约是有效身份证件,但到了伦敦就不算了——因为伦敦当局不信任纽约州政府。而 Bob 的美国护照在伦敦是有效的,因为英国当局信任美国政府,而伦敦当局信任英国当局。
数字身份文档的领域里情况完全一样。Alice 和 Bob 可能持有完全不同的 CA 签发的证书,但只要双方都信任各自的 CA,他们就能相互认证。
关键洞察:这并不意味着 Alice 必须"信任 Bob",只是说她能安全地识别他。
软件身份能用来做什么
一份软件拿到数字身份文档后,它就可以被用于多种用途。我们已经讨论过把身份文档用于认证。它们还可以被用于互信 TLS、授权、可观测性、计量。
认证
身份文档最常见的用途是作为认证的基础。对于软件身份,存在多种使用 X.509 证书或 JWT 来向对端证明服务身份的认证协议。
保密性与完整性
保密性指攻击者看不到消息内容;完整性指攻击者不能在传输过程中篡改消息。传输层安全性(TLS) 是一种广泛使用的安全连接协议,它在不可信网络连接之上、利用 X.509 证书同时提供认证、保密性和消息完整性。
TLS 的一项特性是:连接的任何一方都可以用证书进行认证。举个例子,当你连接到你银行的网站时,你的浏览器用银行出示的 X.509 证书认证了你的银行;而你的浏览器并不会给银行出示一张证书(你用用户名+密码登录,而不是用证书)。
授权
数字身份被认证后,就可以用来授权对服务的访问。典型情况下,每个服务都会维护一份白名单,列出"被允许对它发起请求的"其他服务。授权只能在认证之后进行。
当两段软件通信时,连接两端各持有一张 X.509 证书、互相认证彼此的情况很常见。这就是互信 TLS(mutually authenticated TLS,mTLS)。
可观测性
身份在提升组织基础设施可观测性方面也很有用。在大型组织里,"老旧或无人维护的服务以神秘、未经文档化的方式互相通信"这种事其实常见得令人惊讶。每个服务都有一份唯一的身份,配合可观测性工具就能解决这种问题。在日志方面,当后续出现问题时,"请求方不可抵赖的身份"会非常有用。
计量(Metering)
在微服务架构里,一个常见需求是对请求做限流,避免一个快的微服务压垮一个慢的。如果每个微服务都有一份唯一的身份,就可以基于它来管理每秒请求配额,或者干脆拒绝访问。
小结
人类和软件片段都有身份,都能用身份文档来证明自己的身份。对人类来说,护照是身份文档的典型形态;对软件来说,数字身份文档最常见的形式就是 X.509 证书。证书由 CA 签发;CA 必须谨慎地核验"自己为之签发证书的人或物"的身份,并管理证书的寿命。证书签发之后,任何使用它的人都需要信任签发它的 CA。
一旦有了可信赖的数字身份文档,它们的用途就非常广。最常见的用途之一是建立互信 TLS 连接——同时具备认证、保密性和完整性。另一个常见用途是授权。有了认证、保密性、完整性、授权这四件套,服务之间的连接才是安全的。
下一章:第 4 章 SPIFFE 与 SPIRE 概念入门