install arch linux with an encrypted boot partition.

bootstrap_arch_linux.sh
#! /bin/bash
set -eu

################################################################################
# prompt for info.
################################################################################

lsblk
echo "which device? (e.g., sda, sdb, sdc, etc.)"
read DEVICE
echo "use device $DEVICE? (y/N)"
read REPLY
if [[ ! $REPLY =~ ^([Yy]$|[Yy]es) ]]; then
  echo "stopping script..."
  exit 1
fi


################################################################################
# connect to internet (usually automatic for wired connections).
################################################################################

# for a wireless connections
wifi-menu -o $(iw dev | sed -n "s/^\s*Interface \(.*\)$/\1/p")

# for non-broadcasting wireless networks, wifi-menu will fail. manually define
# the netork via netctl. see examples available in /etc/netcl. once definined
# network <my_network> is in /etc/netctl, run: 
# 
#   netctl start <my_network>
#
# to automatically connect from now on, also run: 
#
#   netctl enable <my_network>
#   systemctl enable netctl@<my_network>.service


################################################################################
# detect devices and configure storage options.
################################################################################

# create partition table
parted -s /dev/${DEVICE} mklabel msdos
parted -s /dev/${DEVICE} mkpart primary 2048s 100%

# create encrypted logical volumes
cryptsetup luksFormat /dev/${DEVICE}1
cryptsetup luksOpen /dev/${DEVICE}1 lvm
pvcreate /dev/mapper/lvm
vgcreate vg /dev/mapper/lvm
lvcreate -L 4G vg -n swap
lvcreate -L 20G vg -n root
lvcreate -l +100%FREE vg -n home

# configure swap and filesystems
mkswap -L swap /dev/mapper/vg-swap
mkfs.ext4 /dev/mapper/vg-root
mkfs.ext4 /dev/mapper/vg-home


################################################################################
# mount logical volumes and bootstrap base and base-devel packages. 
################################################################################

# mount logical volumes
mount /dev/mapper/vg-root /mnt
mkdir /mnt/home
mount /dev/mapper/vg-home /mnt/home

# bootstrap
pacstrap -i /mnt base base-devel

# generate filesystem table
genfstab -U /mnt >> /mnt/etc/fstab

# chroot
arch-chroot /mnt /bin/bash

# run content in arch_chroot_script.sh within the chroot

################################################################################
# return from chroot, clean up, and reboot. 
################################################################################

umount -R /mnt

# remove the live image when rebooting
reboot
#! /bin/bash set -eu ################################################################################ # prompt for info. ################################################################################ lsblk echo "which device? (e.g., sda, sdb, sdc, etc.)" read DEVICE echo "use device $DEVICE? (y/N)" read REPLY if [[ ! $REPLY =~ ^([Yy]$|[Yy]es) ]]; then echo "stopping script..." exit 1 fi ################################################################################ # connect to internet (usually automatic for wired connections). ################################################################################ # for a wireless connections wifi-menu -o $(iw dev | sed -n "s/^\s*Interface \(.*\)$/\1/p") # for non-broadcasting wireless networks, wifi-menu will fail. manually define # the netork via netctl. see examples available in /etc/netcl. once definined # network is in /etc/netctl, run: # # netctl start # # to automatically connect from now on, also run: # # netctl enable # systemctl enable netctl@.service ################################################################################ # detect devices and configure storage options. ################################################################################ # create partition table parted -s /dev/${DEVICE} mklabel msdos parted -s /dev/${DEVICE} mkpart primary 2048s 100% # create encrypted logical volumes cryptsetup luksFormat /dev/${DEVICE}1 cryptsetup luksOpen /dev/${DEVICE}1 lvm pvcreate /dev/mapper/lvm vgcreate vg /dev/mapper/lvm lvcreate -L 4G vg -n swap lvcreate -L 20G vg -n root lvcreate -l +100%FREE vg -n home # configure swap and filesystems mkswap -L swap /dev/mapper/vg-swap mkfs.ext4 /dev/mapper/vg-root mkfs.ext4 /dev/mapper/vg-home ################################################################################ # mount logical volumes and bootstrap base and base-devel packages. ################################################################################ # mount logical volumes mount /dev/mapper/vg-root /mnt mkdir /mnt/home mount /dev/mapper/vg-home /mnt/home # bootstrap pacstrap -i /mnt base base-devel # generate filesystem table genfstab -U /mnt >> /mnt/etc/fstab # chroot arch-chroot /mnt /bin/bash # run content in arch_chroot_script.sh within the chroot ################################################################################ # return from chroot, clean up, and reboot. ################################################################################ umount -R /mnt # remove the live image when rebooting reboot
arch_chroot_script.sh
#! /bin/bash
set -eu

################################################################################
# prompt for info.
################################################################################

lsblk
echo "which device? (e.g., sda, sdb, sdc, etc.)"
read DEVICE
echo "use device $DEVICE? (y/N)"
read REPLY
if [[ ! $REPLY =~ ^([Yy]$|[Yy]es) ]]; then
  echo "stopping script..."
  exit 1
fi


################################################################################
# configure base system.
################################################################################

# set locale to en_US.UTF-8
sed -i 's/#LANG=en_US.UTF-8/LANG=en_US.UTF-8/g' /etc/locale.gen
locale-gen 
echo LANG=en_US.UTF-8 > /etc/locale.conf

# set time
tzselect
ln -s /usr/share/zoneinfo/Zone/SubZone /etc/localtime
hwclock --systohc --utc

# set hostname and append hostname to /etc/hosts
HOSTNAME=hostname
echo "$HOSTNAME" > /etc/hostname
sed -i "s/localhost$/localhost\t$HOSTNAME/g" /etc/hosts 

# install wireless tools
pacman -S iw wpa_supplicant dialog


################################################################################
# add encrypt and lvm2 modules to /etc/mkinitcpio.conf.
################################################################################

OLD_HOOKS="base udev autodetect modconf block filesystems keyboard fsck"
NEW_HOOKS="base udev autodetect modconf block encrypt lvm2 filesystems keyboard fsck"
sed -i "s/$OLD_HOOKS/$NEW_HOOKS/g" /etc/mkinitcpio.conf

# rebuild initial ramdisk with new modules
mkinitcpio -p linux


################################################################################
# install grub (assuing bios/mbr) and add encryption support.
################################################################################

pacman -S grub os-prober
grub-install --recheck /dev/${DEVICE}

FOR_SSD="cryptdevice=/dev/${DEVICE}1:lvm:allow-discards"
LVM_ROOT="root=/dev/mapper/vg-root"
GRUB_CMDLINE_LINUX="GRUB_CMDLINE_LINUX=\"$FOR_SSD $LVM_ROOT\""
GRUB_ENABLE_CRYPTODISK="GRUB_ENABLE_CRYPTODISK=y"

sed -i "s/GRUB_CMDLINE_LINUX=/$GRUB_CMDLINE_LINUX/g" grub
echo "$GRUB_ENABLE_CRYPTODISK" >> /etc/default/grub

grub-mkconfig -o /boot/grub/grub.cfg


################################################################################
# set root password and exit
################################################################################

passwd # set root password

# (optional) run make_luks_key.sh here

exit
#! /bin/bash set -eu ################################################################################ # prompt for info. ################################################################################ lsblk echo "which device? (e.g., sda, sdb, sdc, etc.)" read DEVICE echo "use device $DEVICE? (y/N)" read REPLY if [[ ! $REPLY =~ ^([Yy]$|[Yy]es) ]]; then echo "stopping script..." exit 1 fi ################################################################################ # configure base system. ################################################################################ # set locale to en_US.UTF-8 sed -i 's/#LANG=en_US.UTF-8/LANG=en_US.UTF-8/g' /etc/locale.gen locale-gen echo LANG=en_US.UTF-8 > /etc/locale.conf # set time tzselect ln -s /usr/share/zoneinfo/Zone/SubZone /etc/localtime hwclock --systohc --utc # set hostname and append hostname to /etc/hosts HOSTNAME=hostname echo "$HOSTNAME" > /etc/hostname sed -i "s/localhost$/localhost\t$HOSTNAME/g" /etc/hosts # install wireless tools pacman -S iw wpa_supplicant dialog ################################################################################ # add encrypt and lvm2 modules to /etc/mkinitcpio.conf. ################################################################################ OLD_HOOKS="base udev autodetect modconf block filesystems keyboard fsck" NEW_HOOKS="base udev autodetect modconf block encrypt lvm2 filesystems keyboard fsck" sed -i "s/$OLD_HOOKS/$NEW_HOOKS/g" /etc/mkinitcpio.conf # rebuild initial ramdisk with new modules mkinitcpio -p linux ################################################################################ # install grub (assuing bios/mbr) and add encryption support. ################################################################################ pacman -S grub os-prober grub-install --recheck /dev/${DEVICE} FOR_SSD="cryptdevice=/dev/${DEVICE}1:lvm:allow-discards" LVM_ROOT="root=/dev/mapper/vg-root" GRUB_CMDLINE_LINUX="GRUB_CMDLINE_LINUX=\"$FOR_SSD $LVM_ROOT\"" GRUB_ENABLE_CRYPTODISK="GRUB_ENABLE_CRYPTODISK=y" sed -i "s/GRUB_CMDLINE_LINUX=/$GRUB_CMDLINE_LINUX/g" grub echo "$GRUB_ENABLE_CRYPTODISK" >> /etc/default/grub grub-mkconfig -o /boot/grub/grub.cfg ################################################################################ # set root password and exit ################################################################################ passwd # set root password # (optional) run make_luks_key.sh here exit
make_luks_key.sh
#! /bin/bash
set -eu

################################################################################
# prompt for info.
################################################################################

lsblk
echo "which device? (e.g., sda, sdb, sdc, etc.)"
read DEVICE
echo "use device $DEVICE? (y/N)"
read REPLY
if [[ ! $REPLY =~ ^([Yy]$|[Yy]es) ]]; then
  echo "stopping script..."
  exit 1
fi


################################################################################
# (optional) create a binary luks key to store in the initial ramdisk. 
################################################################################

# generate keyfile and prevent non-root from reading it. 
dd bs=512 count=4 if=/dev/urandom of=/etc/crypto_keyfile.bin
chmod 400 /etc/crypto_keyfile.bin
cryptsetup luksAddKey /dev/${DEVICE}1 /etc/crypto_keyfile.bin

# add key to /etc/mkinitcpio.conf
sed -i "s/FILES=\".*\"/FILES=\"\/etc\/crypto_keyfile.bin\"/g" /etc/mkinitcpio.conf

# rebuild the kernel
mkinitcpio -p linux

# add key to grub config file
CRYPTO_KEY="cryptkey=rootfs:/etc/crypto_keyfile.bin"
CUR_GRUB_CMDLINE_LINUX=$(grep "^GRUB_CMDLINE_LINUX=" /etc/default/grub)
NEW_GRUB_CMDLINE_LINUX=$(echo $CUR_GRUB_CMDLINE_LINUX | cut -d \" -f2)
NEW_GRUB_CMDLINE_LINUX="GRUB_CMDLINE_LINUX=$NEW_GRUB_CMDLINE_LINUX $CRYPTO_KEY"
sed -i "s/$CUR_GRUB_CMDLINE_LINUX/$NEW_GRUB_CMDLINE_LINUX/g" /etc/default/grub
#! /bin/bash set -eu ################################################################################ # prompt for info. ################################################################################ lsblk echo "which device? (e.g., sda, sdb, sdc, etc.)" read DEVICE echo "use device $DEVICE? (y/N)" read REPLY if [[ ! $REPLY =~ ^([Yy]$|[Yy]es) ]]; then echo "stopping script..." exit 1 fi ################################################################################ # (optional) create a binary luks key to store in the initial ramdisk. ################################################################################ # generate keyfile and prevent non-root from reading it. dd bs=512 count=4 if=/dev/urandom of=/etc/crypto_keyfile.bin chmod 400 /etc/crypto_keyfile.bin cryptsetup luksAddKey /dev/${DEVICE}1 /etc/crypto_keyfile.bin # add key to /etc/mkinitcpio.conf sed -i "s/FILES=\".*\"/FILES=\"\/etc\/crypto_keyfile.bin\"/g" /etc/mkinitcpio.conf # rebuild the kernel mkinitcpio -p linux # add key to grub config file CRYPTO_KEY="cryptkey=rootfs:/etc/crypto_keyfile.bin" CUR_GRUB_CMDLINE_LINUX=$(grep "^GRUB_CMDLINE_LINUX=" /etc/default/grub) NEW_GRUB_CMDLINE_LINUX=$(echo $CUR_GRUB_CMDLINE_LINUX | cut -d \" -f2) NEW_GRUB_CMDLINE_LINUX="GRUB_CMDLINE_LINUX=$NEW_GRUB_CMDLINE_LINUX $CRYPTO_KEY" sed -i "s/$CUR_GRUB_CMDLINE_LINUX/$NEW_GRUB_CMDLINE_LINUX/g" /etc/default/grub

The Arch Wiki will tell you how to install Arch with a separate, unencrypted boot partition, but it won’t help if you want to encrypt your boot partition and mount it along with your other ones. The following is an explanation of how to create them using GRUB modules, LVM, and LUKS.

1. Boot your Arch installation image.

Download the latest image here and be sure to verify the image after it is downloaded. After all, encryption is pointless if the installation image itself is compromised.

Burn the image to disk or copy it to a USB. Then, boot from it.

2. Create your partitions.

You’ll first need to do the steps already outlined on the Arch Wiki installation guide up to partition creation. Basically, set up your network interface an identify the devices within the filesystem.

The following will create three partitions for swap, home. and root. Replace the X of /dev/sdX with the letter corresponding to the hard drive you are installing on. Modify the code as suits your needs.

parted -s /dev/sdX mklabel msdos
parted -s /dev/sdX mkpart primary 2048s 100%
cryptsetup luksFormat /dev/sdX1
cryptsetup luksOpen /dev/sdX1 lvm
pvcreate /dev/mapper/lvm
vgcreate vg /dev/mapper/lvm
lvcreate -L 4G vg -n swap
lvcreate -L 20G vg -n root
lvcreate -l +100%FREE vg -n home
mkswap -L swap /dev/mapper/vg-swap
mkfs.ext4 /dev/mapper/vg-root
mkfs.ext4 /dev/mapper/vg-home
mount /dev/mapper/vg-root /mnt
mkdir /mnt/home
mount /dev/mapper/vg-home /mnt/home

These instructions are copied basically verbatim from the blog mentioned at the beginning.

3. Install Arch Linux.

Now, follow the generic install instructions. Don’t forget to generate the fstab.

When you install the kernel, you’ll need to add some modules to the initramfs image. Open /etc/mkinitcpio.conf and encrypt and lvm2 to the kernel build hooks. The order shouldn’t matter, but just in case, edit the line so that it reads as follows:

HOOKS="base udev autodetect modconf block encrypt lvm2 filesystems keyboard fsck"

NOTE: If there are other modules not shown in the above example, leave them alone.

The modules added to the build hooks are necessary for the initramfs to be able to decrypt partitions and mount the filesystem they live on. Save your changes to mkinitcpio.conf and rebuild the kernel image. Run:

mkinitcpio -p linux

4. Install GRUB.

Continue with the install instructions until you set to the part that tells you how to install a bootloader. Install GRUB as you normally would. Then, open /etc/default/grub and add the line:

GRUB_ENABLE_CRYPTODISK=y

Then, also in /etc/default/grub, edit GRUB_CMDLINE_LINUX to pass extra boot parameters to the kernel:

GRUB_CMDLINE_LINUX="cryptdevice=/dev/sdX1:lvm root=/dev/mapper/vg-root"

Note that if you have an SSD and don’t mind the security implications of allowing discards, do this instead:

GRUB_CMDLINE_LINUX="cryptdevice=/dev/sdX1:lvm:allow-discards root=/dev/mapper/vg-root"

Then, regenerate the GRUB config file:

grub-mkconfig -o /boot/grub.cfg

5. (Optional) Create LUKS key.

If you booted your system already, you’ll notice that you have to enter your LUKS password each time you try to decrypt a block device. It gets annoying, but you can get around it by supplying a keyfile to the kernel that’ll boot the decrypt partitions after you decrypt the bootloader. This doesn’t carry security implications because until you enter the password in GRUB, the keyfile is encrypted on the hard drive.

The only security hazards the key poses is when the system is booted and the key resides in the ramfs, unencrypted. At this point, so does the LUKS master key, so if attackers can get hold of your keyfile in this state, they might as well get your master key. If an attacker is that determined and pernicious, you’ll need to do a lot more to secure your system, something well beyond the scope of this post.

Generate the keyfile by doing the following:

1. Fill a file with random bits.

dd bs=512 count=4 if=/dev/urandom of=/crypto_keyfile.bin
cryptsetup luksAddkey /dev/sdX1 /crypto_keyfile.bin

You can stick crypto_keyfile.bin anywhere in the root partition if you’d like. Also, adding the key will prompt you for a password. Enter any existing LUKS password.

2. Build the key into the initramfs.

Add the key to the FILES parameter in /etc/mkinitcpio.conf. Then regenerate the initramfs image by:

mkinitcpio -p linux

3. Add the key to GRUB.

Open /etc/default/grub and append GRUB_CMDLINE_LINUX with cryptkey=rootfs:/crypto_keyfile.bin. Do not delete the cryptdevice parts added earlier!!!

Then, regenerate the grub.cfg file with grub-mkconfig.

Now, the key will be loaded into the boot image and decrypt your partitions once you select a kernel from the GRUB boot menu.