Skip to content

Instantly share code, notes, and snippets.

@dev1lsconf
Forked from umbernhard/arch-secure-install.md
Created August 31, 2022 16:43
Show Gist options
  • Save dev1lsconf/da00f2c2689a35815768bc622f70ea7c to your computer and use it in GitHub Desktop.
Save dev1lsconf/da00f2c2689a35815768bc622f70ea7c to your computer and use it in GitHub Desktop.

Revisions

  1. Matt Bernhard revised this gist Nov 13, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -195,7 +195,7 @@ HOOKS=(systemd base udev sd-plymouth autodetect keyboard keymap modconf block pl
    `doas` is OpenBSD's replacement for `sudo`, featuring a much more elegant codebase that has a smaller attack surface in comparison with sudo. This makes it more likely that systems relying on `doas` for privilege escalation are less likely to be impacted by bugs [like this one](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3156). On Arch, it is super easy to replace `sudo` with `doas`:

    ```
    yay -S opendoas o
    yay -S opendoas
    ```

    This installs `doas`, which I configure as follows in `/etc/doas.conf:
  2. Matt Bernhard revised this gist Nov 13, 2021. 1 changed file with 21 additions and 1 deletion.
    22 changes: 21 additions & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -192,4 +192,24 @@ HOOKS=(systemd base udev sd-plymouth autodetect keyboard keymap modconf block pl

    ## Swapping `doas` for `sudo`

    [TODO]
    `doas` is OpenBSD's replacement for `sudo`, featuring a much more elegant codebase that has a smaller attack surface in comparison with sudo. This makes it more likely that systems relying on `doas` for privilege escalation are less likely to be impacted by bugs [like this one](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3156). On Arch, it is super easy to replace `sudo` with `doas`:

    ```
    yay -S opendoas o
    ```

    This installs `doas`, which I configure as follows in `/etc/doas.conf:

    ```
    permit persist :wheel
    ```

    This allows any member of the `wheel` group to get root privileges. `persist` allows the authentication to be retained for up to five minutes, so you don't have to keep typing in your password.

    It's important that we remove `sudo` as well, otherwise we'll still be susceptible to flaws in it that permit privilege escalation attacks. Doing so is really easy:

    ```
    yay -S opendoas-sudo
    ```

    This will symlink `sudo` to `doas`, as well as uninstalling sudo if you enter `y` at the prompt.
  3. Matt Bernhard revised this gist Nov 6, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -14,7 +14,7 @@ I'm getting off the high horse now and getting on with the show.
    1. [Getting Started](#Getting-Started)
    3. [Setting up Secure Boot](#Setting-up-Secure-Boot)
    4. [Using TPM2-TOTP](#Using-TPM2-TOTP)
    5. [Using systemd-cryptsetup](#Using-systemd-cryptsetup)
    5. [Using systemd-cryptenroll](#Using-systemd-cryptsetup)
    6. [Working with dm-verity](#Working-with-dm-verity)
    7. [Swapping `doas` for `sudo`](#Swapping-doas-for-sudo)

    @@ -169,7 +169,7 @@ sudo reboot

    I've managed to get this working on my Framework laptop, but not on the Lenovo I'm using to write this guide. It's a little finicky, and it might be easiest just to stick with the default.

    ## Using systemd-cryptsetup [WIP]
    ## Using systemd-cryptenroll [WIP]

    If you don't want to have to type in a password at boot every time, you can enroll your LUKS key into the TPM using `systemd-cryptenroll`. Doing this will ensure that your disk is only decrypted if the system state (as measured by Secure Boot) matches a known-good configuration. Using the following configuration will ensure that the disk is unlocked only if everything up to and including the kernel match expected values (replace `/dev/tpmrm0` with the path to your tpm2 device, or use `auto`):

  4. Matt Bernhard revised this gist Nov 6, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -169,7 +169,7 @@ sudo reboot

    I've managed to get this working on my Framework laptop, but not on the Lenovo I'm using to write this guide. It's a little finicky, and it might be easiest just to stick with the default.

    ## Using systemd-cryptsetup
    ## Using systemd-cryptsetup [WIP]

    If you don't want to have to type in a password at boot every time, you can enroll your LUKS key into the TPM using `systemd-cryptenroll`. Doing this will ensure that your disk is only decrypted if the system state (as measured by Secure Boot) matches a known-good configuration. Using the following configuration will ensure that the disk is unlocked only if everything up to and including the kernel match expected values (replace `/dev/tpmrm0` with the path to your tpm2 device, or use `auto`):

  5. Matt Bernhard revised this gist Nov 2, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -174,7 +174,7 @@ I've managed to get this working on my Framework laptop, but not on the Lenovo I
    If you don't want to have to type in a password at boot every time, you can enroll your LUKS key into the TPM using `systemd-cryptenroll`. Doing this will ensure that your disk is only decrypted if the system state (as measured by Secure Boot) matches a known-good configuration. Using the following configuration will ensure that the disk is unlocked only if everything up to and including the kernel match expected values (replace `/dev/tpmrm0` with the path to your tpm2 device, or use `auto`):

    ```
    systemd-cryptenroll --tpm2-device=/dev/tpmrm0 --tpm2-pcrs=0,2,4,5,7 /dev/nvme0n1p2
    systemd-cryptenroll --tpm2-device=/dev/tpmrm0 --tpm2-pcrs=0+2+4+5+7 /dev/nvme0n1p2
    ```
    It will prompt you to enter a password, and if successful should unlock your disk on the next boot up. **Note:** you must re-enroll your key every time your kernel changes (every time sbupdate gets run), otherwise your disk will no longer decrypt automatically.

  6. Matt Bernhard revised this gist Nov 2, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -171,7 +171,7 @@ I've managed to get this working on my Framework laptop, but not on the Lenovo I

    ## Using systemd-cryptsetup

    If you don't want to have to type in a password at boot every time, you can enroll your LUKS key into the TPM using `systemd-cryptenroll`. Doing this will ensure that your disk is only decrypted if the system state (as measured by Secure Boot) matches a known-good configuration. Using the following configuration will ensure that the disk is unlocked only if everything up to and including the kernel match expected values (replace `/dev/tpmrm0` with the path to your tpm2 device):
    If you don't want to have to type in a password at boot every time, you can enroll your LUKS key into the TPM using `systemd-cryptenroll`. Doing this will ensure that your disk is only decrypted if the system state (as measured by Secure Boot) matches a known-good configuration. Using the following configuration will ensure that the disk is unlocked only if everything up to and including the kernel match expected values (replace `/dev/tpmrm0` with the path to your tpm2 device, or use `auto`):

    ```
    systemd-cryptenroll --tpm2-device=/dev/tpmrm0 --tpm2-pcrs=0,2,4,5,7 /dev/nvme0n1p2
  7. Matt Bernhard revised this gist Nov 2, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -174,7 +174,7 @@ I've managed to get this working on my Framework laptop, but not on the Lenovo I
    If you don't want to have to type in a password at boot every time, you can enroll your LUKS key into the TPM using `systemd-cryptenroll`. Doing this will ensure that your disk is only decrypted if the system state (as measured by Secure Boot) matches a known-good configuration. Using the following configuration will ensure that the disk is unlocked only if everything up to and including the kernel match expected values (replace `/dev/tpmrm0` with the path to your tpm2 device):

    ```
    systemd-cryptenroll --tpm2-device=/dev/tpmrm0 --tpm2-pcrs=0,2,4,5,7
    systemd-cryptenroll --tpm2-device=/dev/tpmrm0 --tpm2-pcrs=0,2,4,5,7 /dev/nvme0n1p2
    ```
    It will prompt you to enter a password, and if successful should unlock your disk on the next boot up. **Note:** you must re-enroll your key every time your kernel changes (every time sbupdate gets run), otherwise your disk will no longer decrypt automatically.

  8. Matt Bernhard revised this gist Nov 2, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -184,6 +184,7 @@ You also must replace the `encrypt` hook with `sd-encrypt`, `plymouth` with `sd-
    HOOKS=(systemd base udev sd-plymouth autodetect keyboard keymap modconf block plymouth-tpm2-totp sd-encrypt filesystems fsck)
    ```

    **WARNING:** enabling automatic decryption may make you more vulnerable to evil maid attacks, as you will not have the same opportunity to verify the state of the system before the disk decryption key is unsealed. Do this only if you know what you are doing!

    ## Working with dm-verity

  9. Matt Bernhard revised this gist Nov 2, 2021. 1 changed file with 13 additions and 1 deletion.
    14 changes: 13 additions & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -171,7 +171,19 @@ I've managed to get this working on my Framework laptop, but not on the Lenovo I

    ## Using systemd-cryptsetup

    [TODO]
    If you don't want to have to type in a password at boot every time, you can enroll your LUKS key into the TPM using `systemd-cryptenroll`. Doing this will ensure that your disk is only decrypted if the system state (as measured by Secure Boot) matches a known-good configuration. Using the following configuration will ensure that the disk is unlocked only if everything up to and including the kernel match expected values (replace `/dev/tpmrm0` with the path to your tpm2 device):

    ```
    systemd-cryptenroll --tpm2-device=/dev/tpmrm0 --tpm2-pcrs=0,2,4,5,7
    ```
    It will prompt you to enter a password, and if successful should unlock your disk on the next boot up. **Note:** you must re-enroll your key every time your kernel changes (every time sbupdate gets run), otherwise your disk will no longer decrypt automatically.

    You also must replace the `encrypt` hook with `sd-encrypt`, `plymouth` with `sd-plymouth` (if you're using plymouth), and add the `systemd` hook in your mkinitcpio.conf:

    ```
    HOOKS=(systemd base udev sd-plymouth autodetect keyboard keymap modconf block plymouth-tpm2-totp sd-encrypt filesystems fsck)
    ```


    ## Working with dm-verity

  10. Matt Bernhard revised this gist Oct 5, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -63,7 +63,7 @@ OUT_DIR="EFI/Linux"
    #SPLASH="/usr/share/systemd/bootctl/splash-arch.bmp"
    #BACKUP=1
    EXTRA_SIGN=('/boot/EFI/BOOT/BOOTX64.EFI' '/boot/EFI/systemd/systemd-bootx64.efi')
    CMDLINE_DEFAULT="cryptdevice=UUID={UUID}:cryptlvm root=/dev/mapper/volume-root quiet splash rw"
    CMDLINE_DEFAULT="cryptdevice=UUID={UUID}:luksdev root=/dev/mapper/luksdev quiet splash rw"
    ```

    Note that the `CMDLINE_DEFAULT` variable contains the same thing as the `options` variable from our systemd-boot file above, so make sure `{UUID}` is replaced correctly as in that file. Alternatively, you can just `cat /proc/cmdline >> /etc/sbupdate.conf` from a root shell and adjust as needed. The `EXTRA_SIGN` variable tells `sbupdate` to also sign and include systemd-boot and the basic Linux EFI stub into the unified image.
  11. Matt Bernhard revised this gist Oct 5, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -20,7 +20,7 @@ I'm getting off the high horse now and getting on with the show.

    ## Getting Started

    The first step is to install Arch normally, following the [installation guide](https://wiki.archlinux.org/title/Installation_guide), up to partitioning the disks. You will likely have to disable Secure Boot in your device's firmware before you can boot the archiso USB stick, which is good practice for later on. I would strongly recomend relying on the `archinstall` script to do the install, making sure to turn on disk encryption.
    The first step is to install Arch normally, following the [installation guide](https://wiki.archlinux.org/title/Installation_guide). You will likely have to disable Secure Boot in your device's firmware before you can boot the archiso USB stick, which is good practice for later on. I would strongly recomend relying on the `archinstall` script to do the install, making sure to turn on disk encryption.

    ## Setting up Secure Boot

  12. Matt Bernhard revised this gist Oct 5, 2021. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,6 @@ I'm getting off the high horse now and getting on with the show.

    ### Table of Contents
    1. [Getting Started](#Getting-Started)
    2. [After the first boot](#After-the-first-boot)
    3. [Setting up Secure Boot](#Setting-up-Secure-Boot)
    4. [Using TPM2-TOTP](#Using-TPM2-TOTP)
    5. [Using systemd-cryptsetup](#Using-systemd-cryptsetup)
  13. Matt Bernhard revised this gist Oct 5, 2021. 1 changed file with 0 additions and 14 deletions.
    14 changes: 0 additions & 14 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -23,20 +23,6 @@ I'm getting off the high horse now and getting on with the show.

    The first step is to install Arch normally, following the [installation guide](https://wiki.archlinux.org/title/Installation_guide), up to partitioning the disks. You will likely have to disable Secure Boot in your device's firmware before you can boot the archiso USB stick, which is good practice for later on. I would strongly recomend relying on the `archinstall` script to do the install, making sure to turn on disk encryption.

    ## After the first boot

    Congrats! You've now setup and Arch Linux system! What's that? You don't like just having a black terminal for an operating system?

    This section isn't related to security setup, but it will make your quality of life better. I'm assuming you're a human being, and you have probably used computers before, which means it might be nice to have a GUI. There's a *lot* of ways to accomplish this on Arch, but my preferred way is the GNOME desktop environment. People say it's bloated, and that's sort of true, but it does all the things I need it to do and as of yet I haven't found another desktop environment (more commonly abbreviated DE) that does it better. Checkout [Reddit](https://reddit.com/archlinux/) or the Wiki if you want to mess around with DEs and window managers (WMs) yourself.

    Depending on your choice of DE and your device, you may have to fight with getting graphics, mouse, fingerprint reader, and other drivers loaded. Trying to put all of that stuff in this guide would make it a book, so I'm going to skip it and tell you to rely on the Wiki, Reddit, StackOverflow, and other excellent Internet resources.

    There are only a few things I'm going to recommend. The first is and Arch User Repository ([AUR](https://wiki.archlinux.org/title/Arch_User_Repository)) manager. I like [yay](https://github.com/Jguer/yay) because it's fun to welcome packages onto my system with enthusiasm. Google around if you're more dour.

    I'm also going to recommend [Plymouth](https://aur.archlinux.org/packages/plymouth/), which is a splash screen manager for the boot process. The *only* reason I recommend it is because one of the security features we're going to add later, TPM2-TOTP, has an integration for it that displays nicely with it (it also provides a more aesthetically pleasing way to enter your disk encryption password, but oh my god, who cares). If you're not doing that step, I'd skip Plymouth altogether and keep your boot process faster. Make sure you follow the instructions for the `systemd-boot` hooks specifically (e.g. add `sd-plymouth` to your `mkinitcpio.conf` `HOOKS` variable instead of just `plymouth`).

    One other note about Plymouth: if you aren't seeing it display properly, it's possible that it's because your machine is too fast for it to work right. Confusingly, setting the `ShowDelay` variable to 0 in `/etc/plymouth/plymouthd.conf` ought to fix that.

    ## Setting up Secure Boot

    Now we are ready to implement Secure Boot. I want to stress again that I highly recommend Rod Smith's [super comprehensive explanation](https://www.rodsbooks.com/efi-bootloaders) of what UEFI and Secure Boot are and how they work. I will provide a breif recap here and dive into setting up Scure Boot.
  14. Matt Bernhard revised this gist Oct 5, 2021. 1 changed file with 1 addition and 287 deletions.
    288 changes: 1 addition & 287 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -21,293 +21,7 @@ I'm getting off the high horse now and getting on with the show.

    ## Getting Started

    The first step is to install Arch normally, following the [installation guide](https://wiki.archlinux.org/title/Installation_guide), up to partitioning the disks. You will likely have to disable Secure Boot in your device's firmware before you can boot the archiso USB stick, which is good practice for later on.

    Much of this guide's format and content was stolen from @OdinsPlasmaRifle's [really excellent guide](https://gist.github.com/OdinsPlasmaRifle/e16700b83624ff44316f87d9cdbb5c94). Where possible I've tried to expound a bit on why we're doing certain things, as well as modifying the guide to include additional steps that will make later implementing security features a little easier.

    ### Setting up the partitions

    From the archiso, run gdisk. For me, it looks like this:
    ```shell
    gdisk /dev/nvme0n1
    ```

    Wipe out the existing partition table, and add an EFI system partition (ESP) in the first 512 MB on the disk:

    ```shell
    o
    n
    (Enter)
    (Enter)
    512M
    ef00
    ```

    This partition will contain the bootloader, and will eventually be mounted at `boot`. Now create the LVM system partition, which will take up the whole rest of your disk. This partition will eventually be encrypted via LUKS2 and can contain subpartitions with different read/write permissions.

    ```shell
    n
    (Enter)
    (Enter)
    (Enter)
    8e00
    ```

    After you're done, printing the GPT should show the following (though your partition sizes will likely be different; the table below was on a 120GB nvme drive):
    ```shell
    Number Start (sector) End (sector) Size Code Name
    1 2048 1048576 511.0 MiB ef00 EFI system partition
    2 10506224 250069646 118.7 Gib 8e00 Linux LVM
    ```

    Write the partition table to the disk:

    ```shell
    w
    Y
    ```

    Now format the ESP (for compatability reasons, it must be FAT32 format):
    ```shell
    mkfs.fat -F32 /dev/nvme0n1p1
    ```

    ### Encrypting the disk

    The next step is to set up disk encryption. Depending on your application, an encrypted disk may be unnecessary (we'll see a way later on that will still verify the *contents* of the disk even if they aren't secret), but for most applications it's a good idea.

    First, make sure the `dm-crypt` module is loaded:
    ```shell
    modprobe dm-crypt
    ```

    Encrypt the disk using `cryptsetup`:
    ```shell
    cryptsetup luksFormat /dev/nvme0n1p2
    ```
    (Remember that the second partition on our disk is the LVM partition. I'm using an NVMe disk, but if you're running a different style of disk the preceding information may be different, e.g. your partition may be something like `/dev/sda2`)

    Running this will prompt you to make sure you're ready to encrypt the disk. Type `YES` at the prompt to proceed. Next, you will be prompted to set a disk encryption passsword. This password is one of two security critical passwords on the device, so make it a good one ([remember, length is better than character variation](https://xkcd.com/936/)). Additionally, **DO NOT FORGET THIS PASSWORD**. Doing so will render your machine completely unsuable, and you will lose all data stored on the disk. Mitigate this risk by choosing a memorable (but also unique not easily guessable) password, and performing frequent backups of your data).

    Once you have set your password, the disk is now encrypted and we are ready to begin setting up our LVM partitions. Start by decrypting the disk you just encrypted:
    ```shell
    cryptsetup luksOpen /dev/nvme0n1p2 cryptlvm
    ```

    `cryptlvm` is a label that you can subsequently use to reference the now-decrypted disk. LUKS mounts the disk in the `dev/mapper` folder, which is also where our LVM partitions will be mounted. Make sure the disk was decrypted and mounted properly:
    ```shell
    ls /dev/mapper/cryptlvm
    ```

    ### Configuring LVM

    LVM stands for Logical Volume Manager. For historical reasons I don't really understand, physical volumes, i.e. real hard disks, and logical volumes, software-managed "disks" that may or may not correspond to physical disks are not usually easy to manage. Logical volumes may take up only part of one physical disk, or may span multiple physical disks (akin to RAID0), so the filesystem needs an intelligent way of keeping track of which partitions/filesystems live on which disks. LVM does all of this abstraction for you. At least, that's my understanding, I'm not super well informed on LVM. I just know that it works for our purposes here.

    First, we tell LVM that there is a physical volume on our LVM partition (the disk itself knows that this partition exists; it doesn't know about the logical partitions we create next, that's what LVM manages).
    ```shell
    pvcreate /dev/mapper/cryptlvm
    ```

    Now we create a volume group, which is how LVM keeps track of which logical volumes are associated with a physical volume:
    ```shell
    vgcreate volume /dev/mapper/cryptlvm
    ```

    Now that we have a logical volume, tell LVM about our new logical partitions, starting with swap:
    ```shell
    lvcreate -L4G volume -n swap
    ```
    (Note that the size of this partition is up to you. General guidelines is something like half of RAM, but disks are so large these days in comparison to RAM that I've seen swap partitions as large as 4-5x the RAM. In case you're wondering, swap is used by the OS when RAM starts to get full. The OS can flush parts of RAM that aren't being used right this second to disk, effectively increasing the RAM size a little bit with a performance hit (which depends on the technology of disk you have; SSDs are pretty quick!)

    Next we create a root partition. This corresponds to the `/` directory in Unix-flavored systems, and this presents another opportunity to implement a security feature. Taking a note from Safeboot's spin on System Integrity Protection (SIP), we can choose a smaller root partition that will later on enable us to hash it using the dm-verity module. Doing so will allow us to extend the tamper-evidence that Secure Boot provides up into the operating system, as if the hashing on the root partition doesn't match an expected value, we will know that it may have been tampered with. Additionally, setting this partition to read-only prevents some attacks that rely on modifying the kernel.

    The downside to choosing a smaller root partition and mouting it as read-only is that it can make updating the system tricky. It also means we'll need more partitions over all, as we'll have to split out many folders that are traditionally kept on the root partition, like `/var`, as these partitions contain logging data that by definition needs to be writeable.

    Mounting your root partition at read-only is probably overkill for most applications. It's probably only a good idea you are setting up a machine that is not likely to receive updates frequently and needs a higher degree of protection. Doing this in Arch Linux is therefore not a great move, as the rolling update cycle will cause paine with a read-only root partition. Other distros, like Debian and Ubuntu, are less likely to have issues with this as they release more slowly and all at once. This is why Safeboot works with Ubuntu (in addition to it being a popular distro).

    If you are not planning to later add SIP, create a root partition that is larger than the one prescribed below (20G is probably enough, but 40G guarantees you'll never run out of space).

    ```shell
    lvcreate -L12G volume -n root
    ```

    If you are creating a read-only root partition, make sure to include a partition for `/var` (this may be a good idea for [other reasons too](https://access.redhat.com/discussions/641923)):
    ```shell
    lvcreate -L60G volume -n var
    ```

    Finally, create a home partition, where user data will be stored, with the rest of the space on the disk:
    ```shell
    lvcreate -l 100%FREE volume -n home
    ```

    Once you're done, you can run `lvdisplay` to check your work. [TODO: add what mine looks like?]

    ### Making the filesystems

    Now that we've created our logical volumes, we need to initialize file systems on each of them. The choice of file system is up to you. It's hard to go wrong with ext4, but more recent systems like ZFS or BTRFS may offer better data reliability options.
    ```shell
    mkfs.ext4 /dev/volume/root
    mkfs.ext4 /dev/volume/var
    mkfs.ext4 /dev/volume/home
    ```

    Also don't forget to setup the swap partition:
    ```shell
    mkswap /dev/volume/swap
    ```

    Now we can mount our file systems and proceed with installation!
    ```shell
    mount /dev/volume/root /mnt
    mkdir /mnt/home
    mkdir /mnt/var
    mkdir /mnt/boot
    mount /dev/volume/home /mnt/home
    mount /dev/volume/var /mnt/var
    mount /dev/nvme0n1p1 /mnt/boot
    swapon /dev/volume/swap
    ```

    ### Installation

    Bootstrap Arch onto our newly created filesystem, and install utilities:

    ```shell
    pacstrap /mnt base base-devel linux linux-firmware lvm2 vim
    ```
    (This may take a while depending on your network connection. I have the pleasure of doing this on a Lenovo Flex 14 with really shoddy wifi drivers, which means its taking even longer than usual.)

    Once that's done, generate `fstab`, the file used by the operating system to setup the disks at boot time:

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

    Now it's time to `chroot` into system. This basically lets you walk around inside the environment we've spent the last however many minutes setting up, and spruce up the place before you boot off the disk for real.

    ```shell
    arch-chroot /mnt
    ```

    Set time locale (choose a relevant locale):

    ```shell
    ln -sf /usr/share/zoneinfo/Africa/Johannesburg /etc/localtime
    ```

    Set clock:

    ```shell
    hwclock --systohc
    ```

    Uncomment `en_US.UTF-8 UTF-8` `en_US ISO-8859-1` and other needed localizations in `/etc/locale.gen`. This is really important, as it is needed by most programs to figure out what language localizations to run with. This includes not just the English (or your preferred language), but also the programming languages, like the version of C supported by your system.

    ```shell
    locale-gen
    ```

    Create locale config file:

    ```shell
    locale > /etc/locale.conf
    ```

    Set the lang variable in the above file:

    ```shell
    LANG=en_US.UTF-8
    ```

    Add an hostname (any hostname of your choice as one line in the file. eg. `myhostname`). This is the name of your device, that will be displayed at login and shouted at you through your bluetooth headphones when you connect, so pick something good!

    ```shell
    vim /etc/hostname
    ```

    Update `/etc/hosts`. This overrides DNS settings when your machine does name resolution, so adding the following lines will ensure that whenever a program tries to connect to `localhost` it gets the right IP address (in this case, the loopback address). I'm only including an IPv4 address. If you need IPv6, or more complicated settings, godspeed.

    ```text
    127.0.0.1 localhost
    ```

    Because our filesystem is on LVM we will need to enable the correct mkinitcpio hooks. These allow the initcpio, Arch's initial RAM file system that gets loaded into ram on boot, to include programs that can decrypt our hard drive.

    Edit the `/etc/mkinitcpio.conf`. Look for the HOOKS variable and move `keyboard` to before the `filesystems`. If you don't do that, you may not be able to type in your password! Additionally, add `sd-encrypt` and `lvm2` after `keyboard`. `sd-encrypt` is systemd-boot's hook, which will enable us to use systemd-cryptsetup later on). You can just use `encrypt` if you don't plan on using `systemd-cryptsetup` and are content to just enter a password on boot up every time (See the discussion below for why that may be the more secure thing to do depending on your needs).

    ```text
    HOOKS="base systemd udev autodetect modconf block keyboard sd-encrypt lvm2 filesystems fsck"
    ```

    If you're running an Intel-based system, you may also need to add `i915` to the `MODULES` field. Google it.

    Regenerate the initramfs (the `-p` flag here specifies the name of the image you're regenerating. To regenerate all of them, use `-P`)

    ```shell
    mkinitcpio -p linux
    ```

    Install the systemd-boot bootloader. Note that if you did something other than mount your boot partition at `/mnt/boot` above, you may need to pass the `--path` flag to tell `bootctl` where your ESP is.

    ```shell
    bootctl install
    ```

    Create the bootloader. Edit `/boot/loader/loader.conf`. Replace the file's contents with:

    ```text
    default arch
    timeout 0
    editor 0
    ```

    The `editor 0` ensures the configuration can't be changed on boot.

    Next create a bootloader entry in `/boot/loader/entries/arch.conf`

    ```text
    title Arch Linux
    linux /vmlinuz-linux
    initrd /initramfs-linux.img
    options cryptdevice=UUID={UUID}:cryptlvm root=/dev/mapper/volume-root quiet rw
    ```

    Replace `{UUID}` with the UUID of your LUKS drive. You can get it by running `blkid /dev/nvme0n1p2`, and I prefer piping this output into the bootloader entry file and editing it from there:

    ```shell
    blkid /dev/nvme0n1p2 >> /boot/loader/entries/arch.conf
    ```

    There are a few more things to explain here. The bootloader entry tells systemd-boot what files to load for this entry (the `linux` and `initrd`, i.e. "INITial Ram Disk"), and it passese options to the kernel command line through the `options` entry. These paramters, visible from the `/proc/cmdline` are basically parameters like any other program that tell the kernel to do certain things. Obviously the `cryptdevice` tells the kernel (and by extension the disk encryption kernel module) that the disk with that UUID is encrypted. The `root` parameter tells the kernel where the root file system is once the `cryptdevice` is decrypted. `quiet` tells the kernel not to show a bunch of the logging that happens on boot (you saw what this looks like when you booted from the thumb drive). `splash` tells the kernel to boot with a splash screen if there is one, and `rw` tells the kernel to mount the root partition in read/write mode.

    We *could* go ahead and finish the rest of our security setup below now, in which case this last parameter could be set to read-only. However, you're reading this guide, which means you may not know how to do this stuff. Putting off marking root as read-only gives us wiggle room to experiment later.

    **Important:** before exiting the chroot, you need to set a root password by typing `passwd`. You can also optionally add a non-root user, or you can wait until reboot to do so. Failing to set a root password will get you stuck at the login prompt once booted, and unable to do anything else. I typically also create my user account at this stage (the `-m` creates a home directory):

    ```
    useradd -m matt
    passwd matt
    ```

    **Important** before reboot, you probably also need to install a network manager. I'm choosing the `NetworkManager` package because it's used by GNOME, but any other works too. Without network access on reboot you won't be able to download any new packages. I usually just go ahead and install GNOME at this point while in the chroot, so that on the next bootup I get a nice graphical login.

    ```
    pacman -S gnome
    ```


    ### Reboot

    With that, we're done with installation! Now we'll exit the chroot and reboot.

    ```shell
    exit
    reboot
    ```

    In *theory* you should be good to go now. However, there's a good chance that things didn't go as planned and now you're either in a weird state (I was after I finished a trial install to write this, so you're in good company). This *probably* means you just typo'd something above. Don't freak out. Read whatever error message you're seeing and try googling it. Then, reboot back into the archiso. You can unlock and remount your file system and chroot into it just as we did when we set it up (though you don't have to do all the LVM configuration again). You can fix whatever may be wrong and then reboot again to see if you figured it out. It usually takes me a few iterations of that process to get things right, but don't give up. This is one place where Arch is significantly less fun that other distros with nice installers. But hey, you wanted bleeding edge, you get the bleeding.

    The first step is to install Arch normally, following the [installation guide](https://wiki.archlinux.org/title/Installation_guide), up to partitioning the disks. You will likely have to disable Secure Boot in your device's firmware before you can boot the archiso USB stick, which is good practice for later on. I would strongly recomend relying on the `archinstall` script to do the install, making sure to turn on disk encryption.

    ## After the first boot

  15. Matt Bernhard revised this gist Oct 5, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -436,6 +436,7 @@ cd tpm2-totp
    make
    sudo make install
    ```
    Note: the commands in the git repo are different than in the Arch repo, so I encourage you to look at the help message to figure out which set of commands you need to use.

    Now generate a new secret:
    ```
  16. Matt Bernhard revised this gist Oct 5, 2021. 1 changed file with 10 additions and 4 deletions.
    14 changes: 10 additions & 4 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -415,12 +415,18 @@ We now have Secure Boot setup! Wonderful! However, there is still potential for

    As part of the Secure Boot process, boot "measurements" are made and stored in the TPM, which provides secure registers that are difficult (though not impossible) to read without proper authorization. The registers are called platform configuration registers (PCRs), and each register contains certain data specified by the TPM standard. For example, PCR0 contains a hash of information about the device, including the firmware binary as well as a unique token stored in the TPM on the device. This means that PCR0 values are unique and cryptographically hard to fake. PCR values are also chained, so that the value in PCR1 contains a hash of new data (the specifics of which are not relevant here) *plus* the hash stored in PCR0. So on and so forth for the other PCRs. PCR7 contains a hash of the Secure Boot policy, including a hash of the databse of trusted keys, along with the hash chain, meaning that if we can have a reliable way to check its value we can make sure that our trusted databases have not been tampered with.

    This is where TPM2-TOTP comes in. It's a utility that takes advantage of the TPM's ability to generate time-based one-time passwords (TOTPs) just like the ones used by multifactor authentication apps. The TPM generates a secret based on the current values of the PCRs and some other data and shares that data with the user via a QR code. The QR code can be used with any MFA app (I like Authy or Duo).
    This is where TPM2-TOTP comes in. It's a utility that takes advantage of the TPM's ability to generate time-based one-time passwords (TOTPs) just like the ones used by multifactor authentication apps. The TPM generates a secret based on the current values of the PCRs and some other data and shares that data with the user via a QR code. The QR code can be used with any MFA app (I like Aegis).

    On boot, the TOTP is displayed at the screen where the user enters the disk encryption password, offering an opportunity to verify the state of the system before entering in a password that could potentially be sniffed by malicious software. If the TOTP doesn't match the one on the user's verification app, something has gone wrong and the system should not be trusted.

    TPM2-TOTP can be found [here](https://github.com/tpm2-software/tpm2-totp). I recommend downloading the source and compiling it, as the AUR version may not correctly configure the hooks needed by systemd-boot to display the codes. Most of the depencies should already be installed, though you will need to grab the `autoconf-archive` package.
    TPM2-TOTP can be found in the official repositories, as well as a `git` tracked version in the AUR and [here](https://github.com/tpm2-software/tpm2-totp). The official repo should work, but if it doesn't downloading the source and compiling it may be necessary to correctly configure the hooks needed by systemd-boot to display the codes. Most of the depencies should already be installed, though you will need to grab the `autoconf-archive` package.

    Install from official sources:
    ```
    sudo pacman -S tpm2-totp
    ```

    Install and build from source:
    ```
    sudo pacman -S autoconf-archive tpm2-tss qrencode
    git clone https://github.com/tpm2-software/tpm2-totp
    @@ -433,12 +439,12 @@ sudo make install

    Now generate a new secret:
    ```
    sudo tpm2-totp --pcrs=0,7 init
    sudo tpm2-totp --pcrs=0,7 generate
    ```

    Scan the QR code with your preferred authentication app, and then check that it worked:
    ```
    sudo tpm2-totp show
    sudo tpm2-totp calculate
    ```

    Make sure `tpm2-totp` appears in the `HOOKS` section of `/etc/mkinitcpio.conf` *before* `encrypt`, then regenerate the initramfs, resign, and reboot.
  17. Matt Bernhard revised this gist Oct 5, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -372,7 +372,7 @@ Note that the `CMDLINE_DEFAULT` variable contains the same thing as the `options
    Now, run the tool:
    `sbupdate`

    There should now be a file `linux-signed.efi` in `/boot/EFI/Arch` that corresponds to our signed unified image. Now we have to edit our systemd-boot entry to use that image only. Open the `/boot/loader/entries/arch.conf` file in your editor of choice and change it to this:
    There should now be a file `linux-signed.efi` in `/boot/EFI/Linux` that corresponds to our signed unified image. Systemd-Boot should pick this up automatically if there are no entries present in `/boot/loader/entries`. If you've found this is not the case, you can add a systemd-boot entry to use the signed image only. Open the `/boot/loader/entries/arch.conf` file in your editor of choice and change it to this:

    ```
    title Arch Linux Signed
  18. Matt Bernhard revised this gist Sep 13, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -376,7 +376,7 @@ There should now be a file `linux-signed.efi` in `/boot/EFI/Arch` that correspon

    ```
    title Arch Linux Signed
    efi /EFI/Arch/linux-signed.efi
    efi /EFI/Linux/linux-signed.efi
    ```

    Make sure to run `sudo bootctl update` to tell systemd-boot that there's a new boot image to load.
  19. Matt Bernhard revised this gist Sep 12, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -237,7 +237,7 @@ Because our filesystem is on LVM we will need to enable the correct mkinitcpio h
    Edit the `/etc/mkinitcpio.conf`. Look for the HOOKS variable and move `keyboard` to before the `filesystems`. If you don't do that, you may not be able to type in your password! Additionally, add `sd-encrypt` and `lvm2` after `keyboard`. `sd-encrypt` is systemd-boot's hook, which will enable us to use systemd-cryptsetup later on). You can just use `encrypt` if you don't plan on using `systemd-cryptsetup` and are content to just enter a password on boot up every time (See the discussion below for why that may be the more secure thing to do depending on your needs).

    ```text
    HOOKS="base udev autodetect modconf block keyboard sd-encrypt lvm2 filesystems fsck"
    HOOKS="base systemd udev autodetect modconf block keyboard sd-encrypt lvm2 filesystems fsck"
    ```

    If you're running an Intel-based system, you may also need to add `i915` to the `MODULES` field. Google it.
  20. Matt Bernhard revised this gist Aug 21, 2021. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -17,6 +17,7 @@ I'm getting off the high horse now and getting on with the show.
    4. [Using TPM2-TOTP](#Using-TPM2-TOTP)
    5. [Using systemd-cryptsetup](#Using-systemd-cryptsetup)
    6. [Working with dm-verity](#Working-with-dm-verity)
    7. [Swapping `doas` for `sudo`](#Swapping-doas-for-sudo)

    ## Getting Started

    @@ -468,4 +469,8 @@ I've managed to get this working on my Framework laptop, but not on the Lenovo I

    ## Working with dm-verity

    [TODO]

    ## Swapping `doas` for `sudo`

    [TODO]
  21. Matt Bernhard revised this gist Aug 20, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -359,7 +359,7 @@ yay -S sbupdate
    ```
    KEY_DIR="/etc/efi-keys"
    ESP_DIR="/boot"
    OUT_DIR="EFI/Arch"
    OUT_DIR="EFI/Linux"
    #SPLASH="/usr/share/systemd/bootctl/splash-arch.bmp"
    #BACKUP=1
    EXTRA_SIGN=('/boot/EFI/BOOT/BOOTX64.EFI' '/boot/EFI/systemd/systemd-bootx64.efi')
  22. Matt Bernhard revised this gist Aug 19, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -440,7 +440,7 @@ Scan the QR code with your preferred authentication app, and then check that it
    sudo tpm2-totp show
    ```

    Make sure `tpm-totp` appears in the `HOOKS` section of `/etc/mkinitcpio.conf`, then regenerate the initramfs, resign, and reboot.
    Make sure `tpm2-totp` appears in the `HOOKS` section of `/etc/mkinitcpio.conf` *before* `encrypt`, then regenerate the initramfs, resign, and reboot.
    ```
    sudo mkinitcpio -P
    sudo sbupdate
  23. Matt Bernhard revised this gist Aug 18, 2021. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -397,6 +397,8 @@ If you aren't so lucky as to have an awesome firmware interface that can enroll

    If you're using KeyTool, make sure to copy your keys over to `/boot` so that it can find them.

    **IMPORTANT:** Make sure you make backups of the existing keys. Depending on your device, turning on Secure Boot and trying to use new keys may make existing option ROMs unusable by the firmware, **effectively bricking your device.** This is especially an issue with CPUs that don't have internal graphics available; see the discussion [here](https://github.com/osresearch/safeboot/issues/84). If you think your device may need to use opROMs to boot, proceed with *extreme* caution. There are usually ways to restore the factory boot keys, e.g. by setting jumpers on the board. I don't believe this will be an issue with most newer consumer devices, but be warned. Always make sure to back up the existing keys. There may also [be ways to sign opROMs](https://github.com/osresearch/safeboot/issues/84#issuecomment-815402662) or to [add their hashes to `db`](https://github.com/Foxboron/sbctl/issues/85#issuecomment-886539689), but this is not a beginner friendly operation.

    After the keys are enrolled, make sure to regenerate the initramfs and the unified kernel, and resign it.

    ```
  24. Matt Bernhard revised this gist Aug 18, 2021. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -13,10 +13,10 @@ I'm getting off the high horse now and getting on with the show.
    ### Table of Contents
    1. [Getting Started](#Getting-Started)
    2. [After the first boot](#After-the-first-boot)
    3. [Setting up Secure Boot](#Setting up Secure Boot)
    4. [Using systemd-cryptsetup](#Using systemd-cryptsetup)
    5. [Using TPM2-TOTP](#Using TPM2-TOTP)
    6. [Working with dm-verity](#Working with dm-verity)
    3. [Setting up Secure Boot](#Setting-up-Secure-Boot)
    4. [Using TPM2-TOTP](#Using-TPM2-TOTP)
    5. [Using systemd-cryptsetup](#Using-systemd-cryptsetup)
    6. [Working with dm-verity](#Working-with-dm-verity)

    ## Getting Started

  25. Matt Bernhard revised this gist Aug 18, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -11,8 +11,8 @@ Using Linux is designed to be an empowering and enriching experience. Therefore,
    I'm getting off the high horse now and getting on with the show.

    ### Table of Contents
    1. [Getting Started](#Getting Started)
    2. [After the first boot](#After the first boot)
    1. [Getting Started](#Getting-Started)
    2. [After the first boot](#After-the-first-boot)
    3. [Setting up Secure Boot](#Setting up Secure Boot)
    4. [Using systemd-cryptsetup](#Using systemd-cryptsetup)
    5. [Using TPM2-TOTP](#Using TPM2-TOTP)
  26. Matt Bernhard revised this gist Aug 17, 2021. No changes.
  27. Matt Bernhard revised this gist Aug 17, 2021. 1 changed file with 143 additions and 1 deletion.
    144 changes: 143 additions & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -286,6 +286,7 @@ We *could* go ahead and finish the rest of our security setup below now, in whic

    ```
    useradd -m matt
    passwd matt
    ```

    **Important** before reboot, you probably also need to install a network manager. I'm choosing the `NetworkManager` package because it's used by GNOME, but any other works too. Without network access on reboot you won't be able to download any new packages. I usually just go ahead and install GNOME at this point while in the chroot, so that on the next bootup I get a nice graphical login.
    @@ -322,6 +323,147 @@ I'm also going to recommend [Plymouth](https://aur.archlinux.org/packages/plymou
    One other note about Plymouth: if you aren't seeing it display properly, it's possible that it's because your machine is too fast for it to work right. Confusingly, setting the `ShowDelay` variable to 0 in `/etc/plymouth/plymouthd.conf` ought to fix that.

    ## Setting up Secure Boot
    ## Using systemd-cryptsetup

    Now we are ready to implement Secure Boot. I want to stress again that I highly recommend Rod Smith's [super comprehensive explanation](https://www.rodsbooks.com/efi-bootloaders) of what UEFI and Secure Boot are and how they work. I will provide a breif recap here and dive into setting up Scure Boot.

    Secure Boot is a feature of the Unified Extensible Firmware Interface (UEFI), which we've already been interacting with on the down low. UEFI is basically a standard set of features that device firmware can implement (including a first-stage bootloader), and Secure Boot is one of its features. UEFI firmware has a notion of EFI executables that can be run after the firmware gets initialized (if you've ever mashed F12 repeatedly after pushing the power button to launch a live USB, the menu that comes up to let you select the live image is a list of EFI executables that the firmware has found.

    Systemd-boot is a specific kind of EFI executable called a *boot manager* (also referred to as a second-stage boot loader), that in turn has a more sophistacted set of features for deciding what programs get control on boot. In principle, with the Linux kernel's EFISTUB implementation, you could just launch the kernel directly from UEFI, but this offers less flexibility (you can only boot one thing, whereas with a boot manager you can set multiple options, i.e. a regular image, a recovery image, rebooting into the firmware, etc). Additionally, using a boot manager gives us the ability to use software at boot time to do things like decrypting the hard disk, interacting with the TPM, and measuring the firmware, boot manager, and kernel to make sure nothing has changed unexpectedly.

    ### Generating keys

    Secure boot works by generating a set of signing keys which are used to cryptographically sign EFI executables so that only signed executables can be run via a UEFI implementation with Secure Boot turned on. Secure Boot relies on two different keys, a Platform Key (PK) and a Key Exchange Key (KEK). I'm not going to go into depth here, again check out Rod Smith's site, but briefly the PK is associated with your platform (usually the TPM on the motherboard), the KEK is used to sign a trusted list of signatures and keys (referred to as the database or db), and also to sign a ban list of signatures and keys not trusted by the machine owner (dbx). There are also pther auxiliary keys like Machine Owner Keys (MOKs) that came about as a way for one signing authority to delegate others, but again that's not really important to our discussion here.

    To generate the keys and signatures we need to get Secure Boot working, I recommend just pulling down Rod Smith's script, described [here](https://www.rodsbooks.com/efi-bootloaders/controlling-sb.html#creatingkeys) and wget'able [here](https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh). You also need the `efitools` package.

    ```
    sudo pacman -S efitools
    sudo mkdir /etc/efi-keys
    cd !$
    sudo wget https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh
    sudo chmod +x mkkeys.sh
    sudo ./mkkeys.sh
    ```

    The script will ask you to enter a Common Name, part of the X509 certificate standard. You can just put in whatever you'd like.

    ### Generating and signing a unified EFI image

    Now that we have signing keys, it's time to sign. I really like the [`sbupdate` tool](https://github.com/andreyv/sbupdate#sbupdate), which makes it seamless to generate a unified kernel and bootloader image as well as sign it. Installing `sbupdate` also installs pacman hooks which automatically remake and sign the unified image whenever the system is updated, so you don't have to do it manually every time. Of course, the usual caveats about choosing which software to include in your trusted arsenal apply, but fortunately it's a quite small package that consists of a bash script and some hooks, so it's fairly easy to verify by eye.
    ```
    yay -S sbupdate
    ```

    `sbupdate` does require some configuration, as once it is installed it is the program responsible for setting the kernel command line, splash screen, and other things.

    ```
    KEY_DIR="/etc/efi-keys"
    ESP_DIR="/boot"
    OUT_DIR="EFI/Arch"
    #SPLASH="/usr/share/systemd/bootctl/splash-arch.bmp"
    #BACKUP=1
    EXTRA_SIGN=('/boot/EFI/BOOT/BOOTX64.EFI' '/boot/EFI/systemd/systemd-bootx64.efi')
    CMDLINE_DEFAULT="cryptdevice=UUID={UUID}:cryptlvm root=/dev/mapper/volume-root quiet splash rw"
    ```

    Note that the `CMDLINE_DEFAULT` variable contains the same thing as the `options` variable from our systemd-boot file above, so make sure `{UUID}` is replaced correctly as in that file. Alternatively, you can just `cat /proc/cmdline >> /etc/sbupdate.conf` from a root shell and adjust as needed. The `EXTRA_SIGN` variable tells `sbupdate` to also sign and include systemd-boot and the basic Linux EFI stub into the unified image.

    Now, run the tool:
    `sbupdate`

    There should now be a file `linux-signed.efi` in `/boot/EFI/Arch` that corresponds to our signed unified image. Now we have to edit our systemd-boot entry to use that image only. Open the `/boot/loader/entries/arch.conf` file in your editor of choice and change it to this:

    ```
    title Arch Linux Signed
    efi /EFI/Arch/linux-signed.efi
    ```

    Make sure to run `sudo bootctl update` to tell systemd-boot that there's a new boot image to load.

    ### Configuring Secure Boot in firmware

    At this point we have now generated keys and a unified kernel image, and signed it, but the firmware still doesn't know what keys to trust, so we have to tell it. Reboot into the firmware interface. If you'd like to avoid having to mash the F2 key on reboot every time, you can use bootctl to reboot into the firmware interface:

    ```
    sudo bootctl set-oneshot auto-reboot-to-firmware-setup
    sudo reboot
    ```

    On reboot, if you haven't already, the first thing you should do is set an administrator password on your firmware interface. It's not much good configuring Secure Boot if someone can just go in and turn it off! As with your disk encryption password, do not forget this password! But also pick a good one that's unique and memorable. If you absolutely must, stash the password in a password manager that you trust.

    After that, it's time to enroll the keys you generated earlier into the firmware. On some devices, like the Framework laptop, you can do this directly from the firmware interface. On the Secure Boot page, there are options for locating the PK, KEK, db, and dbx files on the boot partition.

    If you aren't so lucky as to have an awesome firmware interface that can enroll keys, you'll have to use `sbkeysync` or `KeyTools`, instructions for which you can find on the [Arch wiki](https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Enrolling_keys_in_firmware). I've never had much luck with `sbkeysync`, but hopefully you will. Remember to set your firmware interface to `Setup Mode` before trying to use either.

    If you're using KeyTool, make sure to copy your keys over to `/boot` so that it can find them.

    After the keys are enrolled, make sure to regenerate the initramfs and the unified kernel, and resign it.

    ```
    sudo mkinitcpio -P
    sudo sbupdate
    ```

    Finally, turn on Secure Boot in the firmware interface and reboot. If you get into the OS, congratulations, you've successfully setup Secure Boot with keys only known to you! After this step, make sure to remove the keys from your `/boot` partition, as that partition isn't encrypted and will leak the keys to an attacker, which kind of defeats the point.

    ## Using TPM2-TOTP

    We now have Secure Boot setup! Wonderful! However, there is still potential for someone to tamper with the system undetected. An attacker can attach a microcontroller to the motherboard of the device and flash a new database of signed EFI executables, and then boot whatever they want. While we can't stop this attack, we can make it easier to detect using the Trusted Platform Module (TPM) that is resident on pretty much every x86 system produced in the last ten years (and even some non-x86 ones).

    As part of the Secure Boot process, boot "measurements" are made and stored in the TPM, which provides secure registers that are difficult (though not impossible) to read without proper authorization. The registers are called platform configuration registers (PCRs), and each register contains certain data specified by the TPM standard. For example, PCR0 contains a hash of information about the device, including the firmware binary as well as a unique token stored in the TPM on the device. This means that PCR0 values are unique and cryptographically hard to fake. PCR values are also chained, so that the value in PCR1 contains a hash of new data (the specifics of which are not relevant here) *plus* the hash stored in PCR0. So on and so forth for the other PCRs. PCR7 contains a hash of the Secure Boot policy, including a hash of the databse of trusted keys, along with the hash chain, meaning that if we can have a reliable way to check its value we can make sure that our trusted databases have not been tampered with.

    This is where TPM2-TOTP comes in. It's a utility that takes advantage of the TPM's ability to generate time-based one-time passwords (TOTPs) just like the ones used by multifactor authentication apps. The TPM generates a secret based on the current values of the PCRs and some other data and shares that data with the user via a QR code. The QR code can be used with any MFA app (I like Authy or Duo).

    On boot, the TOTP is displayed at the screen where the user enters the disk encryption password, offering an opportunity to verify the state of the system before entering in a password that could potentially be sniffed by malicious software. If the TOTP doesn't match the one on the user's verification app, something has gone wrong and the system should not be trusted.

    TPM2-TOTP can be found [here](https://github.com/tpm2-software/tpm2-totp). I recommend downloading the source and compiling it, as the AUR version may not correctly configure the hooks needed by systemd-boot to display the codes. Most of the depencies should already be installed, though you will need to grab the `autoconf-archive` package.

    ```
    sudo pacman -S autoconf-archive tpm2-tss qrencode
    git clone https://github.com/tpm2-software/tpm2-totp
    cd tpm2-totp
    ./bootstrap
    ./configure --sysconfdir=/etc
    make
    sudo make install
    ```

    Now generate a new secret:
    ```
    sudo tpm2-totp --pcrs=0,7 init
    ```

    Scan the QR code with your preferred authentication app, and then check that it worked:
    ```
    sudo tpm2-totp show
    ```

    Make sure `tpm-totp` appears in the `HOOKS` section of `/etc/mkinitcpio.conf`, then regenerate the initramfs, resign, and reboot.
    ```
    sudo mkinitcpio -P
    sudo sbupdate
    sudo reboot
    ```

    If the value you see is the one on your other device, things should be working. Regenerate the initramfs and resign, then reboot. At the password prompt, you should see the code, which you can verify.


    ### Installing with Plymouth


    If you would like a better looking version of this, install plymouth before installing TPM2-TOTP. The `./configure` step should automatically detect that plymouth is installed and do the right thing. Note that you will have to add `systemd sd-encrypt sd-plymouth sd-plymouth-tpm2-totp` to your `/etc/mkinitcpio.conf` file's `HOOKS` section.
    ```
    sudo mkinitcpio -P
    sudo sbupdate
    sudo reboot
    ```

    I've managed to get this working on my Framework laptop, but not on the Lenovo I'm using to write this guide. It's a little finicky, and it might be easiest just to stick with the default.

    ## Using systemd-cryptsetup

    [TODO]

    ## Working with dm-verity

    [TODO]
  28. Matt Bernhard revised this gist Aug 16, 2021. 1 changed file with 26 additions and 2 deletions.
    28 changes: 26 additions & 2 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -10,10 +10,19 @@ Using Linux is designed to be an empowering and enriching experience. Therefore,

    I'm getting off the high horse now and getting on with the show.

    ### Table of Contents
    1. [Getting Started](#Getting Started)
    2. [After the first boot](#After the first boot)
    3. [Setting up Secure Boot](#Setting up Secure Boot)
    4. [Using systemd-cryptsetup](#Using systemd-cryptsetup)
    5. [Using TPM2-TOTP](#Using TPM2-TOTP)
    6. [Working with dm-verity](#Working with dm-verity)

    ## Getting Started

    The first step is to install Arch normally, following the [installation guide](https://wiki.archlinux.org/title/Installation_guide), up to partitioning the disks. Much of this guide's format and content was stolen from @OdinsPlasmaRifle's [really excellent guide](https://gist.github.com/OdinsPlasmaRifle/e16700b83624ff44316f87d9cdbb5c94). Where possible I've tried to expound a bit on why we're doing certain things, as well as modifying the guide to include additional steps that will make later implementing security features a little easier.
    The first step is to install Arch normally, following the [installation guide](https://wiki.archlinux.org/title/Installation_guide), up to partitioning the disks. You will likely have to disable Secure Boot in your device's firmware before you can boot the archiso USB stick, which is good practice for later on.

    Much of this guide's format and content was stolen from @OdinsPlasmaRifle's [really excellent guide](https://gist.github.com/OdinsPlasmaRifle/e16700b83624ff44316f87d9cdbb5c94). Where possible I've tried to expound a bit on why we're doing certain things, as well as modifying the guide to include additional steps that will make later implementing security features a little easier.

    ### Setting up the partitions

    @@ -273,7 +282,18 @@ There are a few more things to explain here. The bootloader entry tells systemd-

    We *could* go ahead and finish the rest of our security setup below now, in which case this last parameter could be set to read-only. However, you're reading this guide, which means you may not know how to do this stuff. Putting off marking root as read-only gives us wiggle room to experiment later.

    [TODO: create a user and a password and run passwd for root!]
    **Important:** before exiting the chroot, you need to set a root password by typing `passwd`. You can also optionally add a non-root user, or you can wait until reboot to do so. Failing to set a root password will get you stuck at the login prompt once booted, and unable to do anything else. I typically also create my user account at this stage (the `-m` creates a home directory):

    ```
    useradd -m matt
    ```

    **Important** before reboot, you probably also need to install a network manager. I'm choosing the `NetworkManager` package because it's used by GNOME, but any other works too. Without network access on reboot you won't be able to download any new packages. I usually just go ahead and install GNOME at this point while in the chroot, so that on the next bootup I get a nice graphical login.

    ```
    pacman -S gnome
    ```


    ### Reboot

    @@ -301,3 +321,7 @@ I'm also going to recommend [Plymouth](https://aur.archlinux.org/packages/plymou

    One other note about Plymouth: if you aren't seeing it display properly, it's possible that it's because your machine is too fast for it to work right. Confusingly, setting the `ShowDelay` variable to 0 in `/etc/plymouth/plymouthd.conf` ought to fix that.

    ## Setting up Secure Boot
    ## Using systemd-cryptsetup
    ## Using TPM2-TOTP
    ## Working with dm-verity
  29. Matt Bernhard revised this gist Aug 16, 2021. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -273,6 +273,8 @@ There are a few more things to explain here. The bootloader entry tells systemd-

    We *could* go ahead and finish the rest of our security setup below now, in which case this last parameter could be set to read-only. However, you're reading this guide, which means you may not know how to do this stuff. Putting off marking root as read-only gives us wiggle room to experiment later.

    [TODO: create a user and a password and run passwd for root!]

    ### Reboot

    With that, we're done with installation! Now we'll exit the chroot and reboot.
  30. Matt Bernhard revised this gist Aug 16, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion arch-secure-install.md
    Original file line number Diff line number Diff line change
    @@ -260,7 +260,7 @@ Next create a bootloader entry in `/boot/loader/entries/arch.conf`
    title Arch Linux
    linux /vmlinuz-linux
    initrd /initramfs-linux.img
    options cryptdevice=UUID={UUID}:cryptlvm root=/dev/volume/root quiet rw
    options cryptdevice=UUID={UUID}:cryptlvm root=/dev/mapper/volume-root quiet rw
    ```

    Replace `{UUID}` with the UUID of your LUKS drive. You can get it by running `blkid /dev/nvme0n1p2`, and I prefer piping this output into the bootloader entry file and editing it from there: