板子从通用镜像启动,取得 DHCP 租约,并且在任何人碰过设备之前,一个配给脚本就已经在运行。在这个脚本的某处,它必须获得一个只属于这块板、不属于任何其他板的 WireGuard 身份,让这个身份获得授权,并写出网关会接受的配置档。镜像可以携带客户端软件、经过审阅的模板以及网关的公钥。它绝不能携带的是整个机队共用的一把私钥,因为那会把一块被盗的板变成整个机队的事故。下面的顺序让身份留在本地,让授权保持显式。

镜像携带什么,不携带什么

交付软件包、带占位符的模板、网关的公钥以及注册客户端。模板是一种形状,不是机密:它应当可以被配给用户读取,并且不含任何密钥材料。

私钥在首次启动时于设备上生成,并且永不离开设备。只有公开的一半会出行,装在一个注册请求里,而这个请求是由设备对自身身份的自述之外的东西来授权的。正是这一区别阻止了一块被盗的板变成整个机队的问题。这也正是大多数首次启动脚本弄错的部分。

步骤 1:在本地生成密钥

在底层网络连接获批并正常工作之后,在受保护的目录中执行生成。子 shell 把 umask 的改动限制在这次操作内,而 set -C 会拒绝覆盖已有文件:

(
    umask 077
    set -C
    wg genkey > /etc/wireguard/device.key &&
        wg pubkey < /etc/wireguard/device.key > /etc/wireguard/device.pub
)

WireGuard 快速入门 记录了这两条命令所依赖的密钥生成关系。如果生成被中断,就让设备保持未注册,让工作流去核对文件。不要仅仅为了让脚本从头顺利跑一遍就删除已有的身份。

在多次重试之间保留待定的密钥。每次临时网络故障后就重新生成身份,正是机队最终留下一堆没人能对应到设备的孤立对端的原因。

步骤 2:授权一条设备记录

假设库存把这板子称作 device-042,并分配 10.90.0.42/32。注册服务必须核实这位请求者有权使用那条记录。在表单里输入的序列号不是证明,因为序列号就印在箱子外面。

每台设备各自的引导凭据、操作员批准,或由硬件支撑的证明,都可以确立这一声明。保护请求的完整性与响应的真实性,也不要用一个共用的出厂凭据替换一个共用的 VPN 机密。

登记后的记录把设备、它的公钥、分配到的地址以及被允许的管理角色绑定在一起。WireGuard 本身并不定义注册 API,因此那项服务是你刻意构建并运营的东西。

步骤 3:写出两份互相匹配的配置

设备需要一份把管理前缀路由进隧道的配置档,网关需要一条只放行这台设备自身源地址的对端条目。当网关位于 10.90.0.1、管理网段为 10.60.0.0/16 时,设备一侧看起来是这样:

[Interface]
PrivateKey = <device-042 private key>
Address = 10.90.0.42/32

[Peer]
PublicKey = <trusted gateway public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.90.0.1/32, 10.60.0.0/16
PersistentKeepalive = 25

方括号里的值是占位符,不是密钥。当板子位于 NAT 之后并需要保持可达时,keepalive 才重要;它并非到处都需要,而习惯性地加上它会让无线电毫无理由地保持唤醒。

在网关上,对端条目被刻意收窄:

[Peer]
PublicKey = <device-042 public key>
AllowedIPs = 10.90.0.42/32

不要把设备的目的地列表复制到网关的对端条目上。在设备上这份列表说的是把什么路由进隧道;在网关上它说的是这个对端可以使用哪些源地址,这是两种不同的陈述。

转发、防火墙规则以及返回管理网段的路径仍然必须放行已获批的访问。一个已登记的对端并不是对它身后每个应用的许可。

步骤 4:把注册确立为一种生命周期状态

通过各自配置的归属者来应用网关记录与设备配置档,然后只有在预期的身份与地址被接受时才把注册标记为完成。重试应当核对同一条记录,而不是分配第二个对端或第二个地址。

为中断的配给保留一条恢复路径,包括网关已接受密钥而设备始终没有写出配置档的情形。

当一块板被更换或退役时,把它的公钥与它的授权一起移除。新密钥是一次刻意的重新注册事件,而不是重刷镜像的副作用。工作顺序:本地生成、对照库存授权、写出两侧、确立状态,然后通过隧道测试一次管理请求。

相关文章