为什么服务器密钥与用户凭据必须分开管理
网关身份和用户授权是两种影响范围不同的密钥。三个问题决定各自如何存储、发放和吊销。
证明网关自身身份的密钥,和表明某个人可以加入的凭据,都是密钥,相似之处也仅止于此。一个向所有客户端标识一项服务;另一个向该服务标识某位用户。混用两者能在搭建时省一步,却会在出事时花掉一下午,因为两者的恢复方式并不是同一套操作。分开管理在搭建时枯燥乏味,被跳过时却令人难忘。
两种密钥,两个不同的所有者
网关持有一把私钥或一张证书,它唯一的职责是在握手期间证明网关自己的身份。客户端需要与之匹配的公开材料来验证它,永远不需要私密的那一半。正是这种不对称,使得在不必让每个用户都能冒充服务器的前提下,服务器认证成为可能。
用户材料的方向正好相反。客户端私钥、客户端证书或密码表明,正是这个特定的人或设备获得了访问授权。它本来就是会被分发、在设备之间复制、并最终被吊销的。
WireGuard 把这种区分展示得很清楚,因为每个参与者都有一对密钥:服务器的私钥留在服务器上,而你交给用户的配置文件包含他自己的私钥以及服务器的公钥。一份包含服务器私钥的配置不是捷径,而是一场等着被文件共享泄露的沦陷。
决定这种区分的三个问题
问问谁必须能读到这份密钥,一旦暴露攻击者能做什么,以及补救只是吊销一次还是要重建整套服务。
如果用户能读到它,而它证明的是网关身份,那么第二个问题的答案是:攻击者可以向所有客户端冒充你的服务器——这是最糟的结果,因为客户端天生就被设计成信任那个身份。如果它只证明某一位用户,暴露只让攻击者获得该用户对某一个对端的访问权,吊销只是例行操作。如果它是证书颁发机构的密钥,暴露比前两者都糟,因为攻击者可以伪造出每个端点都会信任的身份。
这三个答案推导出存储规则:CA 密钥离线保存或放进保险库,网关密钥留在网关上,用户密钥跟着用户走。任何为了省事把三者放进同一个目录的布局,都是把一项决策变成了意外。
客户端真正需要什么
客户端需要公开证书或对端公钥、它应当信任的 CA 材料或指纹、自己的私钥,以及端点信息。这份清单里没有任何属于网关私密身份的东西。
文档正是泄露发生的地方。一份让你复制服务器目录、再删掉用不着的文件的指南,已经教会了错误的模型,因为删除步骤之后剩下的那个文件,几乎没人会去检查。
吊销单个用户,而不动网关
因为用户身份是单独签发的,所以也可以单独撤销。基于证书的部署会吊销客户端证书并发布更新后的吊销列表;WireGuard 部署则从服务器配置里删掉对应的对端条目。这些操作都不会改动网关自己的密钥。
保存签发记录,否则你不会知道该撤销哪个身份。一张表格就够了,前提是它写明了人、设备、序列号或公钥以及日期,并且在建表的人离开之后有人接着负责它。
下面的命令先查看客户端证书,再通过 OpenSSL 风格的机构吊销它,这正是 easy-rsa 封装的那套流程:
openssl x509 -in client.crt -noout -subject -serial
openssl ca -config openssl.cnf -revoke client.crt
openssl ca -config openssl.cnf -gencrl -out crl.pem在客户端会检查的每个地方发布新列表,否则吊销只是文件里一条什么也改变不了的备注。如果你的网关接受客户端证书却不查吊销列表,就明确说明这一点,而不要暗示吊销是生效的。
备份也要像密钥一样分开存放
重建归档里合法地包含网关密钥和 CA 材料,因为没有它们,恢复就无法重现这项服务。客户端安装包则绝不能包含这些,两者也不能存在一起。给每个归档贴上标签,标注谁可以持有它,而不是它生成的日期。凌晨两点疲惫的管理员读的正是这个标签。
这种区分也决定了谁可以取回哪一份。管理网关、签发用户身份、读取备份是三种不同的权限,需要其中一种的人并不自动需要另外两种。把这些权限写下来,再核对你的存储实际允许什么,因为目录继承会悄悄授予超出策略本意的东西。