给租来的磁盘加密,到底换来了什么
服务器只有两种状态,而磁盘加密只对其中一种有意见。关机时,卷是密文:存储介质里的字节在没有密钥的情况下与噪声无异。运行时,卷已挂载,这意味着主密钥已经被派生出来,加载进内核内存,并且只要机器在运行就一直留在那里。操作系统能读到的每一个文件,之所以能读到,正是因为那把密钥常驻内存。加密并没有失效——它只是恰好在做被要求做的事。
那是一份比宣传语暗示的更窄的保证,但依然值得拥有,因为它覆盖的正是真实会发生的事件。硬盘被淘汰后转卖。出故障的 NVMe 带着你的数据以 RMA 名义寄回厂商。节点关机,磁盘被镜像。备份归档在没人加密的介质上离开了机房。有人能接触到机柜,顺手把不该拿的东西带回了家。这些事一点都不戏剧化,却构成了现实世界中绝大多数的数据外泄——远比人人想象的"对运行中机器的突袭"要常见得多。
| 场景 | 机器状态 | LUKS 有帮助吗? | 暴露的内容 |
|---|---|---|---|
| 硬盘淘汰、转卖或 RMA 寄回 | 关机 | 是,完全有效 | 密文与 LUKS 头 |
| 节点关机,磁盘被镜像 | 关机 | 是 | 密文、分区布局、明文 /boot |
| 备份归档被拷贝到站外 | 不适用 | 只有归档本身被加密时才有效 | 归档中的一切内容,明文可见 |
| 对运行中实例的实时取证 | 运行中 | 基本无效 | 全部——密钥就在 RAM 中 |
| 运行中系统被攻破 | 运行中 | 无效 | 已挂载卷所暴露的一切 |
虚拟化层本身就在你的威胁模型之内,加密并不能把它排除出去
在 VPS 上,你的内核是一台客户机。运营虚拟化层的一方持有这台客户机的内存,就像你持有一份文件的内容一样,中间没有任何加密步骤。virsh dump 把一个运行中域的 RAM 写入文件,这是常规操作;实时迁移会把同一份内存按设计拷贝到网络上,因为迁移本来就是这么回事。存在于客户机内存中的 LUKS 主密钥,也在这一切之内。
所以诚实的说法是这样的:VPS 上的全盘加密能防住除了运营虚拟化层那一方之外的所有人——也能防住那一方,但仅限于机器关机的时候。任何声称"给客户机磁盘加密,就能让运行中的实例对我们不可读"的主机商,描述的都是一台不存在的机器。我们宁可把这句话写清楚,也不让你自己脑补出更舒服的版本。
如果服务商真的在你的威胁模型之内,答案不是换一种更强的密码算法,而是把虚拟化层整个拿掉:独立服务器让你的内核直接跑在裸机上,要读取它的内存就得实际拿到这台机器,再对 RAM 发起 DMA 或冷启动式攻击——缓慢、动静大,需要的访问权限远超一次常规请求所能给到的。VPS 与独立服务器对比指南还讲了这次切换在其他方面同样划算的原因。AMD SEV-SNP、Intel TDX 这类机密计算扩展正是瞄准这个缺口而生,但它们在今天的租用 VPS 上还不是标配,而且只是把信任转移给了 CPU 厂商,并没有消除信任本身。
三种落地方式,各自要付出什么代价
实践中主要有三种形态,它们在安全性和重启的痛苦程度之间做取舍。从控制台解锁的加密根分区最强也最烦人:没有人工介入,什么都撑不过一次重启。initramfs 中带 SSH 服务的加密根分区安全性相同,却能远程解锁,是大多数人应该搭建的方案。明文根分区上的加密数据卷是最省事的选项,也是那个会悄悄让你失望的选项。
它让人失望,是因为明文根分区无论你是否愿意,都会把你的秘密收集起来。systemd 日志写在那里。shell 历史、软件包缓存、core dump、/tmp、Docker 的默认数据根目录也是如此——而几乎每个人都会中招的那一个,是 swap:机器承压时,进程的内存就是往那里去的。给 /var/lib/mysql 加密,却让旁边的 swap 保持明文,这不是打了个折扣的防御,而是一份中间挖了个洞的完整防御。
| 配置方案 | 解锁方式 | 能否扛过无人值守的重启 | 诚实评价 |
|---|---|---|---|
| 加密根分区,控制台解锁 | KVM-over-VNC 或 IPMI | 不能——在有人解锁前一直停机 | 最强;适合很少重启的机器 |
| 加密根分区,initramfs 中带 dropbear | SSH 到解锁端口 | 不能——但可以随时随地解锁 | 明智的默认选择 |
| 加密数据卷,明文根分区 | 启动后脚本或手动执行 | 能 | 除非把 swap、日志和临时目录都处理好,否则很弱 |
| 加密根分区,密钥文件放在明文 /boot 中 | 自动 | 能 | 只能防住转卖的硬盘,别的都防不住 |
分步安装加密根分区
1. 启动安装程序,而不是套用模板。预制镜像给不了你加密根分区,因为磁盘在你成为客户之前就已经写好了。每个 BitVPS 套餐都支持从 ISO 重装、上传自定义 ISO 和 netboot,也都自带 KVM-over-VNC 应急控制台——这一点很关键,因为你需要盯着安装程序、回答它提出的问题。独立服务器通过一个由 VPN 网关保护的 IPMI 端点提供同样的能力,支持 ISO 挂载和 BIOS 访问。
2. 划分一个小的明文引导区。给 /boot 或 EFI 系统分区留一个小分区,其余全部空间划给一个 LUKS 容器。引导程序和 initramfs 必须在任何密钥存在之前就可读,所以这个分区对任何镜像了磁盘的人来说都是可读的。围绕这一点做设计,而不是假装它不存在。
3. 创建容器。cryptsetup luksFormat --type luks2 --pbkdf argon2id /dev/vda2。LUKS2 搭配 argon2id 正是重点所在:argon2id 是内存困难型算法,规范见 RFC 9106,它让离线猜测攻击在硬件层面变得昂贵,而不只是在软件层面变慢——这就是"GPU 农场吭哧吭哧啃你的口令"和"GPU 农场根本不值得对准你"之间的差别。把内存开销控制在机器早期启动阶段能分配到的范围之内;在 4 GB 的实例上,用你 64 GB 笔记本电脑调出来的开销参数,只会导致解锁失败。
4. 打开容器并安装系统。cryptsetup open /dev/vda2 cryptroot,接着在 /dev/mapper/cryptroot 上直接建 LVM 或文件系统,然后让发行版的安装程序对着它安装,/boot 放在明文分区上。Debian、Ubuntu、Alpine、Arch、Rocky、Fedora 和 FreeBSD 都能这么处理;不管你实际用的是哪个发行版,Arch wiki 的 dm-crypt 页面都是最完整的参考资料。
5. 在 initramfs 里放一个 SSH 服务。安装 dropbear-initramfs,把你的公钥放进 /etc/dropbear/initramfs/authorized_keys,再给内核命令行加一个 ip= 参数,让网络接口在口令提示之前就起来。漏掉这个参数,你造出来的就是一台启动到提示符、却没人能连上的机器。
6. 重建并重启。update-initramfs -u 会把 SSH 服务、你的密钥和网络设置一并打进引导程序加载的镜像里。然后开着控制台重启,因为第一次尝试最容易出岔子。
7. 解锁并确认交接完成。SSH 到解锁端口,运行 cryptroot-unlock。initramfs 出示的主机密钥和已安装系统的不一样,所以你的客户端首次连接时会大声警告——这是正确行为,是一个有用的信号,不是障碍:把这个指纹单独固定为一条 known_hosts 记录,而不是干脆关掉主机密钥校验。会话断开,正是真正的系统已经接管的信号。
远程解锁,以及那个没人先问的 04:00 问题
让 initramfs 里的 SSH 服务用自己独立的端口——约定俗成用 2222——这样两把主机密钥就不会撞进同一条 known_hosts 记录里。优先用静态 ip= 而不是 DHCP:initramfs 是一个极简环境,一次失败的 DHCP 交互会留给你一台开着机、连不上、卡在提示符上的机器。如果你依赖 IPv6,要确认你的 initramfs 真的配置了它;有几个发行版在这个阶段还是只启用 v4。
即便 SSH 解锁跑通了,也要把控制台留作后备手段。你最终会撞上的失败不是密码学层面的,而是一次内核更新重建了 initramfs、却没带上你的密钥,或者网络参数在你不知情的情况下变了——那一刻,唯一的入口就是套餐自带的 KVM-over-VNC 控制台。两手都留着不是冗余,而是"小麻烦"和"推倒重装"之间的差别。
然后是那个运营层面的问题,也是在动手搭建这一切之前就该想清楚的问题:加密根分区意味着无人值守的重启会让你的服务保持宕机,直到有人手动解锁。节点维护、内核 panic、断电事件——机器重新出现时停在提示符上,而不是你的应用上。如果这个后果对你的业务来说无法接受,不要用一份放在明文引导分区里的密钥文件来敷衍过去。那就是把钥匙用胶带粘在门上的锁,只能防住转卖的硬盘,别的什么都防不住。如果你愿意,也可以刻意选它,但要在自己的运维手册里写清楚:这是你有意做出的选择。
加密卷周围会泄漏的一切
出问题的地方很少是卷本身。出问题的是那些根本没被放进卷里的东西。
| 泄漏点 | 为什么会发生 | 解决办法 |
|---|---|---|
| Swap | 进程内存(含密钥在内)在系统承压时溢写到磁盘 | 把 swap 放进容器内,或使用随机密钥的 swap 设备,或干脆不用 swap |
| 休眠镜像 | 按设计把完整的 RAM 转储写入磁盘 | 在服务器上禁用它;它本就不该出现在服务器上 |
| 明文的 /boot 和 initramfs | 必须在任何密钥存在之前就可读 | 接受这一点,把它遭到修改视为入侵——加以校验,或在可用时启用 Secure Boot |
| 挂载之前写入的日志 | 早期启动日志落在明文分区上 | 确认你的日志在卷打开之前实际存放在哪里 |
| Docker 数据根目录 | 默认是 /var/lib/docker,在外挂的数据卷之外 | 把它挪进卷内,或者干脆加密根分区 |
| 盒外监控与日志 | 代理把文件内容以明文形式发往第三方 | 在信任这个卷之前,先审计代理都发送了什么 |
有一个特性必须说清楚,因为它经常被过度宣传:LUKS 头会主动暴露自己的存在。任何镜像了这块磁盘的人都能看到有一个加密容器存在、用的是哪种密码算法、KDF 参数是什么,以及占用了多少个密钥槽。LUKS 给你的是机密性,不是可否认性,任何指望"没人会注意到这个容器"的计划,都是建在沙子上的。
口令、密钥文件与分离头
口令就是整套系统。Argon2id 让每一次猜测都变得昂贵,但"昂贵"乘以一个很小的密钥空间,结果依然便宜:从 diceware 词表里选五六个单词,胜过一个带替换字符的十一位密码,而且差距不小。用 --iter-time 针对真正会执行解锁的那台机器来调开销,而不是你正在打字的这台,并且绝不要复用任何靠近过 KYC 账户的口令。
密钥文件省去了打字,却把问题挪到了别处:cryptsetup luksAddKey 把一个密钥加进空闲槽位,而唯一值得拥有的版本,是那种从不留在服务器上的——放在你自己的机器或硬件令牌上,在 SSH 会话中喂给解锁过程。分离头(--header)更进一步:由于元数据存放在别处,数据设备本身与随机字节再无区别。代价是毫无余地。丢了这个头,卷就永久没了,没有任何补救办法——所以要认真对待 cryptsetup luksHeaderBackup,并把这份备份存放在另一处同样加密的地方。上游的 cryptsetup FAQ 和内核的 dm-crypt 文档,是你敲定方案之前值得读的两份参考资料。
还有一条没有例外的规矩:口令永远不进工单。不进我们的工单,也不进任何人的工单。我们做的任何事都不需要它,我们能替你执行的任何操作都用不上它,而工单是数据库里一条写死的记录。如果哪家主机商问你要口令,这段对话到此就该结束了。
被镜像取走的磁盘,究竟会交出什么
把关机场景说具体一点,因为在这件事上含糊其辞对谁都没好处。手里有你磁盘镜像的调查者,能拿到的是:密文、带着密码算法和 KDF 参数以及槽位数量的 LUKS 头、分区表、所有东西的大小,以及整个明文引导分区——你的内核、你的 initramfs,以及其中每个文件的修改时间戳。最后这一项透露的信息比人们以为的要多。软件包的安装时间能勾勒出一条时间线,而一个包含 dropbear 密钥的 initramfs,也能说明这台机器是怎么被管理的。
他们拿不到的是内容本身。面对一个用 argon2id、配了真正强口令的现代 LUKS2 容器,离线攻击不是"再多等一会儿"的问题——它根本不在选项之内。这就是整份价值主张,而且是一份实实在在的价值。
运行中的情形正好相反,而且很简短:一切都能拿到。不是因为加密失效了,而是因为密钥常驻内存——这正是一个已挂载文件系统能正常工作所必须具备的条件。
快照处在两者之间,常常让人意外。我们提供每小时快照、保留 7 天,是块级别的,所以加密卷做出来的快照同样是密文——这是好事,而它的推论也很扎实:没有口令,你同样读不了那份快照。丢了密钥,快照和原卷一样彻底无法恢复。恢复方案里必须包含口令的保管办法,否则你搭建出来的只是七天非常可靠的噪声。我们在卷之外持有关于你的哪些信息,写在 隐私政策 里,我们每周发布一份 PGP 签名的预警金丝雀,作为长期存在的证据,而不是一句承诺。
决定最终结果的部分,从来不是密码学
没有人是因为 AES-256-XTS 顶不住而丢了数据的。他们丢数据,是因为口令是从存过护照的交易所账户上复用来的,是因为为了让重启安静一点,把密钥文件留在了明文引导分区上,是因为站外备份就是一个普通的 tarball,是因为口令留在了笔记本电脑的 shell 历史里,或者是因为某个监控代理一直在把文件内容发送给某个 SaaS。
还有一个容易被忽视的:一台从不关机的服务器,整段生命周期都处于"这一切都帮不上忙"的状态。一个正常运行了 400 天的实例,已经解密了 400 天。如果数据真的是冷数据——归档、密钥备份、一年也就查两次的记录——就把它放进一个容器里,需要时才打开,用完就 cryptsetup close。十秒钟的打字操作,能把一次永久性的暴露变成一次瞬时的暴露,而这个转换比你能传给 luksFormat 的任何参数都更有价值。
顺带把管辖地也纳入同一套推理。加密决定的是什么内容可读;机器坐落在哪个法域决定的是谁有资格来问,以及请求会经过哪些情报联盟。这两者不能互相替代,而真正做对这件事的人,会把它们当成同一个决策来对待。
我们能提供什么,又不能提供什么
从 $8.50 的 Starter 套餐往上,每个套餐都提供了加密根分区真正需要的东西:拥有完整 root 权限的 KVM 虚拟化、启动自定义 ISO 与 netboot 的能力、面板上的从 ISO 重装、内核模块加载,以及在 initramfs 不肯回应时用得上的 KVM-over-VNC 应急控制台。独立服务器档位额外提供一个由 VPN 网关保护的 IPMI 端点,带控制台、断电重启、ISO 挂载和 BIOS 访问。加密这件事上,没有任何一部分是我们卖给你的产品——它是你自己搭建的东西,我们的工作是不挡你的路。
说清楚我们不能做什么,反而更有用。在一台运行中的 VPS 上,虚拟化层能读取客户机内存;这是架构决定的,不是策略开关,你在客户机内部装再多加密都改变不了它。针对这一点,我们提供的不是数学证明,而是态度和证据:不留 netflow、不留 PCAP、不做网卡镜像、面板会话 IP 在 24 小时内清除、注册不做 KYC 所以账户本身不构成筹码、只收加密货币所以账单流水同样不构成筹码,外加一份你自己可以核验的、每周 PGP 签名的预警金丝雀。只有独立硬件能把虚拟化层从整个局面里拿掉,也只有断电能把 RAM 里的内容清掉。
如果这段话读起来像是在某些威胁模型下反对我们自家的 VPS,那确实就是。我们宁可把对的东西卖给你两次,也不愿把错的东西卖给你一次。用一份 ISO 部署一个实例,在 Starter 套餐上试装一个月;如果答案最终指向裸机,独立服务器档位从 $39.50 起,开通需要两到四小时,而不是 41 秒。