Instalación de Arch con cifrado por hardware: cryptsetup y OPAL

Tengo un SSD que además es self-encrypting drive (SED). Sigue las especificaciones de TCG/Opal. En este artículo instalo Arch con partición root cifrada, dejando /boot
sin cifrar. Está basado en este enlace.
Lo ideal es que la placa soporte el cifrado hardware por firmware. Este método es transparente para el sistema operativo. Desafortunadamente, la mía no tiene ninguna opción «HDD Security» en el menú del Setup («BIOS»).
Anteriormente se utilizaban métodos como PBAs, pero es complejo y no soporta bien suspensión S3. Afortunadamente, ahora cryptsetup 2.7 soporta cifrado OPAL y es casi igual de sencillo que cifrado por software.
Ejecutamos timedatectl para actualizar la hora del sistema:
root@archiso ~ # timedatectl
Local time: Tue 2024-06-11 14:57:50 UTC
Universal time: Tue 2024-06-11 14:57:50 UTC
RTC time: Tue 2024-06-11 14:57:50
Time zone: UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Reseteamos el disco. Nos pedirá el PSID (Physical security ID) presente en la etiqueta del SSD (ver imagen arriba):
root@archiso ~ # cryptsetup luksErase --hw-opal-factory-reset /dev/nvme0n1
Enter OPAL PSID:
WARNING!
========
WARNING: WHOLE disk will be factory reset and all data will be lost! Continue?
Are you sure? (Type 'yes' in capital letters): YES
Creamos particiones. En mi caso, serán 2, una EFI, que se montará en /boot, y otra raíz root:
root@archiso ~ # gdisk /dev/nvme0n1
GPT fdisk (gdisk) version 1.0.10
Partition table scan:
MBR: not present
BSD: not present
APM: not present
GPT: not present
Creating new GPT entries in memory.
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-3907029134, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-3907029134, default = 3907028991) or {+-}size{KMGTP}: +4GiB
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI system partition'
Command (? for help): p
Disk /dev/nvme0n1: 3907029168 sectors, 1.8 TiB
Model: CT2000T500SSD8
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): E5CC199A-A957-4864-9632-D60A7592C037
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 3907029134
Partitions will be aligned on 2048-sector boundaries
Total free space is 3898640493 sectors (1.8 TiB)
Number Start (sector) End (sector) Size Code Name
1 2048 8390655 4.0 GiB EF00 EFI system partition
Command (? for help): n
Partition number (2-128, default 2):
First sector (34-3907029134, default = 8390656) or {+-}size{KMGTP}:
Last sector (8390656-3907029134, default = 3907028991) or {+-}size{KMGTP}: +1280GiB
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8309
Changed type of partition to 'Linux LUKS'
Command (? for help): p
Disk /dev/nvme0n1: 3907029168 sectors, 1.8 TiB
Model: CT2000T500SSD8
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): E5CC199A-A957-4864-9632-D60A7592C037
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 3907029134
Partitions will be aligned on 2048-sector boundaries
Total free space is 1214285933 sectors (579.0 GiB)
Number Start (sector) End (sector) Size Code Name
1 2048 8390655 4.0 GiB EF00 EFI system partition
2 8390656 2692745215 1.3 TiB 8309 Linux LUKS
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/nvme0n1.
The operation has completed successfully.
Formateamos la partición EFI
root@archiso ~ # mkfs.fat -F 32 /dev/nvme0n1p1
mkfs.fat 4.2 (2021-01-31)
Formateamos la partición cifrada con LUKS, sólo por hardware (--hw-opal-only
). La contraseña de OPAL Admin y la de LUKS («passphrase») no tienen por qué ser las mismas:
root@archiso ~ # cryptsetup luksFormat /dev/nvme0n1p2 --type luks2 --hw-opal-only
WARNING!
========
This will overwrite data on /dev/nvme0n1p2 irrevocably.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/nvme0n1p2:
Verify passphrase:
Enter OPAL Admin password:
Verify passphrase:
cryptsetup luksFormat /dev/nvme0n1p2 --type luks2 --hw-opal-only 15.93s user 0.30s system 49% cpu 32.563 total
Se creará un volumen lógico en /dev/mapper/cifrada
. Comprobamos que se pueda abrir:
root@archiso ~ # cryptsetup open /dev/nvme0n1p2 cifrada
Enter passphrase for /dev/nvme0n1p2:
cryptsetup open /dev/nvme0n1p2 cifrada 6.46s user 0.08s system 90% cpu 7.249 total
root@archiso ~ # ls -l /dev/ma
ls: cannot access '/dev/ma': No such file or directory
2 root@archiso ~ # ls -l /dev/mapper
total 0
lrwxrwxrwx 1 root root 7 Jun 11 15:01 cifrada -> ../dm-0
crw------- 1 root root 10, 236 Jun 11 13:42 control
Formateamos el volumen lógico LUKS utilizando el sistema de ficheros que deseemos. En mi caso, BTRFS:
root@archiso ~ # mkfs.btrfs /dev/mapper/cifrada
btrfs-progs v6.8.1
See https://btrfs.readthedocs.io for more information.
Performing full device TRIM /dev/mapper/cifrada (1.25TiB) ...
NOTE: several default settings have changed in version 5.15, please make sure
this does not affect your deployments:
- DUP for metadata (-m dup)
- enabled no-holes (-O no-holes)
- enabled free-space-tree (-R free-space-tree)
Label: (null)
UUID: 1a86a74a-a3d0-402d-8b96-33af86bff39d
Node size: 16384
Sector size: 4096 (CPU page size: 4096)
Filesystem size: 1.25TiB
Block group profiles:
Data: single 8.00MiB
Metadata: DUP 1.00GiB
System: DUP 8.00MiB
SSD detected: yes
Zoned device: no
Features: extref, skinny-metadata, no-holes, free-space-tree
Checksum: crc32c
Number of devices: 1
Devices:
ID SIZE PATH
1 1.25TiB /dev/mapper/cifrada
Probamos a montar el volumen lógico formateado
root@archiso ~ # mount /dev/mapper/cifrada /mnt
Si estamos empleando BTRFS, puede ser interesante crear un subvolumen raíz @
y otro @snapshots
:
root@archiso ~ # btrfs subvolume create /mnt/@
Create subvolume '/mnt/@'
root@archiso ~ # btrfs subvolume create /mnt/@snapshots
Create subvolume '/mnt/@snapshots'
root@archiso ~ # ls -l /mnt
total 0
drwxr-xr-x 1 root root 0 Jun 11 15:02 @
drwxr-xr-x 1 root root 0 Jun 11 15:02 @snapshots
# Ahora desmonto y monto sólo el subvolumen raíz:
root@archiso ~ # umount /mnt
root@archiso ~ # mount -o subvol=@ /dev/mapper/cifrada /mnt
root@archiso ~ # ls -l /mnt
total 0
root@archiso ~ # mount --mkdir /dev/nvme0n1p1 /mnt/boot
root@archiso ~ # ls -l /mnt/boot
total 0
Instalamos paquetes con pacstrap. Aquí he incluído como extra amd-ucode
porque tengo CPU AMD, btrfs-progs
para utilidades BTRFS, así como vim
y openssh
.
root@archiso ~ # pacstrap -K /mnt base linux linux-firmware amd-ucode btrfs-progs grub vim openssh
Seguimos la instalación típica de arch:
# fstab
genfstab -U /mnt >> /mnt/etc/fstab
# chroot
arch-chroot /mnt
# zona horaria y sincronizar hora al hardware
ln -sf /usr/share/zoneinfo/Europe/Madrid /etc/localtime
hwclock --systohc
# locales
vim /etc/locale.gen
locale-gen
# hostname
vim /etc/hostname
Tal y como dice aquí, tenemos que editar la configuración de mkinitcpio. En mi caso estoy utilizando el initramfs por defecto, de tipo busybox. Ver enlace para initramfs de tipo systemd.
[root@archiso /]# cd /etc
# Hago backup de la configuración por si acaso:
[root@archiso etc]# cp -rp mkinitcpio.conf mkinitcpio.conf.bak
[root@archiso etc]# vim mkinitcpio.conf
# La línea HOOKS tiene que quedar así. En mi caso, sólo tuve que añadir "encrypt":
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt filesystems fsck)
Regeneramos initramfs:
[root@archiso etc]# mkinitcpio -P
==> Building image from preset: /etc/mkinitcpio.d/linux.preset: 'default'
==> Using default configuration file: '/etc/mkinitcpio.conf'
-> -k /boot/vmlinuz-linux -g /boot/initramfs-linux.img
==> Starting build: '6.9.3-arch1-1'
[...]
Seguimos con instalación típica de Arch. Contraseña:
[root@archiso etc]# passwd
New password:
Retype new password:
passwd: password updated successfully
Instalamos paquetes grub y efibootmgr:
[root@archiso ~]# pacman -S grub efibootmgr
Instalamos GRUB en /boot (esto es para UEFI, si el lector utiliza la clásica BIOS consulte el comando adecuado):
[root@archiso ~]# grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=mi_arch
Tenemos que configurar GRUB. Obtenemos el UUID de la partición LUKS (/dev/nvme0n1p2
, no del volumen lógico /dev/mapper/cifrada
):
[root@archiso default]# blkid
[...]
/dev/nvme0n1p2: UUID="<UUID_DE_PARTICION_LUKS>" SUBSYSTEM="HW-OPAL" TYPE="crypto_LUKS" PARTLABEL="Linux LUKS" PARTUUID="<PART_UUID_DE_PARTICION_LUKS>"
[...]
/dev/mapper/cifrada: UUID="<UUID_DEL_VOLUMEN_LOGICO>" UUID_SUB="<UUID_SUB_DEL_VOLUMEN_LOGICO>" BLOCK_SIZE="4096" TYPE="btrfs"
[...]
Configuramos GRUB en /etc/default/grub
. Buscamos esta línea
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet"
Añadimos lo siguiente:
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet cryptdevice=UUID=<UUID_DE_PARTICION_LUKS>:cifrada root=/dev/mapper/cifrada"
También es posible utilizar la ruta de la partición en lugar del id:
cryptdevice=/dev/nvme0n1p2:cifrada root=/dev/mapper/cifrada"
…pero prefiero utilizar el UUID, por si acaso cambiase por algún motivo el orden de las particiones o cómo denomina Linux al disco…
Regeneramos GRUB:
[root@archiso etc]# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/amd-ucode.img /boot/initramfs-linux.img
Found fallback initrd image(s) in /boot: amd-ucode.img initramfs-linux-fallback.img
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding boot menu entry for UEFI Firmware Settings ...
done
Ya podemos reiniciar con el comando «reboot». Debería aparecer el menú de selección de GRUB. Al iniciar, se mostrará este mensaje:
A password is required to access the cifrada volume:
Enter passphrase for /dev/nvme0n1p2:
Introducimos la contraseña de LUKS y deberíamos arrancar al login de texto de Arch.