跳至內容

dm-crypt/交换分区加密

出自 Arch Linux 中文维基

本文介紹了多種加密交換分區的方法,可滿足不同的需求。若在每次重啟時都重新對交換分區進行加密(使用不同密鑰)的方式,可避免換出到交換分區上的敏感文件片段因未被覆蓋而長期存在,從而更好地保護數據。然而,若使用重新加密,則無法使用休眠功能。

無需休眠支持

[編輯 | 編輯原始碼]

若無需使用休眠功能,則可以通過配置/etc/crypttab,在每次啟動時以隨機密碼,使用dm-crypt plain模式進行解密。在關機時,隨機密碼將被丟棄,設備上只含有加密的、無法訪問的交換數據。

要使用該配置,只需要取消注釋/etc/crypttab中以swap開頭的一列,並修改「設備」(device)參數指向交換分區,例如:

/etc/crypttab
# <name>   <device>            <password>          <options>
swap      /dev/sdX#    /dev/urandom   swap,cipher=aes-xts-plain64,size=512,sector-size=4096

上述配置將解密/dev/sdX#,並映射到/dev/mapper/swap。之後,像普通的swap分區一樣,將/dev/mapper/swap添加到/etc/fstab中,即可完成交換分區配置。若之前已經配置了非加密的交換分區,需要將其禁用(或直接將其在fstab中的條目指向/dev/mapper/swap)。上面給出的選項應當足以應對大多數場景。若需要了解每個選項的詳細解釋,可參見crypttab(5)point cryptsetup FAQ 2.3

警告:上述配置中「設備」參數對應的設備的數據將被永久清除。不要使用內核的簡單命名(例如,/dev/sda, /dev/sdb)指定設備,簡單命名的順序可能在每次啟動時都不同,導致設備數據被意外清除。建議使用如下方式指定:
注意:有時,交換分區配置可能失敗,參見systemd issue 10179

若要使用by-id持久化命名,首先,找到swap分區對應的設備:

# find -L /dev/disk -samefile /dev/sdaX
/dev/disk/by-id/ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470-partX
/dev/disk/by-id/wwn-0x60015ee0000b237f-partX

之後,修改配置文件,使用持久化引用(若上述命令返回多個結果,任選一個即可):

/etc/crypttab
# <name>  <device>                                                         <password>     <options>
swap      /dev/disk/by-id/ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470-partX  /dev/urandom   swap,cipher=aes-xts-plain64,size=512,sector-size=4096

重啟並激活加密交換後,使用swapon -s命令可以看到交換分區對應映射後的設備(例如,/dev/dm-1);使用lsblk命令,可看到交換分區的FSTYPEcrypt。由於每次啟動時都重新加密並格式化交換分區,/dev/mapper/swap的文件系統UUID會在每次啟動時變化。

注意:若swap分區之前曾用作LUKS加密卷,則crypttab不會覆蓋該LUKS加密卷以創建加密的swap分區。這是一項安全措施,用於避免在crypttab中錯誤指定swap分區對應的設備時,造成數據丟失。若確定要使用之前的LUKS加密卷作為swap分區,必須先覆蓋LUKS頭

文件系統UUID和文件系統標籤

[編輯 | 編輯原始碼]

在crypttab中使用內核簡單命名(例如,/dev/sdX#)、ID命名(例如,/dev/disk/by-id/ata-SERIAL-partX)指定加密交換分區的目標設備有較大風險,設備名稱、分區結構的細微變化都可能導致指向錯誤的設備,從而造成數據丟失。使用PARTLABEL、PARTUUID(與分區,而不是文件系統、設備綁定)的風險相對較小,但若打算將目標設備用作其它用途,而忘記移除crypttab中的條目,數據仍可能被覆蓋(文件系統改變,分區不改變)。

更可靠的方法是使用文件系統標籤或文件系統UUID。但在默認情況下,每次重啟時,dm-crypt和mkswap都將覆蓋目標分區上的內容,導致文件系統標籤和文件系統UUID被移除。不過,可以指定swap分區的起始偏移量,以在設備開始處放置另一個空的、容量較小的文件系統。該文件系統僅用於提供持久性的文件系統UUID和文件系統標籤。

使用指定文件系統標籤創建文件系統

# mkfs.ext2 -L cryptswap /dev/sdX# 1M

設備名後的1M參數限制文件系統的大小為1MiB,為之後加密的交換分區留出空間。

# blkid /dev/sdX#
/dev/sdX#: LABEL="cryptswap" UUID="b72c384e-bd3c-49aa-b7a7-a28ea81a2605" TYPE="ext2"

這樣,無論設備名稱、分區數量如何變化,始終可以使用文件系統UUID或文件系統標籤指向/dev/sdX#

接下來,配置/etc/crypttab/etc/fstab條目即可:

/etc/crypttab
# <name> <device>         <password>    <options>
swap     LABEL=cryptswap  /dev/urandom  swap,offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096

注意偏移量的指定(offset=2048),偏移量的單位為512位元組的扇區(不受dm-crypt扇區大小的影響),因此offset=2048相當於1MiB,跳過了提供UUID的文件系統的區域,因此不影響文件系統UUID和文件系統標籤,並正確處理了數據對齊。

/etc/fstab
# <filesystem>    <dir>  <type>  <options>  <dump>  <pass>
/dev/mapper/swap  none   swap    defaults   0       0

在本配置中,只會嘗試使用特定文件系統標籤的設備作為加密交換分區,而不受設備名稱影響。若打算將加密交換分區用作其它用途,當格式化時,文件系統標籤被覆蓋,因此/etc/crypttab不會在下次啟動時意外覆蓋新的文件系統及數據。

在桌面環境中關閉休眠

[編輯 | 編輯原始碼]

桌面環境可能無法自動檢測到swap分區已被隨機密碼加密,不能用作休眠,仍錯誤顯示休眠按鈕。

若使用Xfce,可通過如下命令隱藏「休眠」、「混合睡眠」按鈕:

$ xfconf-query -c xfce4-session -np /shutdown/ShowHibernate -t bool -s false
$ xfconf-query -c xfce4-session -np /shutdown/ShowHybridSleep -t bool -s false

需要休眠支持

[編輯 | 編輯原始碼]

下面介紹在需要進行休眠的情況下,設置加密swap的三種方法。若已經使用其中一種方法完成設置,需要注意系統換出的敏感數據可能在交換分區/交換文件中保留較長時間,直到被覆蓋。若要降低相關風險,可以設置系統任務,在特定時機(例如,系統關機時)重新加密交換分區/重置交換文件。

使用交換文件

[編輯 | 編輯原始碼]

交換文件可放置在加密設備的文件系統中。依照Swap#交換文件中的方法創建交換文件,並完成休眠設置即可。

若採用加密根文件系統的配置,並使用基於systemd的initrd,則配置加密交換文件非常簡單、靈活。在完成配置加密的根文件系統後,只需要按常規方式創建並激活交換文件,並將其添加到/etc/fstab中即可,無需額外配置。

注意:在設置resume=內核參數時,注意其必須指向解密後產生的映射設備,該映射設備包含存儲有交換文件的文件系統。

使用交換分區

[編輯 | 編輯原始碼]
注意:若要重用當前正在被系統使用的交換分區,必須先以root身份執行swapoff /dev/device將其禁用,並在/etc/crypttab中移除相關條目。

使用cryptsetup-luksFormat(8)創建容納交換分區的加密容器:

# cryptsetup luksFormat --label swap /dev/device

打開該容器,並映射到/dev/mapper/swap

# cryptsetup open /dev/disk/by-label/swap swap

在映射設備上創建swap文件系統:

# mkswap /dev/mapper/swap

若不使用Systemd#GPT分區自動掛載,需要將映射設備加入/etc/fstab中:

/dev/mapper/swap none swap defaults 0 0

要啟用休眠,添加resume=/dev/mapper/swap內核參數。詳見電源管理/掛起與休眠#傳遞休眠位置到_initramfs

使用TPM

[編輯 | 編輯原始碼]

通過在TPM中存儲密鑰,可自動完成交換分區的加密與解密。

可以使用systemd-cryptenroll將密鑰註冊到LUKS容器和TPM中。之後,清除之前創建的密碼槽位:

# systemd-cryptenroll --tpm2-device auto /dev/device
# systemd-cryptenroll --wipe-slot password /dev/device

可通過如下命令驗證結果:

# systemd-cryptenroll /dev/device
SLOT TYPE
   0 tpm2

在initramfs中解密分區

[編輯 | 編輯原始碼]

若要從加密的交換分區中喚醒,必須在initramfs中解密該分區。

mkinitcpio
[編輯 | 編輯原始碼]
基於systemd的initramfs
[編輯 | 編輯原始碼]

若使用基於systemd的inintramfs(使用sd-encrypt鉤子),則可使用如下任意一個方案:

例如,若使用TPM加密交換分區:

/etc/crypttab.initramfs
swap UUID=56f8ee97-54b3-4a65-9282-688deb922527 none tpm2-device=auto
基於busybox的initramfs
[編輯 | 編輯原始碼]

若使用基於busybox的initramfs(使用encrypt鉤子),需進行如下操作。

若交換分區所在設備與根文件系統的不同,則其不會被encrypt鉤子打開。由於從休眠中喚醒的過程在讀取/etc/crypttab前進行,不能在/etc/crypttab中進行配置以打開加密的交換分區,而需要修改/etc/mkinitcpio.conf並創建自定義鉤子,以在喚醒開始之前打開加密的交換分區。

注意:本節只適用於encrypt鉤子,其只能解密單個設備(archlinux/mkinitcpio/mkinitcpio#231);若使用sd-encrypt鉤子,則可以解密多個設備(包括加密的交換分區),詳見Dm-crypt/系統配置#systemd-gpt-auto-generator

mkinitcpio-openswapAUR中包含了所需的鉤子及配置文件。

警告:在系統休眠且還未恢復時,在initramfs中掛載文件系統非常危險且可能導致數據丟失。若使用密鑰文件解密,密鑰文件不應保存到任何休眠時已掛載的文件系統上。
注意:為了降低文件系統損壞的可能性,上述包中的腳本使用了-o ro,noload掛載選項。這些選項適用於ext4文件系統,若使用其它文件系統,需修改openswap.conf,使用作用相似的選項。

openswap鉤子添加到/etc/mkinitcpio.confHOOKS數組中,注意應當添加到filesystem鉤子之前,encrypt鉤子之後。再在openswap鉤子之後添加resume鉤子。

HOOKS=(... encrypt openswap resume filesystems ...)

最後,重新生成 initramfs

啟動時,openswap鉤子將打開加密的交換分區,以便內核從中喚醒。若使用自定義鉤子進行喚醒操作,需確保在HOOKS數組中,相關鉤子放置在openswap之後。注意,由於在initrd階段便掛載了交換分區,/etc/crypttab中無需包含交換分區相關條目。

dracut
[編輯 | 編輯原始碼]

創建密鑰文件:

# dd bs=512 count=4 if=/dev/random iflag=fullblock | install -m 0600 /dev/stdin /etc/cryptsetup-keys.d/swap.key

將密鑰文件添加到LUKS卷:

# cryptsetup luksAddKey /dev/device /etc/cryptsetup-keys.d/swap.key

修改dracut配置,加入resume模塊,並將swap.key文件加入到initramfs中(詳見Dracut#休眠):

/etc/dracut.conf.d/resume-from-hibernate.conf
add_dracutmodules+=" resume "
install_items+=" /etc/cryptsetup-keys.d/swap.key "

重新生成 initramfs

在內核參數中添加與交換分區對應的rd.luks.namerd.luks.key參數。

修改後的內核命令行應當與下例相似:

kernel /vmlinuz-linux cryptdevice=/dev/sda2:root root=/dev/mapper/root resume=/dev/mapper/swap rd.luks.name=fd839505-3213-4603-9a70-c5a96a24768f=swap rd.luks.key=/etc/cryptsetup-keys.d/swap.key ro

在LUKS上配置LVM

[編輯 | 編輯原始碼]

若交換分區位於LVM卷組內,且對應卷組在initramfs中被激活,只需要按照電源管理/掛起與休眠#休眠中的步驟進行配置即可。

已知問題

[編輯 | 編輯原始碼]
  • 系統日誌中出現形如Stopped (with error) /dev/dm-1的錯誤。詳見systemd issue 1620