dm-crypt/交换分区加密 - Arch Linux 中文维基

跳至內容

# dm-crypt/交换分区加密

出自 Arch Linux 中文维基
< Dm-crypt

翻譯狀態：

- 本文（或部分內容）譯自 Dm-crypt/Swap encryption，最近一次同步於 2025-07-25，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

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

## 無需休眠支持

若無需使用休眠功能，則可以通過配置`/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`）指定設備，簡單命名的順序可能在每次啟動時都不同，導致設備數據被意外清除。建議使用如下方式指定：

- 使用`by-id`、`by-path`。然而，當出現硬體變化時，兩者仍可能會改變，詳見塊設備持久化命名#通過_id_和_通過路徑。
- 使用PARTLABEL、PARTUUID。
- 使用LVM邏輯卷名稱。
- 使用#文件系統UUID和文件系統標籤中介紹的方法。由於每次啟動時，都將重新加密設備，並使用`mkswap`重新格式化swap分區， 不能直接使用文件系統標籤和文件系統UUID，參見cryptsetup FAQ。但可通過間接手段達成目的。

注意：有時，交換分區配置可能失敗，參見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`命令，可看到交換分區的`FSTYPE`為crypt。由於每次啟動時都重新加密並格式化交換分區，`/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鉤子），則可使用如下任意一個方案：

- 正確設置`rd.luks.uuid=`內核參數以解密交換分區；
- 編輯`crypttab.initramfs`，並重新生成 initramfs。

例如，若使用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.conf`的`HOOKS`數組中，注意應當添加到`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.name`、`rd.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。

分類：​

- 靜態數據加密

dm-crypt/交换分区加密
新增話題