SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-10-03

存储 VPS 数据加密:LUKS、客户端加密怎么选

存储 VPS 的磁盘属于他人。了解 LUKS 全盘加密、客户端密钥分别防范哪些威胁,以及如何保护已下线磁盘、运行中服务器和备份数据。

在存储 VPS 上加密数据意味着什么

要在存储 VPS 上加密数据,首先要确定您要防范谁。磁盘位于他人的机架中,除非明确加密要阻止哪类攻击者,否则“已加密”没有实际意义。这里有 3 个真正有效的层次,它们分别防范不同的对象。

备份数据的简短结论是:在拥有数据的机器上加密,只上传密文,并将密钥保存在存储提供商从未接触过的位置。restic 和 BorgBackup 默认采用这种方式。这是唯一一种能同时防范好奇的运维人员和被扣押服务器的加密层。

提供商侧的静态数据加密是另一种产品。提供商生成并持有密钥,因此这种加密可保护提供商的数据销毁流程和内部处理过程,但不能防范提供商自身。如果密钥不是由您生成的,就应假定持有该密钥的人都能读取数据。

四种威胁,以及各层防护的对象

加密不是安全等级。这是四个相互独立的问题。能解决其中一个问题的安全层,面对下一个问题可能完全无效。

  • 磁盘离开机架。有人更换、转售或报废磁盘,但磁盘上仍保留着你的数据块。全盘加密对此很有效,因为此时机器处于关机状态,密钥从未存储在这块磁盘上。
  • 好奇的运维人员。拥有 hypervisor 或存储访问权限的人读取你的文件,或复制快照。将密钥存储在另一台机器上的加密文件系统可以解决此问题。同一台租用服务器上的全盘加密无法解决,因为服务器运行时会将密钥保存在内存中。
  • 被扣押或制作镜像的服务器。正在运行的虚拟机连同内存一起被依法扣押,或在事件处理中被捕获。只有在数据到达该服务器前就已经是密文的数据才能避免泄露。此时已挂载且可读的任何数据,在镜像中同样可读。
  • 你自己的机器上的 root 帐户遭到入侵。root 可以读取所有已挂载的文件系统,因此上面的每一层防护对它都是透明的。限制损失的办法是隔离:将备份密钥存储在存储服务器无法访问的机器上,并保留一份遭到入侵的机器无法删除的副本。

在输入任何一个 cryptsetup 命令前,先确定你实际需要防范这四种威胁中的哪一种。大多数租用存储空间的人关心前两种。存储客户数据的企业还必须考虑第三种威胁。

第 1 层:使用 LUKS 对存储卷进行全盘加密

LUKS(Linux Unified Key Setup)是 Linux 上标准的块级加密方案。它会加密整个分区,因此写入已挂载文件系统的所有内容,包括文件名和元数据,在磁盘上都以密文形式存在。在存储型 VPS 上,通常应将其应用于较大的数据卷,而不是根磁盘,因为根磁盘容量较小,且通常没有需要隐藏的内容。

luksFormat 会销毁目标分区上的所有数据。运行前请阅读 lsblk 输出,并确认设备名称无误。

lsblk
sudo apt update && sudo apt install -y cryptsetup
sudo cryptsetup luksFormat --type luks2 /dev/sdb1
sudo cryptsetup open /dev/sdb1 vault
sudo mkfs.ext4 /dev/mapper/vault
sudo mkdir -p /srv/vault
sudo mount -o nosuid,nodev /dev/mapper/vault /srv/vault

在写入数据前检查结果。

sudo cryptsetup status vault
sudo cryptsetup luksDump /dev/sdb1
lsblk -f

cryptsetup status vault 应报告 type: LUKS2 和 cipher: aes-xts-plain64。luksDump 应在密钥槽中显示 PBKDF: argon2id,这是一种内存硬化的密钥派生方式,可提高猜测密码短语的成本。lsblk -f 应在 /dev/sdb1 上显示 crypto_LUKS,并在 /dev/mapper/vault 上显示您的 ext4。如果 cryptsetup status 输出 inactive,说明设备处于关闭状态,随后挂载会因 special device /dev/mapper/vault does not exist 而失败。

这些挂载标志不是装饰。存储卷用于保存数据,其中的内容不需要执行,也不需要携带 setuid 位;在数据挂载上启用 nosuid、nodev 和 noexec 不会带来额外成本。

速度很少是问题。grep -m1 -o aes /proc/cpuinfo 输出 aes 表示处理器提供 AES-NI 指令,因此 aes-xts 的运行速度远高于网络附加存储卷能够提供数据的速度。如果缺少该标志,加密本身就会成为瓶颈。应先确认这一点:参见您的 VPS 是否提供 AES-NI。

为什么租用服务器上的 LUKS 能保护已退役的磁盘,却不能保护正在运行的磁盘

这里有一个没有人会主动宣传的限制。没有密钥,机器无法解密卷。因此,要让卷在无人值守重启后恢复,密钥必须能被机器自身访问。这有两个合理选择,但两者都会带来代价。

将密钥文件放在机器上。 无需人工在场,卷即可在启动时解锁。此时,密钥位于同一台租用服务器上,存放在未加密的根磁盘中,而该磁盘也由服务提供商托管。这种方式完全能够防御磁盘被替换的情况:将 /dev/sdb 从机架中取出后,得到的只是无法读取的数据。除此之外,它无法防御其他情况。

sudo install -d -m 700 /etc/cryptsetup-keys.d
sudo dd if=/dev/urandom of=/etc/cryptsetup-keys.d/vault.key bs=512 count=8
sudo chmod 600 /etc/cryptsetup-keys.d/vault.key
sudo cryptsetup luksAddKey /dev/sdb1 /etc/cryptsetup-keys.d/vault.key
sudo blkid -s UUID -o value /dev/sdb1

将上一条命令输出的 UUID 写入 /etc/crypttab。

vault UUID=8f14e45f-ceea-467a-9f9c-1b2c3d4e5f60 /etc/cryptsetup-keys.d/vault.key luks,discard

然后将挂载项添加到 /etc/fstab。

/dev/mapper/vault /srv/vault ext4 defaults,nosuid,nodev 0 2

在系统中还没有需要保护的数据时,通过重启进行测试。重启后,findmnt /srv/vault 输出挂载信息,且 sudo cryptsetup status vault 输出 active,表示 crypttab 和 fstab 配置一致。启动过程停在密码提示处,表示 crypttab 中的密钥文件路径错误,因此 systemd 退回到要求人工输入密码,但此时没有人在现场。

每次启动时输入密码。 服务器上的任何组件都无法自行解锁该卷,因此对攻击者而言,已关机磁盘的副本没有用处。代价是每次重启都需要你输入密码,包括内核更新后的重启。对于数据卷,将其标记为 noauto,并在机器启动后通过 SSH 解锁一次。

vault UUID=8f14e45f-ceea-467a-9f9c-1b2c3d4e5f60 none luks,noauto
sudo cryptsetup open /dev/disk/by-uuid/8f14e45f-ceea-467a-9f9c-1b2c3d4e5f60 vault
sudo mount /srv/vault

如果加密设备本身是根文件系统,那么此时 sshd 尚未运行,因此你需要在 initramfs 中打开 shell。dropbear-initramfs 会提供该 shell。

sudo apt install -y dropbear-initramfs
sudo install -m 600 ~/.ssh/authorized_keys /etc/dropbear/initramfs/authorized_keys
sudo update-initramfs -u

重启后,以 root 身份连接并运行 cryptroot-unlock。initramfs 使用自己的主机密钥,因此客户端会因密钥发生变化而发出警告,除非使用 ssh -o HostKeyAlias=vps-initramfs root@your.server 进行连接。如果希望让该 shell 使用与运行中系统的 sshd 不同的端口,请在 /etc/dropbear/initramfs/dropbear.conf 中将 DROPBEAR_OPTIONS 设置为 -p 2222。

无论采用哪种方式,有一个事实不会改变。卷处于挂载状态时,主密钥位于内核内存中,而虚拟机的内存属于虚拟机监控程序。内存快照或主机级调试器都可以获取该密钥。因此,在租用的硬件上,全磁盘加密能够有效保护离开机房的磁盘,但无法有效保护正在运行的机器。要改变这一点,需要使用能防止主机读取客户机内存的硬件。这正是 VPS 上的机密计算 的作用,但它取决于处理器是否支持相关功能,而这需要服务提供商提供支持。

第 2 层:密钥永不接触存储服务器的加密文件系统

这一层解决了谨慎运维人员的疑虑,因为它采用了一种明确的架构:密文存储在存储 VPS 上,密钥存储在您自己的机器上。存储服务器保存的是无法读取的文件,因为密码短语从未存储在服务器上。

gocryptfs 是实现这一功能的直接工具。它是一个 FUSE(用户空间文件系统)层:一个目录中保存加密文件,另一个挂载点仅向您的用户显示明文。

sudo apt update && sudo apt install -y gocryptfs sshfs
mkdir -p ~/cipher ~/plain
sshfs backup@storage.example.com:/srv/vault ~/cipher
gocryptfs -init ~/cipher
gocryptfs ~/cipher ~/plain

gocryptfs -init 需要一个空目录,并会在那里写入 gocryptfs.conf。复制一个文件进去,然后查看两侧的内容。

cp /srv/data/invoice.pdf ~/plain/
ls ~/plain
ls ~/cipher
fusermount -u ~/plain

ls ~/plain 列出 invoice.pdf。ls ~/cipher 列出 gocryptfs.conf、gocryptfs.diriv 以及一个名称为 base64 字符串的文件,这就是服务提供商能看到的全部内容。执行 fusermount -u 后,明文视图消失,只剩下加密目录。

gocryptfs.conf 使用 scrypt 和您的密码短语封装主密钥,因此请备份该文件,并将密码短语与其分开保存。gocryptfs -info ~/cipher 打印现有目录的参数。gocryptfs -passwd ~/cipher 修改密码短语,但不会重新加密任何内容,因为密码短语始终只用于保护封装后的主密钥。

请明确仍会泄露哪些信息。gocryptfs 会加密文件内容和文件名,但不会隐藏文件数量、目录树结构、每个文件的大致大小或修改时间。读取密文目录的运维人员可以看到您上周二新增了 4000 个文件,其中一个大小为 2 GB。如果这种模式本身也属于敏感信息,则这一层保护不够。

如果目标是对象存储,或者您完全不想使用 FUSE 挂载,可以在传输层使用 rclone crypt remote 实现相同功能。它会包装另一个 remote,通过该包装器写入的所有内容都会在离开本机前加密。

sudo apt update && sudo apt install -y rclone
rclone obscure 'a-long-passphrase-you-chose'
rclone config

~/.config/rclone/rclone.conf 中的结果如下。remote = 行使第二个部分成为第一个部分的包装器。

[storage]
type = sftp
host = storage.example.com
user = backup
key_file = ~/.ssh/id_ed25519

[secret]
type = crypt
remote = storage:vault/rclone
filename_encryption = standard
directory_name_encryption = true
password = <first rclone obscure output>
password2 = <second rclone obscure output>
rclone sync /srv/data secret: --progress
rclone ls secret:
rclone ls storage:vault/rclone

rclone ls secret: 会显示真实文件名,因为 rclone 会在列出文件时为您解密文件名。rclone ls storage:vault/rclone 不使用 crypt wrapper 直接读取相同的数据,并显示加密后的名称。请各运行一次。两次列表之间的差异,就是服务提供商一侧不可读的证明。

有一个容易导致误解的警告。rclone obscure 不是加密。它是可逆的,rclone reveal 可以撤销它。因此,rclone.conf 与密码短语本身具有同等敏感性。将其权限设为 mode 600。如果该文件可能被其他人读取,请使用 rclone config 设置配置密码。这样,rclone 在使用任何 remote 前都会要求输入密码,或从 RCLONE_CONFIG_PASS 读取密码。

第 3 层:数据离开机器前先加密

对于备份,这是最重要的一层,也是工作量最小的一层,因为工具已经实现了这些功能。restic 和 BorgBackup 会在读取文件的机器上加密并验证每个数据块。存储 VPS 上的仓库从第一个字节起就是不可读的,因此存储服务器不会保存密钥,也不需要被信任。

sudo apt update && sudo apt install -y restic
umask 077
nano ~/.restic-pass
chmod 600 ~/.restic-pass
export RESTIC_REPOSITORY=sftp:backup@storage.example.com:/srv/vault/restic
export RESTIC_PASSWORD_FILE=$HOME/.restic-pass
restic init
restic backup /srv/data

使用编辑器将密码管理器中的长密码短语写入该文件,不要使用 echo,这样密码短语就不会出现在 shell 历史记录中。然后进行验证,并查看存储端能够看到哪些内容。

restic snapshots
restic check
restic check --read-data-subset=5%
ssh backup@storage.example.com 'ls /srv/vault/restic'

restic snapshots 列出已有内容。restic check 验证仓库结构,--read-data-subset=5% 下载并验证一部分真实数据,从而发现存储端静默返回错误字节的问题。通过 SSH 执行 ls 会列出目录 config、data、index、keys、locks 和 snapshots;而 data/ 下的每个文件都是一组加密数据块。restic 没有未加密模式:仓库密钥在 init 生成,并使用密码短语进行封装;每个数据包使用计数器模式下的 AES-256 加密,并使用 Poly1305-AES 进行身份验证。

Borg 也能实现相同的结果,但有一个重要区别。

sudo apt update && sudo apt install -y borgbackup
borg init --encryption=repokey-blake2 ssh://backup@storage.example.com/srv/vault/borg
borg create --stats ssh://backup@storage.example.com/srv/vault/borg::data-{now} /srv/data
borg list ssh://backup@storage.example.com/srv/vault/borg

Borg 在 init 中将加密设为可选项,--encryption=none 是有效选项,因此应明确指定该模式。之后无法更改该模式,除非创建新的仓库。repokey-blake2 会将密钥存储在仓库中,并使用密码短语进行封装,因此你只需保管密码短语这一项密钥材料。keyfile 模式则将密钥保存在客户端的 ~/.config/borg/keys 中。如果客户端丢失且没有导出的密钥,仓库将无法读取。无论使用哪种模式,都应导出密钥,并将其与两台机器分开保存。

borg key export ssh://backup@storage.example.com/srv/vault/borg ~/borg-key.txt
borg key export --paper ssh://backup@storage.example.com/srv/vault/borg

加密不会让副本具备持久性。服务提供商仍可能删除仓库,窃取凭据的人也可以删除仓库。请在其他位置保留第二个副本,并在存储端限制 SSH 密钥的权限,防止遭入侵的客户端清理备份历史。调度和保留策略应由备份任务本身负责:请参阅从 VPS 运行 restic 备份。如果存储服务器还作为你管理的另一台服务器的备份目标,请参阅将存储 VPS 与主 VPS 配对,了解该连接的网络配置。

加密是否免除 DSGVO 下的 AV-Vertrag?

不能。如果提供商代表您存储个人数据,那么该提供商就是您的处理者,DSGVO 第 28 条要求签署书面处理者协议,即 Auftragsverarbeitungsvertrag 或 AV-Vertrag。客户端加密不会改变这一点。对于无法访问密钥的一方所持有的密文是否仍属于其所处理的个人数据,各方观点不同。稳妥的做法是将此类安排视为处理活动,并照常签署协议。这是成本较低的选择。

加密改变的是数据泄露对您造成的后果。DSGVO 第 32 条将加密列为适当技术措施的示例,因此可以证明您采取了相应措施。第 33 条仍要求您在 72 小时内向监管机构报告个人数据泄露。第 34(3)(a) 条则能降低后续负担:如果数据已被处理为没有密钥就无法理解的形式,则无需通知每一名受影响人员。存放已关闭 LUKS 卷、且密钥位于另一家公司设备上的磁盘离开机架后,与存放明文数据的同一磁盘相比,所需提交的报告会完全不同。

这会带来两个实际后果。记录每个密钥由谁持有,以及密钥如何轮换。因为无法记录的加密措施,在需要说明其合理性时很难进行辩护。还要注意,加密与数据存储位置无关:如果您的义务是确保数据留在 EU 境内,那么这是托管决策,存储 VPS 的 EU 数据驻留及其成本 与本问题是两件不同的事。具体要求由您所在企业的数据保护官确定。上文的技术部分就是您应提供给对方的材料。

密钥应存放在哪里,以及如何证明它有效

存储 VPS 上的密钥不算密钥。存放在其保护的仓库中的口令短语也不算口令短语。两条规则可以覆盖大多数情况:密钥必须存放在存储提供商不负责运行的另一台机器上,并且还要保留一份离线副本,可以写在纸上,或存放在另一栋建筑中的设备上。

然后验证这套安排,因为未经测试的密钥只是猜测。找一台从未存放过你的数据的第三台机器,只向它提供密钥材料和仓库的读取权限,然后恢复一小部分数据。

export RESTIC_REPOSITORY=sftp:backup@storage.example.com:/srv/vault/restic
restic restore latest --target /tmp/restore-test --include /srv/data/invoice.pdf
sha256sum /tmp/restore-test/srv/data/invoice.pdf

校验和与原始数据匹配,可以证明两件事:密钥有效,并且可以从写入仓库以外的另一台机器读取仓库。每季度执行一次,并记录日期。

备份数据的实用方案

对于只存储而不提供服务的文件,采用简单方案即可。在存有数据的机器上使用 restic 或 Borg 加密,只将仓库发送到存储 VPS,并将密码短语保存在密码管理器中,同时保留一份离线副本。如果希望覆盖服务商处理退役磁盘的场景,也可以在存储卷上使用 LUKS,但要明确:对于正在运行的操作员,这不会提供额外防护。需要可浏览的目录而不是备份仓库时,再使用 gocryptfs 或 rclone crypt 远程端,并从自己的机器挂载它,这样密钥就不会写入租用的硬件。

如果还没有选择存储服务器,该选择会影响后续配置:存储 VPS 与普通 VPS 的区别解释了这些存储卷价格低且速度慢的原因;自托管存储的价格是否真的优于 Dropbox则决定了是否值得自行运行这套方案。

FAQ

VPS 上的全盘加密能防止托管服务商访问我的数据吗?

服务器运行时不能。只有使用密钥才能解密卷,因此密钥要么作为密钥文件保存在机器上,要么在您输入密钥后保存在内核内存中,而这两处都属于主机。运行中的虚拟机进行内存快照时,密钥也会被包含在内。LUKS 能防止的是磁盘离开机架:磁盘被更换、转售或报废时,机器处于关机状态,磁盘内容无法读取。针对这种情况使用 LUKS;针对服务商访问风险,则使用客户端加密。

已经存满数据的存储 VPS 还能加密吗?

不能使用 LUKS 原地加密。cryptsetup luksFormat 会擦除分区。有两种可行方案。连接第二个卷,对其加密,然后使用 rsync -aHAX --info=progress2 复制数据,最后重新格式化旧卷。或者保留现有文件系统,在新目录中使用 gocryptfs 或 rclone crypt 远程端写入密文,然后删除明文。删除虚拟磁盘上的明文,并不能保证旧数据块无法访问,因为主机存储层可能保留您无法控制的快照或副本。因此,凡是曾经以明文存储在该位置的数据,都应视为已经暴露。

如果服务商始终只能看到密文,我还需要 AV-Vertrag 吗?

需要。为您存储个人数据的服务商属于 Art. 28 DSGVO 所称的 Auftragsverarbeiter,无论这些数据在其磁盘上呈现何种形式,都需要签署书面协议。加密会改变数据泄露通知义务,但不会改变合同义务:如果没有密钥就无法理解数据,Art. 34(3)(a) 可免除向每位受影响人员分别通知的义务;但根据 Art. 33 向监管机构提交的 72 小时报告仍然适用。

如果我丢失了 restic 或 Borg 的口令,会发生什么?

数据会丢失。没有恢复途径,也没有任何支持工单能够解决问题,因为存储库密钥由该口令封装,无法通过其他方式解封。Borg 的 keyfile 模式还增加了另一项需要保管的内容,即客户端上的密钥文件,这正是 borg key export --paper 存在的原因。将口令保存在密码管理器中,并保留一份不存放在备份源机器上的离线副本。

对于存储 VPS,gocryptfs 还是 restic 更合适?

它们解决的是不同的问题。restic 用于备份,提供带版本的快照、重复数据删除,以及可从中恢复的存储库。gocryptfs 用于需要打开和编辑的实时文件,并以普通目录的形式挂载。如果两者都有需要,就同时使用它们,不要把备份存储库当作文件共享。