Category Archives: Security

Full Disk Encryption on Arch Linux: NVMe, GRUB2, LVM and LUKS

Last week I had to install my new work computer. Although I am a Debian guy, I thought I should give a chance to Arch Linux as well.
In theory full disk encryption and Linux is not a big deal (there's a lot of documentation out there) and it should be pretty straight forward. In practice, probably because it was the first time doing it on Arch, it took me some time to figure it out how to do it right.

My biggest problem was that the current version of grub shipped with Arch doesn't include support the following combination: NVMe, LVM, LUKS. Apparently the git version has the fix for that issue.

So here is what I did (This post comes without warranty of any kind! I do not issue any guarantee that this will work for you!)

  • Partition the disk - no Windows, no UEFI needed, my disk is only 256G and I will need only one primary partition so... there is no reason to use GPT.

[codesyntax lang="bash"]

parted -a optimal -s /dev/nvme0n1 mklabel msdos
parted -s /dev/nvme0n1 mkpart primary 2048s 100%

[/codesyntax]

  • Encrypt the newly created partition

[codesyntax lang="bash"]

cryptsetup luksFormat /dev/nvme0n1p1
cryptsetup luksOpen /dev/nvme0n1p1 disk

[/codesyntax]

  • Setup logical volumes

[codesyntax lang="bash"]

pvcreate /dev/mapper/disk
vgcreate vg0 /dev/mapper/disk
lvcreate -L 32G vg0 -n swap
lvcreate -L 15G vg0 -n root
lvcreate -l +100%FREE vg0 -n home

[/codesyntax]

  • Create filesystem

[codesyntax lang="bash"]

mkswap -L swap /dev/vg0/swap
mkfs.ext4 /dev/vg0/root
mkfs.ext4 /dev/vg0/home

[/codesyntax]

  • Mount the partitions

[codesyntax lang="bash"]

mount /dev/vg0/root /mnt
mkdir -vp /mnt/home
mount /dev/vg0/home /mnt/home

[/codesyntax]

  • Set mirror list

[codesyntax lang="bash"]

pacman -Sy
pacman -S pacman-contrib
cd /etc/pacman.d/
wget "archlinux.org/mirrorlist/?country=SE" -O mirrorlist.b
sed -i 's/^#//' mirrorlist.b
rankmirrors -n 3 mirrorlist.b > mirrorlist

[/codesyntax]

  • Install base system

[codesyntax lang="bash"]

pacstrap /mnt base base-devel vim less dhclient
genfstab -p -U /mnt > /mnt/etc/fstab

[/codesyntax]

  • Chroot time!

[codesyntax lang="bash"]

arch-chroot /mnt /bin/bash

[/codesyntax]

  • Localization

[codesyntax lang="bash"]

echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
export LANG=en_US.UTF-8
echo LANG=en_US.UTF-8 > /etc/locale.conf
rm -f /etc/localtime
ln -s /usr/share/zoneinfo/Europe/Stockholm /etc/localtime
hwclock --systohc --utc

[/codesyntax]

  • Set the hostname

[codesyntax lang="bash"]

echo jonas > /etc/hostname
vim /etc/hosts

[/codesyntax]

...
127.0.0.1	localhost.localdomain	localhost jonas
::1		localhost.localdomain	localhost jonas
...
  • Install various packages

[codesyntax lang="bash"]

pacman -S wget

[/codesyntax]

  • Identify the network card and enable dhcp client

[codesyntax lang="bash"]

ip link
systemctl enable dhcpcd@<interface>.service
systemctl enable dhcpcd.service

[/codesyntax]

  • Add a new user

[codesyntax lang="bash"]

useradd -m -g users -s /bin/bash jonas
passwd jonas
visudo

[/codesyntax]

...
 ##
 ## User privilege specification
 ##
 root ALL=(ALL) ALL
 jonas ALL=(ALL) ALL
 ...
  • Set the root password

[codesyntax lang="bash"]

passwd

[/codesyntax]

  • Create a key so I won't enter the LUKS passphrase twice

[codesyntax lang="bash"]

dd if=/dev/urandom of=/crypto_keyfile.bin bs=512 count=4
cryptsetup luksAddKey /dev/nvme0n1p1 /crypto_keyfile.bin

[/codesyntax]

  • Create the initial ramdisk environment

[codesyntax lang="bash"]

vim /etc/mkinitcpio.conf

[/codesyntax]

MODULES="ext4"
HOOKS="base udev autodetect modconf block encrypt lvm2 resume filesystems keyboard fsck"
FILES=/crypto_keyfile.bin

[codesyntax lang="bash"]

mkinitcpio -p linux

[/codesyntax]

  • The current version of grub shipped with Arch doesn't include support for NVMe, but grub-git it seems it does

[codesyntax lang="bash"]

vim /etc/pacman.conf

[/codesyntax]

[archlinuxfr]
SigLevel = Optional TrustAll
Server = http://repo.archlinux.fr/$arch

[codesyntax lang="bash"]

pacman -Syu
pacman -S yaourt

# required packages to build grub-git
pacman -S git rsync freetype2 ttf-dejavu python autogen help2man fuse

su -l jonas

# add unifont gpg key (more details here[1])
export KEY="1A09227B1F435A33"
gpg --recv-keys $KEY
gpg --edit-key $KEY

# install grub-git (please note that you will need at least 2G available on your /tmp)
yaourt -S grub-git

[/codesyntax]

  • We don't need to be "jonas" anymore

[codesyntax lang="bash"]

exit

[/codesyntax]

  • Now that we have grub installed, let's configure and install it

[codesyntax lang="bash"]

vim /etc/default/grub

[/codesyntax]

GRUB_CMDLINE_LINUX="cryptdevice=/dev/nvme0n1p1:disk"
GRUB_ENABLE_CRYPTODISK=y

[codesyntax lang="bash"]

grub-mkconfig -o /boot/grub/grub.cfg
grub-install /dev/nvme0n1

[/codesyntax]

  • Security considerations

[codesyntax lang="bash"]

chmod 000 /crypto_keyfile.bin
chmod -R g-rwx,o-rwx /boot

[/codesyntax]

  • Done!

[codesyntax lang="bash"]

exit
reboot

[/codesyntax]

[1]: https://bbs.archlinux.org/viewtopic.php?pid=1488734#p1488734