Installing Archlinux with full system and LVM encryption on LUKS
- Tutorial
In this post you will read a little about my strange research during forced sick leave. We will talk about several things at once that are not “best practice”, but also possible! So, there will be a tutorial on how to install Archlinux (my favorite distr) so that:
It is noteworthy that everything will be encrypted, except for the EFI system partition with a single grubx64.efi file - an EFI application for running grub.
If you are interested, welcome under the cat!
At first, I configured this all on my Lenovo X240 laptop, then I already used a virtual machine with OVMF in Proxmox to write the article.
Everything is created fairly standard. The image uses my favorite arch, which can always be downloaded from Yandex .
Then a few moments on virtualke in Proxmox regarding UEFI. To test the booth with UEFI (otherwise it will not be so interesting), you need to set OVMF instead of SeaBIOS in the properties of the virtual machine:
![](https://habrastorage.org/webt/ru/ge/fh/rugefhk4s2dhorfq7myeyu_yuam.png)
Next, add the UEFI disk, respectively, so that you
![](https://habrastorage.org/webt/hp/ht/6w/hpht6w6iadkra0ur4mon_iuvgeu.png)
can start something like this: In the console of the virtual machine, we immediately start the sshd service, set the root password and find out the dhcp-address of the virtual machine:
![](https://habrastorage.org/webt/zy/1y/et/zy1yetqzltmbhk9yb3mxirmfqby.png)
Next, we can continue working on ssh to make it more convenient.
So, having already connected via ssh, we first set the time so that later it would not turn out that file systems were created in the future:
We check that everything is correct:
Now we can proceed to the layout of the disk. At this stage, I have a disk / dev / vda, because Virtio controller and it's just an empty disk without a partition table:
We will break it into 2 partitions:
Use gdisk to create a gpt:
Next, create the first partition for EFI with type EF00 (EFI System Partition):
Now we create a partition for LUKS, where we will not even bother with the type and leave it as it is:
Let's write the changes and finish with partitioning:
With the first section (vda1) everything is quite simple. We just need to format it and for now it's all:
The second partition is the container that you first need to prepare. Format the partition using cryptsetup and set the passphrase:
*** I did not bother with the choice of ciphers, with a random mashing with uranium and other things, but simply created a default container.
Next, open the container by pointing to the same passphrase:
Now we have an open container accessible through device mapper:
Now we can continue with lvm (I will write in a quick way, since this is not a subject):
Next, create file systems on our lv:
Now all this can be mounted to install the base system. The installation point will be / mnt, where the root of our future system will begin:
*** I create / boot / efi so that / boot itself remains on / dev / mapper / rootvg-root, and the efi folder is already to mount / dev / vda1 (fat32 efi partition) into it:
Check current mount points (always useful):
As we see, everything is fair and now is the time to put the arch itself.
Install the base packages from the base and base-devel sets using the pacstrap package (they can put everything you want and besides this):
Everything is perfectly loaded, the basic system is ready. I, naturally, removed a conclusion. Now we can configure this very system to load and work.
From the basic things we will immediately generate fstab:
Next, we will make the arch-chroot in this new system:
*** The arch-chroot is a very useful utility, because it does everything by itself. Although you can always use the standard chroot, before doing this, follow the instructions for the gentoo-handbook wiki.gentoo.org/wiki/Handbook : AMD64 / Installation / Base section “Mounting the necessary
files systems ”. Set up the system time and hostname:
Set the root password:
Uncomment the necessary locales in /etc/locale.gen:
Generate them:
Immediately configure them for the system and the console:
Now we will configure the /etc/mkinitcpio.conf file, which is responsible for options, hooks, etc., when generating the initramfs:
The most important thing here is the hooks and their order:
*** resume hook for booting system after hibernation from swap. On virtualk it is not needed. I copied it from beech.
Now we can generate the initramfs:
Now that we have a system, we need to install the bootloader itself. I chose grub (2), because it is somehow more familiar and quite easy to load the kernel from an encrypted partition (well, or I didn’t particularly look for others).
Install the grub package:
Before generating the config, edit the default grub options:
here you need to uncomment one important line (without comment, of course):
and add (there is empty by default) in GRUB_CMDLINE_LINUX:
UUID I took from blkid:
We generate a config for grub:
Next, install grub itself on the disk:
*** you can add --recheck --debug, specify the architecture ... but ... because it works by itself)
Now let's edit / etc / crypttab so that the system itself knows that it is necessary to decrypt the LUKS partition when loading. Add a line:
Which means that you need to request a password (none) for the / dev / vda2 section and present it as container through device mapper.
Now we are ready to exit the chroot and reboot the system:
Now let's turn to the virtual machine console to see the result:
![](https://habrastorage.org/webt/zx/hd/sh/zxhdshkaqy4zc06h3_etdlrwfxu.png)
At this stage, we run the EFI application /boot/efi/EFI/arch/grubx64.efi with / dev / vda1, which asks us for a password in order to decrypt our container.
Further, after entering the password:
![](https://habrastorage.org/webt/g3/o1/px/g3o1px_jx-gved8okzl2ojt2m3y.png)
Here is the usual grub window with our boot options from /boot/grub/grub.cfg.
At this stage, grub decrypted our container and accessed this file itself (/boot/grub/grub.cfg), the kernel, and initramfs. After selecting the default option, the kernel will boot, initramfs:
![](https://habrastorage.org/webt/4o/lh/gg/4olhggvohhh5t5wvk8ta0wzeoek.png)
Active, the kernel and it came to the encrypt hook, which again asks us for the password to decrypt the container (in general, enter the password 2 times, but it may be that you are going to make 2 containers from excess paranoia boot and root :)
And further, after the system has been fully booted:
![](https://habrastorage.org/webt/sp/bz/dp/spbzdplbl60sycfknr2bjuc5wuk.png)
PS: to increase the level of schizophrenia, only a secure boot is missing in order to sign our grubx64.efi loader.
I just found the kernel and initramfs on / dev / vda1 to be uninteresting, since I did it 100 times. Other boot loaders such as SHIM, bootctl, etc. do not know how to do this (well, and I don’t know - tell in the comments)
- without a separate / boot (just to / root)
- / on lvm
- lvm inside luks-container
- with UEFI
- in the virtual machine.
with secure boot(“hard”, hardly possible in a virtual machine)
It is noteworthy that everything will be encrypted, except for the EFI system partition with a single grubx64.efi file - an EFI application for running grub.
If you are interested, welcome under the cat!
At first, I configured this all on my Lenovo X240 laptop, then I already used a virtual machine with OVMF in Proxmox to write the article.
Test bench setup:
Everything is created fairly standard. The image uses my favorite arch, which can always be downloaded from Yandex .
Then a few moments on virtualke in Proxmox regarding UEFI. To test the booth with UEFI (otherwise it will not be so interesting), you need to set OVMF instead of SeaBIOS in the properties of the virtual machine:
![](https://habrastorage.org/webt/ru/ge/fh/rugefhk4s2dhorfq7myeyu_yuam.png)
Next, add the UEFI disk, respectively, so that you
![](https://habrastorage.org/webt/hp/ht/6w/hpht6w6iadkra0ur4mon_iuvgeu.png)
can start something like this: In the console of the virtual machine, we immediately start the sshd service, set the root password and find out the dhcp-address of the virtual machine:
![](https://habrastorage.org/webt/zy/1y/et/zy1yetqzltmbhk9yb3mxirmfqby.png)
Next, we can continue working on ssh to make it more convenient.
Disk layout
So, having already connected via ssh, we first set the time so that later it would not turn out that file systems were created in the future:
timedatectl set-ntp true && timedatectl set-timezone Europe/Moscow
We check that everything is correct:
root@archiso ~ # timedatectl
Local time: Tue 2018-08-14 13:42:03 MSK
Universal time: Tue 2018-08-14 10:42:03 UTC
RTC time: Tue 2018-08-14 10:42:04
Time zone: Europe/Moscow (MSK, +0300)
System clock synchronized: yes
NTP service: active
RTC inlocal TZ: no
Now we can proceed to the layout of the disk. At this stage, I have a disk / dev / vda, because Virtio controller and it's just an empty disk without a partition table:
root@archiso ~ # fdisk -l /dev/vda
Disk /dev/vda: 15 GiB, 16106127360 bytes, 31457280 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
We will break it into 2 partitions:
- fat32 drive for UEFI applications (EFI_system_partition)
- LUKS container with everything else
Use gdisk to create a gpt:
root@archiso ~ # gdisk /dev/vda
GPT fdisk (gdisk) version 1.0.4
Command (? forhelp): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y
Next, create the first partition for EFI with type EF00 (EFI System Partition):
Command (? forhelp): n
Partition number (1-128, default 1):
First sector (34-31457246, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-31457246, default = 31457246) or {+-}size{KMGTP}: +512M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): <b>EF00</b>
Changed type of partition to 'EFI System'
Now we create a partition for LUKS, where we will not even bother with the type and leave it as it is:
Command (? forhelp): n
Partition number (2-128, default 2):
First sector (34-31457246, default = 1050624) or {+-}size{KMGTP}:
Last sector (1050624-31457246, default = 31457246) or {+-}size{KMGTP}:
<b>Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'</b>
Let's write the changes and finish with partitioning:
Command (? forhelp): 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/vda.
The operation has completed successfully.
Creating a LUKS container and file systems
With the first section (vda1) everything is quite simple. We just need to format it and for now it's all:
root@archiso ~ # mkfs.vfat /dev/vda1
mkfs.fat 4.1 (2017-01-24)
The second partition is the container that you first need to prepare. Format the partition using cryptsetup and set the passphrase:
root@archiso ~ # cryptsetup -v luksFormat /dev/vda2
WARNING!
========
This will overwrite data on /dev/vda2 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/vda2:
Verify passphrase:
Command successful.
*** I did not bother with the choice of ciphers, with a random mashing with uranium and other things, but simply created a default container.
Next, open the container by pointing to the same passphrase:
root@archiso ~ # cryptsetup luksOpen /dev/vda2 container
Enter passphrase for /dev/vda2:
Now we have an open container accessible through device mapper:
root@archiso ~ # ls -l /dev/mapper | grep container
lrwxrwxrwx 1 root root 7 Aug 14 14:01 container -> ../dm-0
Now we can continue with lvm (I will write in a quick way, since this is not a subject):
root@archiso ~ # pvcreate /dev/mapper/container
Physical volume "/dev/mapper/container" successfully created.
root@archiso ~ # vgcreate rootvg /dev/mapper/container
Volume group "rootvg" successfully created
root@archiso ~ # lvcreate -L1G -n swap rootvg
Logical volume "swap" created.
root@archiso ~ # lvcreate -L5G -n root rootvg
Logical volume "root" created.
root@archiso ~ # lvcreate -L2G -n home rootvg
Logical volume "home" created.
root@archiso ~ # lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
home rootvg -wi-a----- 2.00g
root rootvg -wi-a----- 5.00g
swap rootvg -wi-a----- 1.00g
Next, create file systems on our lv:
root@archiso ~ # mkfs.ext4 -L root /dev/mapper/rootvg-root
mke2fs 1.44.3 (10-July-2018)
...
Writing superblocks and filesystem accounting information: done
[root@archiso ~]# mkfs.ext4 -L home /dev/mapper/rootvg-home
mke2fs 1.44.3 (10-July-2018)
Creating filesystem with 524288 4k blocks and 131072 inodes
...
Writing superblocks and filesystem accounting information: done
[root@archiso ~]# mkswap -L swap /dev/mapper/rootvg-swap
...
LABEL=swap, UUID=98b0bc31-1c62-4fec-bb97-e1913d1e8cb4
Now all this can be mounted to install the base system. The installation point will be / mnt, where the root of our future system will begin:
[root@archiso ~]# mount /dev/mapper/rootvg-root /mnt/
[root@archiso ~]# mkdir -p /mnt/{home,boot/efi}
*** I create / boot / efi so that / boot itself remains on / dev / mapper / rootvg-root, and the efi folder is already to mount / dev / vda1 (fat32 efi partition) into it:
[root@archiso ~]# mount /dev/vda1 /mnt/boot/efi/
[root@archiso ~]# mount /dev/mapper/rootvg-home /mnt/home/
[root@archiso ~]# swapon /dev/mapper/rootvg-swap
Check current mount points (always useful):
[root@archiso ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 462.5M 1 loop /run/archiso/sfs/airootfs
sr0 11:0 1 573M 0 rom /run/archiso/bootmnt
vda 254:0 0 15G 0 disk
├─vda1 254:1 0 512M 0 part /mnt/boot/efi
└─vda2 254:2 0 14.5G 0 part
└─container 253:0 0 14.5G 0 crypt
├─rootvg-swap 253:1 0 1G 0 lvm [SWAP]
├─rootvg-root 253:2 0 5G 0 lvm /mnt
└─rootvg-home 253:3 0 2G 0 lvm /mnt/home
As we see, everything is fair and now is the time to put the arch itself.
Base system installation
Install the base packages from the base and base-devel sets using the pacstrap package (they can put everything you want and besides this):
pacstrap /mnt base base-devel
Everything is perfectly loaded, the basic system is ready. I, naturally, removed a conclusion. Now we can configure this very system to load and work.
From the basic things we will immediately generate fstab:
genfstab -pU /mnt >> /mnt/etc/fstab
Next, we will make the arch-chroot in this new system:
[root@archiso ~]# arch-chroot /mnt
*** The arch-chroot is a very useful utility, because it does everything by itself. Although you can always use the standard chroot, before doing this, follow the instructions for the gentoo-handbook wiki.gentoo.org/wiki/Handbook : AMD64 / Installation / Base section “Mounting the necessary
files systems ”. Set up the system time and hostname:
ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtime && \
hwclock --systohc && \
echo luks-test > /etc/hostname
Set the root password:
[root@archiso /]# passwd root
New password:
Retype new password:
passwd: password updated successfully
Uncomment the necessary locales in /etc/locale.gen:
[root@archiso /]# vi /etc/locale.gen
[root@archiso /]# grep -v '^#' /etc/locale.gen
en_US ISO-8859-1
en_US.UTF-8 UTF-8
ru_RU.UTF-8 UTF-8
ru_RU ISO-8859-5
Generate them:
[root@archiso /]# locale-gen
Generating locales...
en_US.ISO-8859-1... done
en_US.UTF-8... done
ru_RU.UTF-8... done
ru_RU.ISO-8859-5... done
Generation complete
Immediately configure them for the system and the console:
[root@archiso /]# echo LANG=en_US.UTF-8 > /etc/locale.conf
[root@archiso /]# echo KEYMAP=ru > /etc/vconsole.conf
[root@archiso /]# echo FOND=cyr-sun16 >> /etc/vconsole.conf
Now we will configure the /etc/mkinitcpio.conf file, which is responsible for options, hooks, etc., when generating the initramfs:
vi /etc/mkinitcpio.conf
The most important thing here is the hooks and their order:
HOOKS=(base udev autodetect modconf block keymap encrypt lvm2 resume filesystems keyboard fsck)
*** resume hook for booting system after hibernation from swap. On virtualk it is not needed. I copied it from beech.
Now we can generate the initramfs:
[root@archiso /]# mkinitcpio -p linux
==> Building image from preset: /etc/mkinitcpio.d/linux.preset: 'default'
-> -k /boot/vmlinuz-linux -c /etc/mkinitcpio.conf -g /boot/initramfs-linux.img
==> Starting build: 4.17.14-arch1-1-ARCH
-> Running build hook: [base]
-> Running build hook: [udev]
-> Running build hook: [autodetect]
-> Running build hook: [modconf]
-> Running build hook: [block]
-> Running build hook: [keymap]
-> Running build hook: [encrypt]
-> Running build hook: [lvm2]
-> Running build hook: [resume]
-> Running build hook: [filesystems]
-> Running build hook: [keyboard]
-> Running build hook: [fsck]
==> Generating module dependencies
==> Creating gzip-compressed initcpio image: /boot/initramfs-linux.img
==> Image generation successful
Now that we have a system, we need to install the bootloader itself. I chose grub (2), because it is somehow more familiar and quite easy to load the kernel from an encrypted partition (well, or I didn’t particularly look for others).
Install the grub package:
[root@archiso /]# pacman -S grub dosfstools efibootmgr mtools
Before generating the config, edit the default grub options:
vim /etc/default/grub
here you need to uncomment one important line (without comment, of course):
# Uncomment to enable booting from LUKS encrypted devices
GRUB_ENABLE_CRYPTODISK=y
and add (there is empty by default) in GRUB_CMDLINE_LINUX:
GRUB_CMDLINE_LINUX="cryptdevice=UUID=5ad7c9ad-fb17-4839-925e-479432516c07:container"
UUID I took from blkid:
[root@archiso /]# blkid | grep vda2
/dev/vda2: UUID="5ad7c9ad-fb17-4839-925e-479432516c07" TYPE="crypto_LUKS" PARTLABEL="Linux filesystem" PARTUUID="667a1243-17ff-4f03-952c-5afd5e3415cc"
We generate a config for grub:
[root@archiso /]# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
WARNING: Failed to connect to lvmetad. Falling back to device scanning.
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/initramfs-linux.img
Found fallback initrd image(s) in /boot: initramfs-linux-fallback.img
WARNING: Failed to connect to lvmetad. Falling back to device scanning.
done
Next, install grub itself on the disk:
[root@archiso /]# grub-install /dev/vda
Installing for x86_64-efi platform.
...
Installation finished. No error reported.
*** you can add --recheck --debug, specify the architecture ... but ... because it works by itself)
Now let's edit / etc / crypttab so that the system itself knows that it is necessary to decrypt the LUKS partition when loading. Add a line:
echo"container /dev/vda2 none" >> /etc/crypttab
Which means that you need to request a password (none) for the / dev / vda2 section and present it as container through device mapper.
Now we are ready to exit the chroot and reboot the system:
[root@archiso /]# exitexit
[root@archiso ~]# reboot
Welcome back!
Now let's turn to the virtual machine console to see the result:
![](https://habrastorage.org/webt/zx/hd/sh/zxhdshkaqy4zc06h3_etdlrwfxu.png)
At this stage, we run the EFI application /boot/efi/EFI/arch/grubx64.efi with / dev / vda1, which asks us for a password in order to decrypt our container.
Further, after entering the password:
![](https://habrastorage.org/webt/g3/o1/px/g3o1px_jx-gved8okzl2ojt2m3y.png)
Here is the usual grub window with our boot options from /boot/grub/grub.cfg.
At this stage, grub decrypted our container and accessed this file itself (/boot/grub/grub.cfg), the kernel, and initramfs. After selecting the default option, the kernel will boot, initramfs:
![](https://habrastorage.org/webt/4o/lh/gg/4olhggvohhh5t5wvk8ta0wzeoek.png)
Active, the kernel and it came to the encrypt hook, which again asks us for the password to decrypt the container (in general, enter the password 2 times, but it may be that you are going to make 2 containers from excess paranoia boot and root :)
And further, after the system has been fully booted:
![](https://habrastorage.org/webt/sp/bz/dp/spbzdplbl60sycfknr2bjuc5wuk.png)
PS: to increase the level of schizophrenia, only a secure boot is missing in order to sign our grubx64.efi loader.
I just found the kernel and initramfs on / dev / vda1 to be uninteresting, since I did it 100 times. Other boot loaders such as SHIM, bootctl, etc. do not know how to do this (well, and I don’t know - tell in the comments)
Useful materials on the topic and materials used
Only registered users can participate in the survey. Sign in , please.