dm-crypt/系统配置
- 若需要在启动早期阶段远程解密分区(例如,解密没有显示输出的设备或远程服务器),参考Dm-crypt/特殊应用#远程解锁分区。
- 使用支持直接将命令输出插入到所编辑的文本中的文本编辑器,可以便于在修改配置文件时输入UUID、PARTUUID等内容。例如,对于nano,可使用
Ctrl+t;对于vim或Neovim,可使用:read;对于mcedit,可使用Alt+u。接下来,可使用lsblk、blkid命令及恰当的参数,输出并插入所需内容。或者,也可以使用终端多路复用器的复制、粘贴功能。
若要从加密的根文件系统启动,initramfs需要包含能在早期用户空间(即initramfs阶段)解密卷的工具。一般使用内核参数指定要解密的卷。
下列小节介绍了如何配置mkinitcpio以生成所需的initramfs,以及所需的内核参数。
依据具体的配置,需要启用如下mkinitcpio钩子中的部分:
| busybox | systemd | Use case |
|---|---|---|
encrypt
|
sd-encrypt
|
若根分区是加密的,或者需要在根分区挂载之前挂载其它加密分区,则需要此钩子。在其它情况下,初始化脚本(例如,/etc/crypttab )将解锁非根分区,故无需此钩子。注意,此钩子必须放置在udev / systemd钩子之后。
|
keyboard
|
需要,用于使得在早期用户空间可以使用键盘。
提示:对于外设连接经常改变(即,后续启动时连接的外设可能和生成initramfs镜像时不一致)的系统(例如,使用外置键盘的笔记本、headless系统),建议将本钩子放置在
autodetect之前,以便始终包含所有键盘驱动。否则,若在生成镜像时未连接外置键盘,但在启动时连接,则外置键盘可能由于缺少驱动而无法正常工作。 |
|
keymap
|
sd-vconsole
|
在输入密码时,提供非标准键盘布局支持。必须放置在encrypt钩子之前。在 /etc/vconsole.conf 中设置键盘布局,详见控制台键盘配置持久化。
|
consolefont
|
在早期用户空间加载非默认字体。在 /etc/vconsole.conf 中设置字体,详见控制台键盘配置持久化。
|
|
其它可能需要的钩子参考相应配置方案的指南。
/etc/mkinitcpio.conf后,应当重新生成 initramfs。对于基于busybox的initramfs,使用encrypt钩子时,典型的配置如下:
/etc/mkinitcpio.conf
... HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt lvm2 filesystems fsck) ...
对于基于systemd的initramfs,使用sd-encrypt钩子时,典型的配置如下:
/etc/mkinitcpio.conf
... HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt lvm2 filesystems fsck) ...
encrypt钩子和sd-encrypt钩子需要设定的内核参数不同。但root、resume参数的设定方式相同。
root=参数指定了解密后的、实际的根文件系统:
root=device
- 若直接在加密设备上创建根文件系统,则为
/dev/mapper/dmname。 - 若在LVM上层使用加密的逻辑卷,则设置同上。
- 若在加密设备上使用LVM,则为
root=/dev/<卷组名称>/<逻辑卷名称>。
- 若使用
sd-encrypt钩子以及GPT分区自动挂载,则无需指定root=参数。详见在单一分区上配置LUKS。 - 若使用GRUB,并通过grub-mkconfig生成
grub.cfg配置文件,则无需手动设置root=参数。grub-mkconfig将自动检测解密后的根文件系统的UUID,并将其添加到grub.cfg中。
resume=device
-
device应当为用于休眠的设备文件或加密后的swap文件系统。对于单独的swap分区,该参数的值形如/dev/mapper/swap。详见Dm-crypt/交换分区加密。
encrypt不支持如下功能:
- 解密多个加密设备 (archlinux/mkinitcpio/mkinitcpio#231)。在initramfs中只能解密一个设备。
- 使用分离的LUKS头 (archlinux/mkinitcpio/mkinitcpio#234)。
- 设置某些crypttab支持的加密选项。
指定在冷启动时包含加密的根分区的设备(加密容器)。encrypt钩子通过该参数判断哪个设备包含了加密的系统。
cryptdevice=device:dmname:options
-
device:包含加密容器的设备。强烈建议使用块设备持久化命名指定。 -
dmname:解密后产生的设备映射器名称(device-mapper name),设备解密后,可通过/dev/mapper/dmname访问解密后的数据。 -
options:(可选),按逗号分隔的选项(例如,启用TRIM支持)。若无需额外指定选项,省略该参数(即,使用cryptdevice=device:dmname)。 - 若加密的根分区在LVM上,则应当首先激活LVM,并设置
device为/dev/<卷组名称>/<逻辑卷名称>。
cryptkey=参数。在启动时,将提示输入密码。该参数指定了encrypt钩子用于解锁cryptdevice的密钥文件。若密钥放置在默认位置(详见下),无需手动指定此参数。
取决于密钥文件的存储位置,该参数有三种指定方式。
若密钥文件存储在某设备上的文件系统中,作为该文件系统中的一个文件:
cryptkey=device:fstype:path
-
device:存储密钥文件的设备。强烈建议使用块设备持久化命名指定。 -
fstype:存储密钥文件的设备的文件系统。或者,指定auto表示自动探测文件系统类型。 -
path:在该文件系统中,密钥文件的绝对路径。
例如:cryptkey=LABEL=usbstick:vfat:/secretkey
若密钥文件直接对应某一设备上的一段比特流:
cryptkey=device:offset:size
offset表示比特流起始位置相对于设备首部的偏移量,size表示比特流长度。offset、size的单位都是字节。
例如:cryptkey=UUID=ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ:0:512从指定设备开头处读取512字节,作为密钥文件内容。
:”,需要使用反斜杠“\”转义。例如,对于ID为usb-123456-0:0的USB设备,可设置cryptkey=/dev/disk/by-id/usb-123456-0\:0:0:512。若密钥文件已包含在initramfs中[1]:
cryptkey=rootfs:path
例如:cryptkey=rootfs:/secretkey。
注意,若没有指定cryptkey,将默认尝试从initramfs中读取/crypto_keyfile.bin。[2]
该参数专门用于传递dm-crypt plain模式的加密选项。
参数格式如下:
crypto=hash:cipher:keysize:offset:skip
参数内容直接与cryptsetup选项有关。参见Dm-crypt/设备加密#plain模式的加密选项。
即使设备采用plain模式的默认选项加密,也必须指定crypto参数。但该参数的每个部分都可以留空:
crypto=::::
该参数的具体例子如下:
crypto=sha512:twofish-xts-plain64:512:0:
systemd-cryptsetup-generator是用于解锁加密设备的systemd单元生成器。其将读取部分内核参数、/etc/crypttab以进行生成。关于其的详细叙述和支持的选项,参见systemd-cryptsetup-generator(8)。
若使用sd-encryptmkinitcpio钩子、systemd dracut模块,则systemd-cryptsetup-generator将在initramfs阶段运行。
下面将介绍部分systemd-cryptsetup-generator读取的内核参数。
- 若系统中存在
/etc/crypttab.initramfs文件,则其将被复制到initramfs中的/etc/crypttab,以便指定需要在initramfs阶段解密的设备。该文件的语法详见#crypttab。若不存在/etc/crypttab.initramfs文件,则initramfs中将不包含/etc/crypttab。此时必须通过下面介绍的内核参数指定要解密的设备。 - 与
rd.luks参数不同,/etc/crypttab.initramfs不局限于使用UUID指定设备。可以使用任何块设备持久化命名方法。 - 若所有前提条件满足,则可以使用GPT分区自动挂载,在
/etc/crypttab.initramfs中可使用/dev/gpt-auto-root-luks代指加密的根分区,而无需手动指定UUID、PARTUUID等设备标识符。详见#systemd-gpt-auto-generator。 - 在解密过程中,输入的密码将被systemd-cryptsetup(8)缓存到内核钥匙环中,故若多个设备使用相同的密码,只需要输入一次密码。钥匙环中缓存的密码还可用于在后期用户空间中解锁crypttab中指定的其它设备。
- 所有
rd.luks相关参数都可多次指定,以解密多个设备。 -
rd.luks相关参数仅支持解密LUKS设备。若要解密dm-crypt plain模式加密的设备,必须在/etc/crypttab.initramfs中指定。语法详见#crypttab。 - 在修改
/etc/crypttab.initramfs后,需要重新生成 initramfs。
/etc/crypttab//etc/crypttab.initramfs配置文件和luks.*/rd.luks.*内核参数,则只有在内核参数中指定了的设备会被解密。对于crypttab中指定,但内核参数未指定的设备,将不会解密,并显示Not creating device 'devicename' because it was not specified on the kernel command line.警告。若要解密/etc/crypttab中指定的所有设备,不要设置luks.*内核参数,但仍可使用rd.luks.*内核参数指定initramfs阶段要解密的设备。若要解密/etc/crypttab.initramfs中指定的所有设备,不要设置任何luks.*、rd.luks.*内核参数。rd.luks.name,则无需指定rd.luks.uuid。rd.luks.uuid=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
使用此参数指定要在启动过程中解密的设备的UUID。
默认情况下,解密后的设备将被映射到/dev/mapper/luks-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX,其中XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX是LUKS所在分区的UUID。
rd.luks.uuid。rd.luks.name=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=name
本参数用于指定要解密的设备,并设置解密后设备的映射名称,其中XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX是LUKS所在分区的UUID。name与encrypt的cryptdevice配置中dmname参数作用相同。
例如,若设置rd.luks.name=12345678-9abc-def0-1234-56789abcdef0=root,则将解密UUID为12345678-9ABC-DEF0-1234-56789ABCDEF0的分区,解密后的分区可在/dev/mapper/root访问。
指定用于解密特定UUID的分区所需要的密钥文件。与encrypt钩子的cryptkey参数不同,密钥文件位置没有默认值。
若密钥文件已包含在initramfs中:
rd.luks.key=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=/path/to/keyfile
或者:
rd.luks.key=/path/to/keyfile
/etc/cryptsetup-keys.d/name.key,则无需指定rd.luks.key参数。若密钥文件在另一设备上:
rd.luks.key=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=/path/to/keyfile:UUID=ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ
将UUID=ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ替换为密钥文件所在设备的UUID。
- 若存储密钥文件的设备使用的文件系统与根文件系统不同,则必须在initramfs中包含所需内核模块。
- 默认情况下,若
rd.luks.key指定了位于另一设备上的密钥文件,但该设备在启动过程中不可用,则不会回退到使用密码解密。若需要回退,在rd.luks.options参数中指定keyfile-timeout=选项。例如,若要等待该设备10秒,使用:rd.luks.options=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=keyfile-timeout=10s
rd.luks.options=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=options
或者:
rd.luks.options=options
指定用于解密特定UUID的分区时的额外选项。若不指定UUID,则指定的选项将用于所有解密过程,除非在其它地方(例如,crypttab)单独为该解密过程指定了选项。
该参数作用与crypttab的选项字段相同,和crypttab选项字段的格式也相同,都使用逗号分隔,使用option=value指定带有值的选项。该参数与encrypt钩子的cryptdevice参数类似。
例如:
rd.luks.options=timeout=10s,discard,password-echo=no,tries=1
在启动时,能用于输入密码解密卷的时间受两个选项影响:
-
rd.luks.options=timeout=mytimeout:询问密码的超时时间 -
rootflags=x-systemd.device-timeout=mytimeout:systemd等待根文件系统所在设备出现的时间(默认为90秒)
若要完全关闭超时,将两个超时时间都设为0:
rd.luks.options=timeout=0 rootflags=x-systemd.device-timeout=0
当输入密码时,systemd-cryptsetup默认将对每个输入的字符回显星号(*)。而encrypt钩子在输入时将不回显。要禁用回显,设置password-echo=no选项:
rd.luks.options=password-echo=no
若系统有TPM2芯片,或者使用了FIDO2兼容的安全密钥。可以使用它们而非密码、密钥文件来解密卷。
除了rd.luks.uuid/rd.luks.name外,还需添加如下参数:
- 若使用TPM2芯片:
rd.luks.options=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=tpm2-device=auto - 若使用FIDO2密钥:
rd.luks.options=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=fido2-device=auto
此外,也可以在/etc/crypttab.initramfs中指定上述参数:
/etc/crypttab.initramfs
root UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX none tpm2-device=auto
上述配置中,使用UUID指定加密设备名称,解密后的设备使用root挂载名称(解密后的设备可通过/dev/mapper/root访问),不使用密码解密,而是从TPM2设备获取密钥。
注意,若要使用TPM2解密,在密码字段必须填写none或者-,而不能留空。否则,tpm2-device=auto将被识别为密码,在启动时,将尝试使用该“密码”解密,并在解密失败时要求手动输入密码,而不尝试使用TPM2解密。
若通过UUID指定设备,请确保其是在磁盘上实际存在的加密容器的UUID,而不是解密后的根文件系统的UUID。
当使用分离的LUKS头时,使用该参数可指定存储加密数据的块设备。同时必须在rd.luks.options中指定LUKS头的位置。
详见Dm-crypt/特殊应用#在加密系统时使用分离的LUKS头。
若满足Systemd#GPT分区自动挂载中的所有要求,则可以不设置rd.luks相关内核参数。systemd-cryptsetup-generator将自动探测并尝试解密LUKS加密的根分区。
udev将创建/dev/gpt-auto-root、/dev/gpt-auto-root-luks符号链接,分别指向解密后的根分区、存储根分区加密容器的分区。可在相关配置文件中使用,作为对相关分区的持久性引用。
在指定crypttab选项时,可以在/etc/crypttab.initramfs中使用/dev/gpt-auto-root-luks作为设备名称。例如,一个不设置额外选项、使用自动解密的配置文件如下:
/etc/crypttab.initramfs
root /dev/gpt-auto-root-luks none tpm2-device=auto,fido2-device=auto
与fstab相似,/etc/crypttab(encrypted device table,加密设备表)包含了一系列需要在启动过程中挂载的文件系统,不同之处在于crypttab中指定的是需要被解密的加密设备。可以使用该文件自动挂载加密的swap设备、非根文件系统。
crypttab在fstab之前处理,以便在尝试挂载加密容器中的文件系统之前,先解密加密容器。
注意,crypttab在系统启动后(后期用户空间,挂载根文件系统后)才被处理,因此在加密了根分区的情况下,不能用于替代mkinitcpio钩子、内核参数配置。crypttab将由systemd-cryptsetup-generator(8)处理。
该文件语法详见crypttab(5)。此外,下文还提供了一些例子。在#在启动时挂载节中还包含了使用UUID挂载加密设备的方法。
- 若设置了
nofail选项,则密码输入界面可能会在输入过程中消失。因此,只应在使用密钥文件时设置nofail选项。 - 对于dm-crypt plain模式加密的设备,必须指定
plain选项,以便systemd-cryptsetup(8)正确识别。参见systemd issue 442。
/etc/crypttab
# 示例crypttab文件。字段:名称、底层设备、密码、cryptsetup选项 # Mount /dev/lvm/swap re-encrypting it with a fresh key each reboot swap /dev/lvm/swap /dev/urandom swap,cipher=aes-xts-plain64,size=256,sector-size=4096 # Mount /dev/lvm/tmp as /dev/mapper/tmp using plain dm-crypt with a random passphrase, making its contents unrecoverable after it is dismounted. tmp /dev/lvm/tmp /dev/urandom tmp,cipher=aes-xts-plain64,size=256 # Mount /dev/lvm/home as /dev/mapper/home using LUKS, and prompt for the passphrase at boot time. home /dev/lvm/home # Mount /dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx as /dev/mapper/backup using LUKS, with a passphrase stored in a file. backup UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /home/alice/backup.key # Unlock /dev/disk/by-partuuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx using the only available TPM, naming it myvolume myvolume PARTUUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none tpm2-device=auto
修改crypttab后,若要立即测试并应用更改,先使用daemon-reload重新加载systemd配置,然后启动新生成的systemd-cryptsetup@name.service单元。
# cryptsetup status name
/dev/mapper/name is active. type: ... cipher: ... keysize: ... bits key location: ... device: /dev/sdxN sector size: ... offset: ... sectors size: ... sectors mode: ... flags: ...
有关systemd-cryptsetup@name.service单元的更多信息,详见#按需挂载。
若要在启动过程中挂载加密设备,将目标设备的UUID加入到/etc/crypttab。可使用lsblk -f查看目标设备的UUID。
crypttab中的条目形如:
/etc/crypttab
externaldrive UUID=2f9a8428-ac69-478a-88a2-4aa458565431 none timeout=180
若设备使用LUKS2加密,也可以通过LUKS2 label指定:
/etc/crypttab
externaldrive LABEL=encrypted-ext-drive-1 none timeout=180
注意,LUKS2头中设定的label和加密容器上层的文件系统的label是不同的概念。
上述条目中,第一项为设备解密后的设备映射名。none选项表示在启动时手动输入解密密码。timeout选项指定了输入密码的超时时间。
crypttab中的某一条目对应设备的密码与之前的条目相同,则可设置第三个选项为none,将自动使用缓存的密码进行解密。crypttab中设置的timeout选项只决定输入密码的超时时间。此外,systemd还有等待设备可用的超时时间(默认为90秒)。这两个超时时间是独立的。因此,即使crypttab中的timeout选项设置值长于90秒(设置为0表示无限时),systemd仍然只会等待某个设备90秒。要修改systemd的等待时间,可在fstab中,为相应的设备设置x-systemd.device-timeout选项(详见systemd.mount(5))。建议对于启动时要挂载的加密设备,将crypttab中的timeout与fstab中的x-systemd.device-timeout设置为相同的值。若根文件系统是加密的,可在其中存储解密其它设备的密钥文件。由于根文件系统是加密的,因此在系统关机时,密钥文件是安全的。存储密钥文件的好处在于,在启动时,可通过设置crypttab,自动通过密钥文件解密其它设备,而无需输入密码。
例如,解密指定UUID的设备:
/etc/crypttab
home-crypt UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX /etc/cryptsetup-keys.d/home-crypt.key
- 若没有指定密钥文件,systemd-cryptsetup(8)会自动尝试从
/etc/cryptsetup-keys.d/name.key、/run/cryptsetup-keys.d/name.key读取密钥文件。[3] - 若使用dm-crypt plain模式,需要在
/etc/crypttab中指定相关加密选项。参见#crypttab节中提到的systemd相关注意事项。
之后,使用/etc/crypttab中定义的设备映射名称,添加对应的/etc/fstab条目:
/etc/fstab
/dev/mapper/home-crypt /home ext4 defaults 0 2
/dev/mapper/home-crypt已经是持久性的、唯一的分区映射名,可直接使用,而无需通过UUID指定。若要使用UUID指定,应当注意加密容器中文件系统的UUID和包含加密容器的分区的UUID不同。
在启动时,systemd的生成器将自动处理多层映射的块设备。
例如,可以先建立RAID,在此之上创建加密卷,再在加密卷上创建LVM逻辑卷,形成多层映射:
$ lsblk -f
─sdXX linux_raid_member
│ └─md0 crypto_LUKS
│ └─cryptedbackup LVM2_member
│ └─vgraid-lvraid ext4 /mnt/backup
└─sdYY linux_raid_member
└─md0 crypto_LUKS
└─cryptedbackup LVM2_member
└─vgraid-lvraid ext4 /mnt/backup
启动过程中,将询问密码,并自动挂载所有层级的设备。
对于非根分区,只要正确设置了相应crypttab、fstab条目,就无需额外添加mkinitcpio钩子或修改相关配置。注意/etc/crypttab只适合于处理非根分区的挂载。若在挂载在RAID上的根分区时使用了mdadm_udev钩子,则需要额外配置/etc/madadm.conf并更新initramfs,以正确加载RAID配置。
若在/etc/crypttab中有如下条目:
/etc/crypttab
externaldrive UUID=... none noauto
则若要打开externaldrive,除了直接使用cryptsetup外:
# cryptsetup open UUID=... externaldrive
还可启动systemd-cryptsetup@externaldrive.service。这样,无需在打开加密卷时手动输入加密选项。若需要密码进行解锁,启动单元时将提示输入。
有关单元文件由systemd-cryptsetup-generator(8)生成。可通过如下命令查看所有生成的单元文件:
$ systemctl list-unit-files | grep systemd-cryptsetup
若在crypttab中指定了某一设备,即使该设备并不需要在启动时就完成挂载,在默认情况下,cryptsetup服务仍会阻塞地等待该设备完成挂载,再继续启动进程。可以通过指定nofail选项避免阻塞等待。添加该选项后,将从指定设备的挂载服务(systemd mount service)中移除Before=cryptsetup.target,避免启动过程阻塞。若设备不被启动过程依赖,且使用密钥文件解锁,则可使用nofail选项加快启动过程。
/etc/crypttab
data UUID=d0d0d110-0a71-4ed6-936a-304969ea36af /etc/cryptsetup-keys.d/data.key nofail
若使用了Plymouth,需要确保使用了正确的模块(详见Plymouth#mkinitcpio),否则Plymouth将覆盖密码输入提示符,导致无法解密设备,系统无法启动。
若需要使用键盘输入密码(特别是键盘通过USB拓展坞连接时),或要从特定文件系统上读取密钥文件(且该文件系统在生成initramfs时未挂载),可能需要手动向mkinitcpio的MODULES数组中添加需要的模块。详见Mkinitcpio#模块(MODULES)。键盘、文件系统需要的模块名称可参见Mkinitcpio/极简_initramfs#整理模块。
对于外设连接经常改变(即,后续启动时连接的外设可能和生成initramfs镜像时不一致)的系统,需要将keyboard钩子放置到autodetect钩子之前,以包含所有键盘有关模块,而不是只包含在生成initramfs时连接到计算机的键盘的模块。详见Mkinitcpio#常用钩子。