Join the discussion on >>/sec/3

How to create a hardened Arch Linux Install

last updated: 04/02/2021

Author: 6e336d

Status: Complete


This short guide will show you how to create a hardened arch linux install with multiple layers of security.


Why Arch?
Arch is highly modular and makes achieving this very easy compared to other distros

Why GRUB instead of alternatives like syslinux?
GRUB is a huge project. The more popular the code is, the less likely that it has major security problems because it has been reviewed by the community, it also has encrypted /boot support.

Why AppArmor?
Because it's simple, easy to use and has been around for a long time. And because firejail(sandbox app) supports it. It's something that you can actually learn and create profiles yourself. It's also avaliable in the official Arch repositories so you won't have to compile it yourself or get it from the AUR

Why linux-hardened?
It has AppArmor support, contains some security and grsecurity patches and a security-focused compile-time configuration.

Why do you focus on UEFI?
At some point, a non-encrypted binary needs to be loaded in order to decrypt the rest, you can't just have a mass block of encrypted data without a way to decrypt them. That's where the EFI executable comes into play, I tried to reduce the risk by putting the executable on a USB drive so it can be with you all the time and it can be easy to destroy if a theif steals your laptop.

Can you explain the boot process?
Sure! You insert the USB drive in your computer, a GRUB EFI executable on a FAT 32 partition gets loaded, asks you for password once(won't repeat if you insert it wrong, you will need to reboot instead), after you insert the password for the boot partition it will load the complete GRUB bootloader containing the kernel, initramfs and other things. When the kernel gets loaded, it will load a custom initcpio hook which will do the following:

1 - check for the presence of the USB drive(it tries to identify it by its ID(stored in: /dev/disk/by-id)

2 - Attempt to decrypt the boot partition(I know that the boot partition has been decrypted by the EFI executable, but you will need to do that again, sorry).

3 - After the boot partition gets decrypted, it will get mounted in /mnt.

4 - After that it will obtain the necessary header file from the encrypted boot partition to decrypt an LVM partition which contains the root and swap partition, you will enter the password.

5 - after it gets decrypted, it will unmount the boot partition from /mnt so the system can mount it in /boot using the data given from /etc/fstab.

You will have to enter 3 passwords during the boot process, 2 for /boot and 1 for the LVM partitions

Why seperate header?
I used a seperate header for the LVM partition so that a thief won't detect the presence of encrypted data so they won't even know about it.

Why LVM on LUKS?
Reduces the suspicion of the presence of encrypted partitions and requires you to enter one password for root and swap instead of two.

Did you create this?
No, I just read a lot of articles and manuals to give you a starting point instead of doing it yourself. Please note that I'm not an expert by any means. I'm just a completely normal person who read a bunch of wiki pages and decided to help people

Why would I want this? I'm not important and I have nothing to hide.
I'm the most boring and unimportant person ever, but I still did it. Because a hacker can obtain your data if they found an exploit/stole your computer. If you have nothing to hide, would you be happy to publish you passwords publicly? Of course not, no one wants that.

Does this replace common sense/will I be secure after this?
Absolutely NO, THERE IS NO SUCH THING AS %100 SECURITY, A DETERMINED ATTACKER MIGHT STILL BE ABLE TO COMPROMISE YOUR SYSTEM, THIS GUIDE IS NOT MEANT TO SECURE YOUR SYSTEM, it's meant to harden it instead.

Quote from the Arch wiki about security:

It is possible to tighten the security so much as to make your system unusable. The trick 
is to secure it without overdoing it.

There are many other things that can be done to heighten the security, but the biggest threat
is, and will always be, the user. When you think security, you have to think layers. When one
layer is breached, another should stop the attack. But you can never make the system 100% secure
unless you unplug the machine from all networks, lock it in a safe and never use it. Be a little
paranoid. It helps. And be suspicious. If anything sounds too good to be true, it probably is!
The principle of least privilege: each part of a system should only be able to access what is
required to use it, and nothing more.

Please note that physical security is as important as digital security.

Also note that security follows simplicity, the more simple your system is, the more secure it is.




Preperation and installation:

Get the Arch ISO from [archlinux.org]and verify the integrity using PGP and sha1sum.

Put the ISO on a USB drive(I'm going to assume that you know this).

Boot from the ISO.

Write lsblk a bunch of devices will show up

Take note of how everything is there

Insert a USB that is at least 2GB

Now write lsblk again

Identify the USB device

Fill it with random data using the following command

dd if=/dev/urandom of=/dev/sdX status=progress

Replace sdX with your USB drive.

This will overwrite all previous data on the USB drive and make them irrecoverable.

I'm going to assume that you have a hard drive without any partitions, write cfdisk /dev/sdX

Replace sdX by your hard drive.

Create 2 partitions, the first one will take all your hard drive space but will leave a few hundred megabytes.

The second one will have the rest(will be used to create a header file).

Fill the partitions with random data;

dd if=/dev/urandom of=/dev/sdXX status=progress

sdXX stands for the partitions on your hard drive, do this for both them.

Format the second one by:

mkfs.ext4 /dev/sdXX

mount the second one by:
mkdir /mnt/headerstore
mount /dev/sdXX /mnt/headerstore

Replace XX by your second partiton device.

Enter the directory /mnt/headerstore by cd, and create the header

dd if=/dev/zero of=header.img bs=4M count=1 conv=notrunc
[Source]

After that, create a luks2(encrypted partition) of your first partition in the hard drive(the big one).
cryptsetup luksFormat --type luks2 /dev/sdX --align-payload 8192 --header /mnt/headerstore/header.img

The flags' meaning, according to the Arch wiki:

When using option --header, --align-payload allows specifying the start of encrypted data 
on a device. By reserving a space at the beginning of device you have the option of later
reattaching the LUKS header.

Enter YES and write your password.

After that open it up

cryptsetup open --header=/mnt/headerstore/header.img /dev/sdX arch

If everything went correctly it should ask you for password now.

Now let's focus on the USB

Sources for this section:
[Arch Wiki]: FDE, Preparing the boot partition
[Arch Wiki]: Encrypted Boot and a detatched LUKS header on a USB

First of all create an EFI partition:

gdisk /dev/sdX

X stands for your USB device

Now create a new partition by typing n

it will show some sector range, press enter on the first one, on the second one write +512M.
This will give it 512 Megabytes of space which is going to have the EFI executable.
When it asks for hexadecimal code, give it EF00 which is the code for EFI System.

After that create a new one, this one is going to be the encrypted /boot.
To create it, type n then press enter and give it what remained of the USB.
When it asks for code give 8300 which stands for Linux filesystem, after that write the changes by typing w and exit.

Now format the EFI partition with FAT32(you have to do that or else the motherboard won't read it.

mkfs.fat -F 32 /dev/sdXX

Relpace XX by the EFI partition device.

After that create an encrypted parition at the second one by

cryptsetup luksFormat /dev/sdXX

Replace XX by the second parition at the USB (We aren't going to use LUKS2 because GRUB doens't support it yet).

After that, open it up by:

cryptsetup open /dev/sdXX cryptboot

After inserting your password, mount the partition by doing:

mkdir /mnt/cryptboot
mount /dev/mapper/cryptboot /mnt/cryptboot

When you do that, copy the header file from the second partition of the hard drive that we created earlier.

cp /mnt/headerstore/header.img /mnt/cryptboot/

After that, unmount the second partition of the hard drive.

umount /mnt/headerstore and destroy it to make the header irrecoverable from that partition:

dd if=/dev/urandom of=/dev/sdX status=progress

X is going to be the second partition of your hard drive.

LVM ON LUKS

Now we're going to create a logical volume on top of the first luks partition that we created earlier, I'm going to assume that it's still opened because we did that earlier

Sources for this section:
[Arch Wiki]: FDE, LVM on LUKS

First we create a physical volume:

pvcreate /dev/mapper/arch

Then we create a volume group named archlinux

vgcreate archlinux /dev/mapper/arch

Now create your volumes:

lvcreate -L XG archlinux -n root

lvcreate -L XG archlinux -n swap

Replace X by the size you want.

Now we're going to setup the partition:

mkfs.ext4 /dev/archlinux/root

mkswap /dev/archlinux/swap

swapon /dev/archlinux/swap

Now we're going to unmount everything we did in /mnt

umount /mnt/*

Delete the remaining folders

rm -r /mnt/*

And then we will mount the archlinux partitions properly

mount /dev/archlinux/root /mnt

mkdir /mnt/boot

mkdir /mnt/efi

mount /dev/mapper/cryptboot /mnt/boot

Now mount the efi parition(first partition from USB) to /mnt/efi

mount /dev/sdXX /mnt/efi

Installation

Sources for this section:
[Arch Wiki]: Installation

Now install Arch:

pacstrap /mnt base base-devel vim linux-hardened grub efibootmgr

We need base-devel for compiling firejail with apparmor support.

Wait until it finishes and generate the fstab:

genfstab -U /mnt >> /mnt/etc/fstab

Now chroot

arch-chroot /mnt

And enable the community-testing repository (for getting apparmor, you won't need to that in the future once it gets out of testing).

vim /etc/pacman.conf and uncomment [community-testing] and the line below it.

Now update the repositories

pacman -Syu

and install apparmor

pacman -S apparmor

Bootloader and initcpio configuration

Sources for this section:
[Arch Wiki]: Installation procedure and custom encrypt hook
[Arch Wiki]: Persistent block device naming by ID and Path

First off, write
ls -l /dev/disk/by-id/

And take a picture of the output of the id that corresponds to the encrypted boot partition(second parition on USB) and the id that corresponds to the encrypted LVM partition(first one on the hard drive) you can also copy it with vim if you want.

Now we're going to create a custom initcpio hook that fits our configuration.

I'm going to use a script that's mentioned by the Arch wiki here(slightly modified by me to fit our configuration):

[Arch Wiki]: Installation procedure and custom encrypt hook

create a file in /etc/initcpio/hooks/customencrypthook

#!/usr/bin/zsh
run_hook() { 

    modprobe -a -q dm-crypt >/dev/null 2>&1

    modprobe loop
 
    [ "${quiet}" = "y" ] && CSQUIET=">/dev/null" 

    while [ ! -L '/dev/disk/by-id/usbdrive-part2' ]; do 

        echo 'Waiting for USB' 
        sleep 1 
     done 

     cryptsetup open /dev/disk/by-id/usbdrive-part2 cryptboot 
     #replace usbdrive with the id that corresponds to the second USB partition

     mkdir -p /mnt

     mount /dev/mapper/cryptboot /mnt

     cryptsetup open /dev/disk/by-id/harddrive arch --header=/mnt/header.img 
     #harddrive represents your LVM partition id
    umount /mnt
}

Basically what this script does is it checks for presence of our USB device, if it does then it attempts to decrypt it.
Then it mounts it to /mnt, gets the header file, decrypts the LVM partition then it unmounts /mnt

After that copy some files

cp /usr/lib/initcpio/install/encrypt /etc/initpcio/install/customencrypthook

After that edit /etc/initpcio/install/customencrypthook and remove help() section as it is not necessary.

After that edit /etc/mkinitcpio.conf

Put this in the modules section

MODULES=(loop)

And put customencrypthook lvm2 in the HOOKS section after block and before filesystems.

Now we are going to execute

mkinitcpio -p linux for the linux kernel

After that execute

mkinitcpio -p linux-hardened for the linux-hardened kernel.

Bootloader setup and AppArmor and Audit Framework kernel parameters

Sources in this section:

[Arch Wiki]: AppArmor
[Arch Wiki]: Audit Framework
[Arch Wiki]: FDE, Configuring the bootloader

Edit /etc/default/grub and add these as kernel parameters between the quotes in GRUB_CMDLINE_LINUX="apparmor=1 security=apparmor audit=1".

The audit framework provides Controlled Access Protection Profile auditing system that reliably collects information about any security-relevant (or non-security-relevant) event on a system.
It can help you track actions performed on a system.
Which is needed by some AppArmor functiones to work properly.

After that add a line below GRUB_CMDLINE_LINUX:

GRUB_ENABLE_CRYPTODISK=y

Which is needed so that GRUB can detect the encrypted partitions.

After that enable the auditd and apparmor services:

systemctl enable apparmor

systemctl enable auditd

Now we're going to install the bootloader to the /efi parition by:

grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=GRUB --recheck

And we're going to configure the bootloader(it might throw some lvmetad errors, don't worry as long as it detects it in the end).

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

Now set the root password and create a normal user account and stuff like that.

Now type exit and reboot, if everything works fine then the boot process should continue like I described above.

Once your system boots run

sudo apparmor_status

If it shows 44 profiles are in enforce mode in the first line then you did it correctly!

Firejail

Sources in this section:
[Arch Wiki]: Firejail, Firejail with AppArmor

According to the Arch wiki:

Firejail is an easy to use SUID sandbox program that reduces the risk of security breaches 
by restricting the running environment of untrusted applications using Linux namespaces, 
seccomp-bpf and Linux capabilities

It's avaliable in the Arch repositories but without AppArmor support, to get AppArmor support you can either compile it yourself or get the package from the AUR, since the topic of the AUR can be controversial, I'm going to explain how to compile it yourself.

1 - clone the repository from here: https://github.com/netblue30/firejail

2 - enter the folder

3 - execute the following:

./configure --prefix=/usr --enable-apparmor

make

make install-strip

To enable its AppArmor profile, execute :

sudo aa-enforce firejail-default

If apparmor throws error about duplicate lines in a specific directory, simply go to that directory and comment the duplicate lines.

For some reason it throws an error about some "/ or variable", but when you restart and run sudo apparmor_status it should show firejail-default in the profiles.

There are many ways to execute apps with firejail and apparmor, check the wiki entry for more info.

Next steps:

[Arch Wiki]: Firewalls
[Arch Wiki]: Restricting Root
[Arch Wiki]: TCP/IP Stack Hardening


[return to /Ω/]