Instantly share code, notes, and snippets.
Created
May 24, 2024 12:33
-
Star
1
(1)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save amimof/f7ad75d5c2c06e5268f1d9a729866a21 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 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