客户端证书通过校验,第一轮交换完成,随后连接却因一个关于额外认证轮次的错误停下。证书链里没有错,网络里也没有任何变化。网关被配置成向连接方要求第二份证明,而客户端从不发送它。判定谁证明什么、按什么顺序证明,就是全部工作,而它始于从你脚下的端点读取策略。两份不同性质的证明、固定顺序,是一项设计决定,而不是一个勾选框。

症状:第一份证明成功之后失败

第一轮交换完成,日志看起来健康,直到网关通过 EAP 索要用户身份。随后握手停滞,或返回一个点名那额外轮次的协议错误。一张完全有效的机器证书被拒绝,理由与它的有效性毫无关系。策略要了第二份证明,而客户端的答复从未到达。

对那次失败的两种描述,取决于你站在哪一边,都是准确的。从客户端一侧看,像是服务器拒绝了一张有效证书;从服务器一侧看,像是客户端完成不了登录。同一件事在一份日志里读作信任问题,在另一份里读作能力问题。只有配置好的策略才告诉你究竟是哪一种。

这项扩展增加了什么,又没有增加什么

IKEv2 带有一种扩展,可在单个会话内运行不止一次认证交换。RFC 4739 勾勒了若干序列,其中包括客户端先证明一个证书身份、再通过 EAP 认证一个人。该文档处于实验状态,这意味着没有任何实现欠你这个特性。在对端协商出它之前,不要对支持情况做任何假设。

双方都必须支持该扩展,并在交换过程中就它达成一致。配置了第二轮要求的网关无法强迫客户端执行一轮,而支持它的客户端,除非服务器要求,也不会使用它。正是这种不对称,使失败通常表现为超时或协议错误,而不是一句关于能力的明确说明。只读一方的配置,你只能知道将会发生什么的一半。

每个端点一份证明是常见的形态,而它不是这种设计。网关出示自己的证书,用户回答 EAP,双方各自恰好认证了对方一次。这两份证明来自相反的端点,所以哪一份都没有单独说明机器和使用它的人。

EAP-TLS 是第三种形态,它也不是这一种。在那里,客户端证书是在某个 EAP 方法内部出示的,所以客户端完成的仍然是一次 IKE 认证。凭据看起来可能与多轮的情形一模一样,而协议承载的却是一轮而不是两轮。这就是为什么从 EAP-TLS 部署照搬来的设计,会在期待第二份证明的地方失败。

同一个文件在网关上读起来不一样

同一个 swanctl 文件,在哪儿运行就读出不同的意思,而这正是让人栽跟头的地方。在笔记本上,网关是远端;在网关上,笔记本才是远端,所以把 local 一侧写成我是谁,把 remote 一侧写成我会接受谁。local 块描述这个端点如何证明自己,remote 块则写明它要求另一端做什么。把块在两个文件之间复制,一个字符都不改,含义却整个颠倒。比较两个文件几乎什么也告诉不了你,因为同样的词在各自里面意思相反。

一个段落的位置决定它的顺序,除非轮次编号把它覆盖掉。因此额外的 local 或 remote 段落描述的是额外轮次,而不是备选方案,而 swanctl.conf 参考文档 里的显式轮次编号,正是为了让这个顺序成为有意的。没有它,移动一个块就会改变行为。这也是为什么两份在纸面上看起来等价的配置,可能按相反的顺序行事。

这条顺序规则产生了那个值得记住的故障形态。第二个 remote 块不是另一个可接受的选项;它是第二项要求,所以一条读起来像“或”的策略,行为却是“而且接着”。网关策略可能先接受已登记机器的证书,然后要求该用户的 EAP 交换,顺序就是这样。

把轮次与相互独立的因素区分开

两轮并不会自动成为两个相互独立的因素。重复一份证明,或者把两份凭据放在同一个存储里,都不会带来设计本应增加的那份强度。独立性是秘密如何被持有、什么会危及它们的属性,而不是协议跑了多少次交换。把轮次算作因素的设计,夸大了它实际拥有的东西。当合规问题问这次登录到底用了几个因素时,这个区分最为要紧。

机器证书证明它持有那把被接受的密钥,仅此而已。它不是硬件证明,也不是设备健康报告,所以需要姿态信息的策略需要另一种机制。subject 字段也不是你可以信任的资产标签,因为 subject 是由签发或登记这张证书的人选定的。如果设计需要证明机器是健康的,那份证明必须来自一个测量机器的组件。

在加上一轮之前,先写下它到底证明了什么。当两轮把同一件事证明了两遍,第二轮带来的是延迟和工单,而不是保障。这条笔记同样能止住一场关于额外轮次是否值回成本的争论。

写出配对规则,并测试那些拒绝

决定哪些机器身份可以与哪些人配对,并把规则写进执行所在的地方。两份有效凭据并排放着,并不能证明任何关于配对的事,因为配对是一项授权决定,而不是认证结果。登记记录或认证后端必须执行组织想要的那种关系。

然后测试那些本该失败的情况:一个被接受的用户配上一台未获批准的机器,一个未获批准的用户拿着机器凭据,以及一个无法执行额外轮次的对端。如果三者都悄悄拿到了同样的访问权,那策略只是在描述一种意图,而不是在执行它。把声明的配置与守护进程报告的情况作比较,因为一条从未匹配上的连接,看起来和一条通过的规则一模一样:

swanctl --list-conns
swanctl --list-sas

检查协商出的轮次和由此产生的授权,而不只是登录成功。也不要把旧式 IKEv1 XAuth 设置当成捷径:去对齐协议、角色、顺序和客户端的真实行为,而不是把一条必需的轮次删到连接成功为止。删掉失败的那一轮,正是一套双证明设计悄悄变成一套没人审过的单证明设计的方式。把这次删除留在变更记录里。

相关文章