Skip to content

Instantly share code, notes, and snippets.

@amimof
Created May 24, 2024 12:33
Show Gist options
  • Save amimof/f7ad75d5c2c06e5268f1d9a729866a21 to your computer and use it in GitHub Desktop.
Save amimof/f7ad75d5c2c06e5268f1d9a729866a21 to your computer and use it in GitHub Desktop.
#
# A step-by-step gist that can be used to install Debian 12 (bookworm) on a ZFS mirror.
# This is intended to be used as guide and not as a script, all thought it could be with some modifications.
#
# - ZFS native encryption with passphrase.
# - Installs ZFSBootLoader with remote access using Dracut & Dropbear.
# - Requires at least 3 disks. 1 boot disk and 2 for the ZFS mirror pool. Make sure to update the disk vars further down.
#
# Inspiration:
# https://docs.zfsbootmenu.org/en/v2.3.x/general/remote-access.html
# https://docs.zfsbootmenu.org/en/v2.3.x/guides/debian/bookworm-uefi.html
# https://github.com/Sithuk/ubuntu-server-zfsbootmenu/blob/main/ubuntu_server_encrypted_root_zfs.sh#L1406
# https://github.com/prabirshrestha/simple-ubuntu-installer/blob/main/simple-ubuntu-installer
#
# Setup live environment
apt install openssh-server
useradd -g users -G sudo -m --shell /usr/bin/bash amimof
passwd amimof
source /etc/os-release
export ID
# Install required packages
cat <<EOF > /etc/apt/sources.list
deb http://deb.debian.org/debian bookworm main contrib
deb-src http://deb.debian.org/debian bookworm main contrib
EOF
apt update
apt install -y debootstrap gdisk dkms linux-headers-$(uname -r)
apt install -y zfsutils-linux
# Generate hostid
zgenhostid -f 0x00bab10c
# Disk vars for convenience. These may change so be careful!
export BOOT_DISK1="/dev/sda"
export BOOT_PART1="1"
export BOOT_DEVICE1="${BOOT_DISK1}${BOOT_PART1}"
export POOL_DISK1="/dev/sdb"
export POOL_PART1="1"
export POOL_DEVICE1="${POOL_DISK1}${POOL_PART1}"
export POOL_DISK2="/dev/sdc"
export POOL_PART2="1"
export POOL_DEVICE2="${POOL_DISK2}${POOL_PART2}"
# Set your SSH public key used to access ZFS Boot Menu in order to unlock disks
export SSH_PUBLIC_KEY=""
# Encryption key
export ZFS_SECRET_KEY="secretkey"
# Wipe partitions
zpool labelclear -f "$POOL_DISK1"
zpool labelclear -f "$POOL_DISK2"
wipefs -a "$POOL_DISK1"
wipefs -a "$POOL_DISK2"
wipefs -a "$BOOT_DISK1"
sgdisk --zap-all "$POOL_DISK1"
sgdisk --zap-all "$POOL_DISK2"
sgdisk --zap-all "$BOOT_DISK1"
# Create EFI boot and zpool partitions
sgdisk -n "${BOOT_PART1}:1m:+512m" -t "${BOOT_PART1}:ef00" "$BOOT_DISK1"
sgdisk -n "${POOL_PART1}:0:-10m" -t "${POOL_PART1}:bf00" "$POOL_DISK1"
sgdisk -n "${POOL_PART2}:0:-10m" -t "${POOL_PART2}:bf00" "$POOL_DISK2"
# Create zfs mirror pool with encryption
echo "${ZFS_SECRET_KEY}" > /etc/zfs/zroot.key
chmod 000 /etc/zfs/zroot.key
zpool create -f -o ashift=12 \
-O compression=lz4 \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-O encryption=aes-256-gcm \
-O keylocation=file:///etc/zfs/zroot.key \
-O keyformat=passphrase \
-o autotrim=on \
-m none zroot "$POOL_DEVICE1"
# Create file system and mount dataset to /mnt
zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/${ID}
zpool set bootfs=zroot/ROOT/${ID} zroot
zpool export zroot
zpool import -N -R /mnt zroot
zfs load-key -L prompt zroot
zfs mount zroot/ROOT/${ID}
udevadm trigger
# Install Debian
debootstrap bookworm /mnt
# Copy files into intall and chroot into /mnt
cp /etc/hostid /mnt/etc/hostid
cp /etc/resolv.conf /mnt/etc/
mkdir /mnt/etc/zfs
cp /etc/zfs/zroot.key /mnt/etc/zfs
mount -t proc proc /mnt/proc
mount -t sysfs sys /mnt/sys
mount -B /dev /mnt/dev
mount -t devpts pts /mnt/dev/pts
chroot /mnt /bin/bash
#### REMINDER! From now on, you are chrooted in /mnt! ####
# Set hostname
echo 'amir-lab' > /etc/hostname
echo -e '127.0.1.1\tamir-lab' >> /etc/hosts
# Apt sources
cat <<EOF > /etc/apt/sources.list
deb http://deb.debian.org/debian bookworm main contrib
deb-src http://deb.debian.org/debian bookworm main contrib
deb http://deb.debian.org/debian-security bookworm-security main contrib
deb-src http://deb.debian.org/debian-security/ bookworm-security main contrib
deb http://deb.debian.org/debian bookworm-updates main contrib
deb-src http://deb.debian.org/debian bookworm-updates main contrib
deb http://deb.debian.org/debian bookworm-backports main contrib
deb-src http://deb.debian.org/debian bookworm-backports main contrib
EOF
apt update
# Packages
apt install -y locales openssh-server net-tools tzdata vim curl
# Locale and timezone
ln -sf /usr/share/zoneinfo/Europe/Stockholm /etc/localtime
dpkg-reconfigure tzdata -f noninteractive
vim locale.gen
locale-gen
cat > /etc/default/locale <<-EOF
LANGUAGE="en_US.UTF-8"
LC_ALL="en_US.UTF-8"
EOF
export LANGUAGE="en_US.UTF-8"
export LC_ALL="en_US.UTF-8"
# User account
passwd root
useradd -g users -G sudo -m -s /usr/bin/bash amimof
passwd amimof
# Networking
cat > /etc/network/interfaces.d/ens192 <<-EOF
auto ens192
allow-hotplug ens192
iface ens192 inet dhcp
EOF
#systemctl enable networking
# Install ZFS
apt install linux-headers-amd64 linux-image-amd64 zfs-initramfs dosfstools
apt install zfsutils-linux zfs-zed
echo "REMAKE_INITRD=yes" > /etc/dkms/zfs.conf
systemctl enable zfs.target
systemctl enable zfs-import-cache
systemctl enable zfs-mount
systemctl enable zfs-import.target
echo "UMASK=0077" > /etc/initramfs-tools/conf.d/umask.conf
# Install ZBM
apt-get install --yes bsdextrautils mbuffer
apt-get install --yes --no-install-recommends libsort-versions-perl libboolean-perl libyaml-pp-perl git fzf make kexec-tools dracut-core cryptsetup
mkdir /tmp/zfsbootmenu
cd /tmp/zfsbootmenu
git clone https://github.com/zbm-dev/zfsbootmenu
make core dracut
# Configure SSH
apt install -y dracut-network dropbear
git -C /tmp clone 'https://github.com/dracut-crypt-ssh/dracut-crypt-ssh.git'
mkdir /usr/lib/dracut/modules.d/60crypt-ssh
cp /tmp/dracut-crypt-ssh/modules/60crypt-ssh/* /usr/lib/dracut/modules.d/60crypt-ssh/
rm /usr/lib/dracut/modules.d/60crypt-ssh/Makefile
sed -i \
-e 's, inst "\$moddir"/helper/console_auth /bin/console_auth, #inst "\$moddir"/helper/console_auth /bin/console_auth,' \
-e 's, inst "\$moddir"/helper/console_peek.sh /bin/console_peek, #inst "\$moddir"/helper/console_peek.sh /bin/console_peek,' \
-e 's, inst "\$moddir"/helper/unlock /bin/unlock, #inst "\$moddir"/helper/unlock /bin/unlock,' \
-e 's, inst "\$moddir"/helper/unlock-reap-success.sh /sbin/unlock-reap-success, #inst "\$moddir"/helper/unlock-reap-success.sh /sbin/unlock-reap-success,' \
/usr/lib/dracut/modules.d/60crypt-ssh/module-setup.sh
mkdir -p /etc/cmdline.d
echo "ip=dhcp rd.neednet=1" > /etc/cmdline.d/dracut-network.conf
mkdir -p /etc/dropbear
for keytype in rsa ecdsa ed25519; do
ssh-keygen -t "${keytype}" -m PEM -f "/etc/dropbear/ssh_host_${keytype}_key" -N ""
done
echo "${SSH_PUBLIC_KEY}" > /root/.ssh/authorized_keys
cat <<-EOF >/etc/zfsbootmenu/dracut.conf.d/dropbear.conf
add_dracutmodules+=" crypt-ssh network-legacy "
install_optional_items+=" /etc/cmdline.d/dracut-network.conf "
## Copy system keys for consistent access
dropbear_rsa_key="/etc/dropbear/ssh_host_rsa_key"
dropbear_ecdsa_key="/etc/dropbear/ssh_host_ecdsa_key"
dropbear_ed25519_key="/etc/dropbear/ssh_host_ed25519_key"
EOF
systemctl stop dropbear
systemctl disable dropbear
# Generate images
update-initramfs -c -k all
generate-zbm --debug
# Set ZBM properties
zfs set org.zfsbootmenu:commandline="quiet" zroot/ROOT
zfs set org.zfsbootmenu:keysource="zroot/ROOT/${ID}" zroot
mkfs.vfat -F32 "$BOOT_DEVICE1"
cat << EOF >> /etc/fstab
$( blkid | grep "$BOOT_DEVICE" | cut -d ' ' -f 2 ) /boot/efi vfat defaults 0 0
EOF
mkdir -p /boot/efi/EFI/ZBM
curl -o /boot/efi/EFI/ZBM/VMLINUZ.EFI -L https://get.zfsbootmenu.org/efi
cp /boot/efi/EFI/ZBM/VMLINUZ.EFI /boot/efi/EFI/ZBM/VMLINUZ-BACKUP.EFI
# Configure boot entries
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
efibootmgr -c -d "$BOOT_DISK1" -p "$BOOT_PART1" \
-L "ZFSBootMenu (Backup)" \
-l '\EFI\ZBM\VMLINUZ-BACKUP.EFI'
efibootmgr -c -d "$BOOT_DISK1" -p "$BOOT_PART1" \
-L "ZFSBootMenu" \
-l '\EFI\ZBM\VMLINUZ.EFI'
# Generate ZBM images with SSH. Replace filenames with those generated by generate-zbm
generate-zbm --debug
efibootmgr --disk "$BOOT_DISK1" \
--part "$BOOT_PART1" \
--create \
--label "ZFSBootMenu (SSH)" \
--loader '\EFI\ZBM\vmlinuz-2.3.0' \
--unicode 'zbm.prefer=zroot ro initrd=\EFI\ZBM\initramfs-2.3.0.img quiet'
# First boot
exit
umount -n -R /mnt
zpool export zroot
reboot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment