1. Foreword
  2. Prerequisites
  3. Disk Partitioning
  4. Encrypting Root
  5. Applying Filesystems and Mounting
  6. Debootstrap
  7. The Chroot Environment
    1. Installing Base Components your_img

Foreword

  • Bare Minimal Install
    • Only packages required for function as well as a text editor will be installed.
  • LUKS Full Disk Encryption
    • we will be utilizing cryptsetup to set up strong full disk encryption.
  • **efibootmgr **
    • We will get debian to play nicely with efibootmgr, no GRUB needed!
  • dracut
    • We will configure debian to utilize dracut vice initramfs-tools, as it is easier to configure and automate.

Prerequisites

This guide will assume you have the following:

  • An internet connection
  • A GNU/Linux system
  • The following packages (can be found on nearly all distros)
    • cryptsetup, dd, debootstrap, arch-chroot OR chroot

partition scheme

we will be creating 3 total partitions

  1. a /boot partition
  2. a /root partition (to be encrypted)
  3. a /home partition (to be encrypted)

in my system, the target device will be /dev/sdc

wiping the target device

lsblk -f /dev/sdc
sdc
├─sdc1                                
├─sdc2                                
└─sdc3                                

currently, there are multiple partitions present. ensure there is no important data on it, and issue the following command to wipe it (including the partition table)

sudo shred -fuvzn 1 /dev/sdc

there is no need to wait for it to cycle through completely unless you are excessively paranoid.

now, verify that it’s been wiped.

lsblk -f /dev/sdc
sdc

assigning partitions

now, let’s apply partitions to the drive.

sudo cfdisk /dev/sdc
/dev/sdc1                      2048           526335           524288          256m efi system
/dev/sdc2                    526336        419956735        419430400          200g linux filesystem
/dev/sdc3                 419956736        976773119        556816384        265.5g linux filesystem
  1. first partition, between 256m and 1g “efi system” type partition
  2. second partition for root, can generally be quite a bit smaller than home. i went with 200g. default “linux filesystem” works here.
  3. third partition for home, use the remaining space. default “linux filesystem” works here.

encrypting the partitions

now, we will encrypt our two partitions and unlock them

$ cryptsetup --label crypthome -c aes-xts-plain64 -y -s 512 luksformat /dev/sdc2
$ cryptsetup luksopen /dev/sdc2 cryptroot 
$ cryptsetup --label crypthome -c aes-xts-plain64 -y -s 512 luksformat /dev/sdc3
$ cryptsetup luksopen /dev/sdc3 crypthome

applying filesystems and mounting

$ mkfs.fat -f 32 /dev/sdc1
$ mkfs.ext4 /dev/mapper/cryptroot
$ mkfs.ext4 /dev/mapper/crypthome
$ mount /dev/mapper/cryptroot /mnt
$ mkdir /mnt/home
$ mount /dev/mapper/crypthome /mnt/home
$ mkdir /mnt/boot 
$ mount /dev/sdc1 /mnt/boot 

now, we must mount directories such as /proc and /sys as slaves. this will allow the chroot environment to access more aspects of the host system, such as efivars and networking (which becomes important later)

  • note, arch-chroot does this for you. skip the mounting block below if you wish to utilize said command.
$ mount --types proc /proc /mnt/proc
$ mount --rbind /sys /mnt/sys
$ mount --make-rslave /mnt/sys
$ mount --rbind /dev /mnt/dev
$ mount --make-rslave /mnt/dev
$ mount --bind /run /mnt/run
$ mount --make-slave /mnt/run 

debootstrapping

now, before we can chroot in, we must deploy a base install of debian stable.

sudo debootstrap --arch amd64 stable /mnt https://deb.debian.org/debian
  • this is super barebones, it does not come with a kernel, a bootloader, sudo/doas, wifi or any firmware. more on that later.

the chroot environment

now that there is a bare system, let’s begin configuring it.

first, copy your resolvconf

sudo cp /etc/resolvconf.conf /mnt/etc/

execute the chroot

sudo arch-chroot /mnt

fstab, crypttab and /home

before we proceed, let’s make it so our encrypted home is automatically unlocked and mounted when we unlock our root drive. to read more about this process, see my other page here

we will be working all with uuid’s below.

to orient ourselves, we need to run an lsblk -f first.

name         mountpoints fsuse% label    fstype      uuid
sdc
├─sdc1       	/mnt/boot      19%          vfat        47e8-f103
├─sdc2                          cryptroot crypto_luks 0c401b77-7b4c-4a9f-95fd-502568c64c73
│ └─cryptroot	/mnt            1%          ext4        5c9e4f0a-92f2-4b50-a993-9c3bd81f060e
└─sdc3                          crypthome crypto_luks 3db4034a-ac9d-433f-a50c-e2e7c4ecf503
  └─crypthome	/mnt/home      12%          ext4        9fc3f7b3-ded3-40e8-94d8-78abacc5fdbc

the keyfile

let’s first generate a keyfile for /dev/sdc3 so we can automate the unlocking.

mkdir /etc/keys
cd /etc/keys
dd if=/dev/random of=home.key bs=4096 count=1
cryptsetup luksaddkey /dev/sdc3 home.key

crypttab

now, let’s tell crypttab to utilize the key on startup

edit your /etc/crypttab file to include the below information. remember, the uuid is the uuid of the crypto_luks partition containing the /home, not the unencrypted ext4 partition inside of it

crypthome uuid=3db4034a-ac9d-433f-a50c-e2e7c4ecf503 /etc/keys/home.key

fstab

now, for the fstab, we will be working with uuids as well. this isn’t explicitly necessary, but on a device with many sata/nvme devices, it’s a very good habit to build.

# this is the uuid of the ext4 partition inside of /dev/sdc2
uuid=5c9e4f0a-92f2-4b50-a993-9c3bd81f060e 	    	/      	ext4      	defaults,rw,noatime,nodiratime	0 1

# this is the uuid of the ext4 partition inside of /dev/sdc3, the one we made a keyfile for
uuid=9fc3f7b3-ded3-40e8-94d8-78abacc5fdbc		/home      	ext4      	defaults,rw,noatime,nodiratime	0 2

# this is the uuid of the vfat partition inside of /dev/sdc1
uuid=47e8-f103		/boot 	vfat      	rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro	0 2

configuring apt

to enable non-free, add the following to /etc/apt/sources.list

deb https://deb.debian.org/debian stable main non-free contrib non-free-firmware

optionally, to disable the auto installation of recommended/suggested software, add the following lines to /etc/apt/apt.conf

apt::install-recommends "false";
apt::install-suggests "false";

configuring dracut

first, ensure dracut is installed

sudo apt install dracut

this will remove debian’s initramfs-tools, which is the goal here. do so.

in /etc/dracut.conf.d/, we will make a file ending in .conf

add the following lines to it. “amdgpu” isn’t needed unless you want the driver to load early.

# /etc/dracut.conf.d/10.conf
hostonly="yes"
add_drivers+=" amdgpu vfat "
add_dracutmodules+=" crypt "

installing efibootmgr with kernel/ hooks

first, install efibootmgr

sudo apt install efibootmgr

efibootmgr config file

now, we must configure efibootmgr to work functionally. we must create 3 files. this was taken and adapted from void linux’ implimentation of efibootmgr, which will update your boot entry based on the correct kernel version.

first, the config file

cat /mnt/etc/default/efibootmgr-kernel-hook
# options for the kernel hook script installed by the efibootmgr package.
# to allow efibootmgr to modify boot entries, set
modify_efi_entries=1
# kernel command-line options.  example:
options="quiet loglevel=3 fbcon=font:ter16x32 fbcon=nodefer rd.luks.name=0c401b77-7b4c-4a9f-95fd-502568c64c73=cryptroot root=/dev/mapper/cryptroot"
# disk where efi partition is.  default is /dev/sda
disk="/dev/disk/by-id/ata-samsung_ssd_860_evo_500gb_s3z1ny0m626144t"
# partition number of efi partition.  default is 1
part=1

as a note, my “disk=” points to the device by id, you could give an argument such as “/dev/nvme0n1” or “/dev/sda” depending on your actual target device.

additionally, ensure your “rd.luks.name” points to the crypto_luks uuid of your root partition.

postinst.d/ hook

This hook will be ran when debian installs a new kernel. This will take the kernel installed to /boot with the correct version number and architechture, then generate and apply a new efibootmgr entry to reflect the newly created initrd and vmlinuz files.

Place this script in /etc/kernel/postinst.d, I named mine zz-crypt. Ensure you make it executable!

#!/usr/bin/sh
#
# kernel hook for efibootmgr.
#
# arguments passed to this script: $1 pkgname, $2 version.
#
# use pkgname
pkgname="$1"
# not version
version="$2"

. "${rootdir}/etc/default/efibootmgr-kernel-hook"
if [ "x${modify_efi_entries}" != x1 ]; then
exit 0
fi

options="${options} initrd=/initrd.img-${pkgname}"

args=""
if [ "x${disk}" != x ]; then
args="-d $disk"
fi
if [ "x${part}" != x ]; then
args="$args -p $part"
fi

# get major version, e.g. "4.8" for "linux4.8"
major_version=$(echo $pkgname | cut -c 6-)

# look for previous entry for this major kernel version
existing_entry=$(efibootmgr | grep "debian-${pkgname}")

# get the boot order
# this is required because when in the next step the existing entry is removed,
# it is also removed from the order so it needs to be restored later
bootorder=$(efibootmgr |grep "bootorder: " |cut -c 12-)

# if existing, remove it
if [ "$existing_entry" != "" ]; then
/etc/kernel.d/postrm.d/zz-efibootmgr $pkgname
fi

# create the new entry
efibootmgr -qc $args -l "debian-${pkgname}" -l /vmlinuz-${pkgname} -u "${options}"
echo "efibootmgr -qc $args -l "debian-${pkgname}" -l /vmlinuz-${pkgname} -u "${options}""

# restore the boot order
efibootmgr -qo $bootorder

postrm.d/ hook

This hook, much like the prior one, will detect your old entry and remove it. This will only trigger when an old kernel is removed.

#!/bin/sh
#
# Kernel hook for efibootmgr.
#
# Arguments passed to this script: $1 pkgname, $2 version.
#
PKGNAME="$1"

. "${ROOTDIR}/etc/default/efibootmgr-kernel-hook"
if [ "x${MODIFY_EFI_ENTRIES}" != x1 ]; then
exit 0
fi

# get major version, e.g. "4.8" for "linux4.8"
major_version=$(echo $PKGNAME | cut -c 6-)

# get hex number of the matching entry
hexnum=$(efibootmgr | grep "Debian-${PKGNAME}" | cut -c "5-8")

# delete it
echo "[ "$hexnum" ] && efibootmgr -Bq -b $hexnum"
[ "$hexnum" ] && efibootmgr -Bq -b $hexnum

Place this script in /etc/kernel/postrm.d, I named mine zz-crypt. Ensure you make it executable!


Users, groups and locales

On a minimal install of debian, there is no implimentation of priv esc tools such as sudo. We can use doas in it’s stead. Additionally, we must create the proper groups and set up the locale.

Adding a User

Let’s add a basic user which we’ll add to the wheel group later

useradd -m eternal

doas installation

sudo apt install doas

doas, by default, installs no new groups, or default permissions. let’s configure that

doas configuration

Here’s an example of my /etc/doas.conf file. In my experience, for some tools when invoked inside of certain shells, it will only accept the absolute path of the binary; hence the seemingly duplicated lines.

This will allow the user “eternal” to run certain commands as root without a password, such as brightnessctl and wg-quick. The first line instructs it to permit all members of the wheel group root upon entry of a password, and to persist for some time.

permit keepenv persist :wheel
permit keepenv nopass eternal cmd /bin/lsblk
permit keepenv nopass eternal cmd /usr/bin/lsblk
permit keepenv nopass eternal as root cmd lsblk
permit keepenv nopass eternal as root cmd wg
permit keepenv nopass eternal as root cmd wg-quick
permit keepenv nopass eternal cmd /bin/brightnessctl
permit keepenv nopass eternal cmd /usr/bin/brightnessctl
permit keepenv nopass eternal as root cmd brightnessctl

Adding Wheel

Now that we’ve told doas to allow the :wheel group, we must add our user to the wheel group.

usermod -a -G wheel eternal

Changing root / user passwords

It’s generally a good idea to have a root password as a fallback

passwd root 
passwd eternal

Setting locale

We’ll set the timezone like we’d normally do,

ln -sf /usr/share/zoneinfo/America/Chicago /etc/localtime

Now, for the locale, we must install locales

apt install locales
dpkg-reconfigure locales