克隆 VPN 服务器镜像,而不克隆它的身份
判断这次复制是还原一台网关,还是新增第二台。可复用的配置、签发权限和网络状态各自以不同方式随镜像迁移。
镜像启动、服务拉起、客户端连接成功——此刻要停下来问清楚:发生的到底是两种截然不同的操作中的哪一种。要么这份副本在还原一台此前就存在的逻辑网关,要么它在为机群新增第二台网关。两者都合理,但对身份与访问权限的影响完全不同。一台能干净启动的机器,哪一种都证明不了。
决定答案的是三个条件,也就是镜像可能携带的三类材料。要在构建镜像之前把它们分开,而不是在镜像被部署两次之后。
先确定你正在做的是哪一种操作
还原保留同一个服务身份。旧实例已经不在了,名称与证书继续沿用,客户端继续信任同一个接入点。新增则创建第二个身份,客户端、日志和吊销流程都必须能把它区分出来。
这个区分不是表面功夫。如果两台在线主机出示同一张网关证书,客户端分不清它们,审计轨迹也分不清,而一旦吊销那张证书,两台会同时失效。这或许正是深思熟虑的高可用设计想要的,却几乎不是一次匆忙复制镜像的本意。
所以第一个决定是一句话,必须在镜像离开构建主机之前写下来:这份副本还原网关 A,或者这份副本成为网关 B。此后的一切都是对这句话的记账。如果没人写得出来,这份副本就不该开始构建。
可复用输入、身份与签发权限、部署状态
可复用那一类最好办:软件包、经过评审且不含密钥的配置、服务模板、加固设置。镜像真正擅长的是这些,而且可以无限制地重复产出。
身份与签发权限这一类,正是复制出错的地方。网关的私钥与证书向每个客户端表明这台网关的身份。证书机构的签发密钥是另一件性质完全不同的东西:它负责签发身份。信任某个签发者,并不意味着每台新网关都要具备签发能力;把签发密钥随镜像一起发出,等于把这项能力交给任何能读到镜像的人。
部署状态这一类最容易被忽略,因为它看起来像配置。监听地址、地址池、推送路由、解析器设置和本地集成,全都编码着针对第一台主机的假设。照抄它们的第二个节点,可能会从另一台网关已经占用的池里分配地址,或者把客户端指向一个只存在于原主机旁边的资源。
新节点应当得到什么,由谁来给
独立管理的节点应当通过既定的登记流程取得自己的凭据,签发操作要发生在签发密钥所在之处,而不是在新主机上。记录清楚哪个身份可以被撤回而不影响其他节点;如果答案是“全部”,那就说明这套设计里只有一个身份在假扮两个。
网络取值也应当同等对待。挑选一个不与现有网关冲突的地址池、一个监听地址和一组推送路由,把它们写进供给输入,而不是写进镜像。输入是可以评审的,镜像不行。
也存在合理的中间情形。受支持的恢复或复制设计可以有意让多台主机共用同一个逻辑服务身份,前提是对旧副本有受控访问,并且有轮换计划。那是一个有人负责的决定,而不是因为镜像用起来方便就默认发生的事。
openssl x509 -in /etc/openvpn/server/server.crt -noout -subject -issuer -dates
find /etc/openvpn -name '*.key' -o -name '*.pem' | head -20
第一条命令会告诉你,节点实际出示的是哪个身份、由谁签发。第二条只是起点清单,不是证明:私密材料可能存放在那个目录之外,可能放在某个应用数据库里,也可能留在正在运行的文件系统已经看不到的快照层里。
镜像的一份副本会悄悄带走什么
从镜像的最新修订里删掉一个文件,并不会把它从更早的修订、层缓存或它在世时打下的快照里抹去。这就是为什么带凭据的镜像必须在整个生命周期里被当作敏感对象对待,而不只是在构建的那一刻。
把镜像内容和供给输入当作两个独立的问题来检查。镜像回答的是“这个产物里面有什么”,而输入回答的是“这个实例首次启动后会变成什么”。一份干净、但带初始脚本去拉取共享密钥的镜像,第一个问题答得好,第二个答得很糟。
合法含有秘密的恢复镜像,应当只交给真正需要它的人,并记录清楚存放在哪里。另一种做法——一份因为不需要任何供给就能用而显得方便的镜像——恰恰就是那份把网关身份送给任何找到它的人的镜像。这两件事里,只有一件会出现在构建日志里。
上线前的准入检查
在节点接收流量之前,确认四件事:它出示的身份、它将接受的客户端、它被允许访问的资源,以及它分发出去的地址的回程路径。
systemctl status openvpn-server@lab --no-pager
ss -lunp 'sport = :1194'
ip -4 route show table all | grep -F '10.90.'
然后再看反面情形,这恰恰是能抓住事故的那一面:新节点是否带着原本属于原主机的管理员或客户端访问权限?一份被复制过来的配置可能夹带多余的客户端条目、继承下来的管理路由,或者在原主机上才说得通的推送指令。
如果一份含有在用秘密的镜像已经越过了获批边界,那就更换凭据并控制住这些副本。从最新构建里删掉文件,并不等于让旧副本仍然持有的凭据退役;这两件事之间的空档,正是攻击者需要的那扇窗口。