This is a short description of steps to have new secure Void Linux installation with following features:
/boot
partition on USB stick (not encrypted)- full disk encryption with detached LUKS header on USB stick
- LVM on top of the encrypted partition
- remote unlocking of the encrypted partition
mkinitcpio
to generate initramfs
This manual is heavily based on Void Linux FDE documentation, Void Linux kernel documentation, Arch Linux LVM on LUKS documentation, Arch Linux detached LUKS header documentation and Arch Linux remote unlocking documentation.
This manual assumptions:
/dev/sda
- USB stick/dev/nvme0n1
- internal drive- wired network connection
Be very careful with drive names! Check command syntax twice before pressing Enter key!
To start prepare Void Linux installation media (must be separate USB drive or whatever else you have to start the process) and boot using it.
You are expected to run all commands below on a target computer running one of live Void Linux installers (some steps can be made beforehand on another computer though).
# dd if=/dev/urandom of=/dev/sda bs=1M oflag=direct status=progress
# fdisk /dev/sda
USB stick must have dos label and two partitions - EFI (to mount as /boot/efi
) and Linux (to mount as /boot
).
# fdisk -l /dev/sda
Disk /dev/sda: 7.45 GiB, 8002732032 bytes, 15630336 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0bfa9df7
Device Boot Start End Sectors Size Id Type
/dev/sda1 2048 1050623 1048576 512M ef EFI (FAT-12/16/32)
/dev/sda2 1050624 3147775 2097152 1G 83 Linux
# mkfs.vfat /dev/sda1
# mkfs.ext2 /dev/sda2
# mount /dev/sda2 /mnt
# dd if=/dev/zero of=/mnt/header.img bs=16M count=1
# dd if=/dev/urandom of=/dev/nvme0n1 bs=1M oflag=direct status=progress
# fdisk /dev/nvme0n1
Internal drive must have gpt label and single Linux partition.
# fdisk -l /dev/nvme0n1
Disk /dev/nvme0n1: 931.51 GiB, 1000204886016 bytes, 1953525168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 45526BA4-E54F-2641-9A90-5735D0C3C772
Device Start End Sectors Size Type
/dev/nvme0n1p1 2048 1953523711 1953521664 931.5G Linux filesystem
# cryptsetup luksFormat --header /mnt/header.img /dev/nvme0n1p1
# cryptsetup open --header /mnt/header.img /dev/nvme0n1p1 cryptlvm
# pvcreate /dev/mapper/cryptlvm
# vgcreate lvgroup /dev/mapper/cryptlvm
# lvcreate -L 8G -n swap lvgroup
# lvcreate -L 32G -n root lvgroup
# lvcreate -l 100%FREE -n home lvgroup
# lvreduce -L -256M lvgroup/home
# mkfs.ext4 /dev/lvgroup/root
# mkfs.ext4 /dev/lvgroup/home
# mkswap /dev/lvgroup/swap
# umount /mnt
# mount /dev/lvgroup/root /mnt
# mkdir /mnt/home
# mount /dev/lvgroup/home /mnt/home
# mkdir /mnt/boot
# mount /dev/sda2 /mnt/boot
# mkdir /mnt/boot/efi
# mount /dev/sda1 /mnt/boot/efi
# swapon /dev/lvgroup/swap
# mkdir -p /mnt/var/db/xbps/keys
# cp /var/db/xbps/keys/* /mnt/var/db/xbps/keys/
# xbps-install -Sy -R https://repo-default.voidlinux.org/current -r /mnt base-system cryptsetup grub-x86_64-efi lvm2
# xchroot /mnt
[xchroot /mnt] # chown root:root /
[xchroot /mnt] # chmod 755 /
[xchroot /mnt] # passwd root
[xchroot /mnt] # echo void > /etc/hostname
[xchroot /mnt] # echo "LANG=en_US.UTF-8" > /etc/locale.conf
[xchroot /mnt] # echo "en_US.UTF-8 UTF-8" >> /etc/default/libc-locales
[xchroot /mnt] # xbps-reconfigure -f glibc-locales
Use blkid
to find out UUID of USB stick partitions.
# <file system> <dir> <type> <options> <dump> <pass>
tmpfs /tmp tmpfs defaults,nosuid,nodev 0 0
/dev/lvgroup/root / ext4 defaults 0 0
/dev/lvgroup/home /home ext4 defaults 0 0
/dev/lvgroup/swap swap swap defaults 0 0
UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" /boot ext2 defaults 0 0
UUID="xxxx-xxxx" /boot/efi vfat defaults 0 0
[xchroot /mnt] # ln -s /etc/sv/sshd /etc/runit/runsvdir/default/
[xchroot /mnt] # ln -s /etc/sv/dhcpcd-eth0 /etc/runit/runsvdir/default/
[xchroot /mnt] # ssh-keygen -A
[xchroot /mnt] # xbps-install mkinitcpio mkinitcpio-encrypt mkinitcpio-lvm2
[xchroot /mnt] # xbps-install mkinitcpio-encryptssh
[xchroot /mnt] # xbps-alternatives -s mkinitcpio
Copy encryptssh to encryptssh2 hook and edit it to include LUKS header parameter to cryptsetup commands
[xchroot /mnt] # mkdir -p /etc/initcpio/{hooks,install}
[xchroot /mnt] # cp /usr/lib/initcpio/hooks/encryptssh /etc/initcpio/hooks/encryptssh2
[xchroot /mnt] # cp /usr/lib/initcpio/install/encryptssh /etc/initcpio/install/encryptssh2
[xchroot /mnt] # nvi /etc/initcpio/hooks/encryptssh2
diff --git a/encryptssh2 b/encryptssh2
index f15eb32..b4ad06f 100644
--- a/encryptssh2
+++ b/encryptssh2
@@ -54,6 +54,8 @@ run_hook ()
OLDIFS="${IFS}"
IFS=","
+ cryptheader="--header /boot/header.img"
+ cryptargs="${cryptargs} ${cryptheader}"
for cryptopt in ${cryptoptions}; do
case ${cryptopt} in
allow-discards)
@@ -74,7 +76,7 @@ run_hook ()
echo ${resolved} > /.cryptdev
- if /sbin/cryptsetup isLuks ${resolved} >/dev/null 2>&1; then
+ if /sbin/cryptsetup isLuks ${cryptheader} ${resolved} >/dev/null 2>&1; then
[ ${DEPRECATED_CRYPT} -eq 1 ] && warn_deprecated
dopassphrase=1
# If keyfile exists, try to use that
[xchroot /mnt] # nvi /etc/mkinitcpio.conf
diff --git a/mkinitcpio.conf b/mkinitcpio.conf
index 4a2ce87..143021d 100644
--- a/mkinitcpio.conf
+++ b/mkinitcpio.conf
@@ -4,7 +4,7 @@
# run. Advanced users may wish to specify all system modules
# in this array. For instance:
# MODULES=(usbhid xhci_hcd)
-MODULES=()
+MODULES=(loop)
# BINARIES
# This setting includes any additional binaries a given user may
@@ -16,7 +16,7 @@ BINARIES=()
# FILES
# This setting is similar to BINARIES above, however, files are added
# as-is and are not parsed in any way. This is useful for config files.
-FILES=()
+FILES=(/boot/header.img)
# HOOKS
# This is the most important setting in this file. The HOOKS control the
@@ -49,12 +49,12 @@ FILES=()
#
## NOTE: If you have /usr on a separate partition, you MUST include the
# usr and fsck hooks.
-HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block filesystems fsck)
+HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block netconf dropbear encryptssh2 lvm2 filesystems fsck)
# COMPRESSION
# Use this to compress the initramfs image. By default, gzip compression
# is used. Use 'cat' to create an uncompressed image.
-#COMPRESSION="zstd"
+COMPRESSION="zstd"
#COMPRESSION="gzip"
#COMPRESSION="bzip2"
#COMPRESSION="lzma"
[xchroot /mnt] # mkdir /root/.ssh
[xchroot /mnt] # chmod 700 /root/.ssh
[xchroot /mnt] # nvi /root/.ssh/authorized_keys
[xchroot /mnt] # chmod 600 /root/.ssh/authorized_keys
Without /etc/dropbear/root_key
file and proper public key in it you won't be able to unlock internal drive remotely.
[xchroot /mnt] # cp /root/.ssh/authorized_key /etc/dropbear/root_key
Ensure you have proper ip
parameters here - host ip address, subnet mask and gateway address.
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=4 cryptdevice=/dev/nvme0n1p1:cryptlvm root=/dev/lvgroup/root net.ifnames=0 ip=192.168.0.55::192.168.0.1:255.255.255.0::eth0:none"
[xchroot /mnt] # grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id="Void" --removable
This will generate initramfs and bootloader configuration (/boot/grub/grub.cfg
file).
[xchroot /mnt] # xbps-reconfigure -fa
Don't forget to remove installation media from the box.
[xchroot /mnt] # exit
# umount -R /mnt
# reboot
You have to do it from another computer.
$ ssh [email protected]
Don't forget to backup your /boot/header.img
file or full USB stick.