隧道的一端用另一个端从不检查的密钥槽来签名控制通道,连接在交换任何一张证书之前就以认证错误断开。这就是 tls-auth 方向不匹配的样子,而且它是确定性的:同样的两个文件每次尝试都失败,换任何网络都一样。日志里不会出现你要找的那个选项名,于是人们重建从未损坏的密钥、重新签发证书。解决办法是让两端互补,或者让两端都保持双向,而不是削弱验证。

故障发生在证书之前

使用 tls-auth 时,两端持有同一把共享密钥,各自使用由它派生出的两个槽之一:一个槽签发出站控制包,另一个验证入站控制包。方向 0 与方向 1 以相反顺序分配这两个角色,因此这一对必须互补,HMAC 校验才能对上。当一侧的分配被反过来,接收方就会在错误的槽里找签名并丢弃数据包。会话到此结束,所以这个错误关乎数据包认证,而不是证书库会产生的任何东西。

这种确定性对诊断很重要,因为时间或路径问题留下的痕迹不同:间歇性断连、只有一个方向失败,或只在特定网络下断开的会话。方向不匹配每次都在第一次握手时失败,而且在持有同样两个文件的另一台机器上失败得一模一样。用 --verb 4 读日志,去找第一个被拒绝的数据包,而不是最后一行。如果那次拒绝发生在任何证书交换之前,那么共享密钥及其方向就是值得检查的两件事。

What you seeWhat it rules outNext check
Authentication error before any certificate is sentThe data channel is irrelevant; the control channel never authenticatedCompare tls-auth and its direction on both ends
Certificate or handshake failure after the control channel authenticatesThe shared key and its direction already agreeCheck the CA, the certificate dates and the hostname
Session completes but throughput or cipher warnings appearDirection was never the problemCompare the data-channel cipher settings
Startup stops on an options errorThe number itself is not the issueRe-read the inline versus external directive syntax

数字住在哪里

OpenVPN 2.6 手册 记录了两个位置:密钥单独成文件时用 tls-auth 的第二个参数,密钥内联在配置里时用独立的 key-direction 行。两者设置的是同一个值,所以配置应当二选一,绝不要同时使用。省略也是一种选择,它让两端进入双向安排,在双方都不指定方向时可用。两个携带相同数字的对端并不处于这种安排:各自都期望在一个槽里签名、在另一个槽里验证,结果两边都朝同一个方向做。

# server.conf, external key
tls-auth ta.key 0

# client.ovpn, external key
tls-auth ta.key 1

# client.ovpn, inline key
key-direction 1

内联形式是独立一行的指令,不是密钥块开始标签上的属性;给那个标签加参数是错误,不是改方向。位置同样重要:指令写在它所属的块之外,写在块内的值会被当作密钥材料读取。照抄配置分发者本来的安排,不要自创配对,因为对一台服务器可用的配置,在另一侧可能已经镜像过了。

这个选项不碰什么

它不加密应用流量。tls-auth 只是在控制通道的数据包外面加一层 HMAC,数据通道由握手中协商的会话密钥保护,所以吞吐量或加密算法的问题与方向数字无关。这个设置也不增加第二层加密,正是这个误解让人去找更长的密钥。

它不适用于 tls-crypt,那是另一种控制通道机制,有自己的选项和密钥处理方式,也完全不涉及任何一端的证书身份。因此方向匹配只能证明两端对如何认证控制通道达成一致,并不能证明信任链已被验证。

把这一对齐,然后重连

在改动任何一侧之前先比较两份配置,因为去改本来正确的那一侧会让工作量翻倍。下面的 grep 显示每个文件选了哪种机制;详细运行显示控制通道到底有没有通过认证。两份输出都留着,下一次改动才能和已知状态对比。

grep -n -E 'tls-auth|tls-crypt|key-direction' server.conf client.ovpn
openvpn --config client.ovpn --verb 4 2>&1 | grep -i -E 'hmac|tls error|control channel'

任何改动之后都要重启两端,因为这些选项在启动时只读一次,只重载一侧会让这对在整个旧会话期间都不一致。如果当前部署没有配置方向也能工作,那么给一端加上这个设置就会重现你最初的故障;要么都别动,要么两端都配。一次只改一端并保留上一个文件,这样回退是两分钟的事,而不是重建。

把每一端的机制、密钥文件和方向记进部署笔记,否则下一个人会读到两个相似的文件,并以为这两个数字应该彼此一致。方向是协调细节,不是安全升级:它只把控制通道的两个方向分开,别的什么都不做。

相关文章