Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save shizmob/3b8538f4da1406be077ad13b5f656a58 to your computer and use it in GitHub Desktop.
Save shizmob/3b8538f4da1406be077ad13b5f656a58 to your computer and use it in GitHub Desktop.
Installing Alpine with LUKS and ZFS from just a rescue environment
#!/bin/sh
set -e
# configuration
alpinever=3.15
apkver=2.12.7-r3
# curl -sL "http://dl-cdn.alpinelinux.org/alpine/v$alpinever/main/$apkarch/apk-tools-static-$apkver.apk" | sha256sum
apkdigest=8fcd7b71dc1415ea23902e55b53db3d738f3a2cce50195ef804ba177d9b591a8
alpinekeysver=2.4-r1
# curl -sL "http://dl-cdn.alpinelinux.org/alpine/v$alpinever/main/$apkarch/alpine-keys-$alpinekeysver.apk" | sha256sum
alpinekeysdigest=61092b6b26802ece6296f592d7754f0205800e5c735bc61a0e21613dc101369d
apkarch=x86_64
tempmnt=/mnt
# prepare kernel modules, this may need tweaking based on your particular rescue environment
if ! dpkg-query -l zfs-dkms | grep -q '^ii'; then
apt update
apt install zfs-dkms/bullseye-backports
hash -r
fi
# build setup environment
mkdir -p "$tempmnt"/alpine
if ! test -f "$tempmnt"/sbin/setup-alpine; then
if ! test -f ./sbin/apk.static; then
curl -o apk.apk -L "http://dl-cdn.alpinelinux.org/alpine/v$alpinever/main/$apkarch/apk-tools-static-$apkver.apk"
echo "$apkdigest apk.apk" | sha256sum -c
tar -xzf apk.apk
fi
if ! test -d ./etc/apk/keys; then
curl -o alpine-keys.apk -L "http://dl-cdn.alpinelinux.org/alpine/v$alpinever/main/$apkarch/alpine-keys-$alpinekeysver.apk"
echo "$alpinekeysdigest alpine-keys.apk" | sha256sum -c
tar -xzf alpine-keys.apk
fi
./sbin/apk.static \
--arch "$apkarch" \
--root "$tempmnt" \
--keys-dir "$(realpath --relative-to "$tempmnt" ./etc/apk/keys)" \
-U -X "http://dl-cdn.alpinelinux.org/alpine/v$alpinever/main" \
add --initdb \
alpine-base alpine-conf
fi
# prepare setup environment
if ! mount | grep -q "$tempmnt"/dev; then
mount --rbind /dev "$tempmnt"/dev
fi
if ! mount | grep -q "$tempmnt"/proc; then
mount -t proc none "$tempmnt"/proc
fi
if ! mount | grep -q "$tempmnt"/sys; then
mount -t sysfs none "$tempmnt"/sys
fi
if ! mount | grep -q "$tempmnt"/tmp; then
mount -t tmpfs none "$tempmnt"/tmp
fi
cp -L /etc/resolv.conf "$tempmnt"/etc
mkdir -p "$tempmnt"/lib/modules
cp -R /lib/modules/"$(uname -r)" "$tempmnt"/lib/modules
# fix up essential services, normally done by initramfs
for svc in devfs hwdrivers procfs sysfs; do
chroot "$tempmnt" rc-update add "$svc" sysinit
done
for svc in bootmisc fsck modules sysctl urandom; do
chroot "$tempmnt" rc-update add "$svc" boot
done
for svc in killprocs mount-ro; do
chroot "$tempmnt" rc-update add "$svc" shutdown
done
# do the evolution
cp "$1" "$tempmnt"/tmp/init
chmod +x "$tempmnt"/tmp/init
exec chroot "$tempmnt" /tmp/init
#!/bin/sh
set -e
# configuration, change me!
hostname=strata
netaddr=162.55.237.210/26
netgw=162.55.237.193
zfsvol=umi
kernflavour=lts
disks='/dev/sda /dev/sdb /dev/sdc /dev/sdd'
bootmodules='af_packet ipv6 zfs sd-mod usbhid dm_crypt xhci_hcd ahci ccp igb'
# dropbear doesn't support ed25519 keys
bootkey='ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBADwJtijDYN7xm9cxy44SgXo+dx91R542K5Anq1X+ifEJHIfcL3hdU6AjBdbWviWiGmYoCV3TdwEuQVsLOB1xggw3QGkifF2d6h+QX92G3Cfx2XDWctDM7poSli6eB29dACEkDBMcTNwHdoiQBaESr/yPR1gWcscJ0b6ExiKV/JSWfojgg== [email protected]'
initramfsrev=04e6c3c3b16a01ba9807cb566f93fa31f2fb23a8
bootdisk="${disks%% *}"
bootdev="${bootdisk}1"
encdevs=
for disk in $disks; do
encdevs="$encdevs ${disk}2"
done
luks_type="CA7D7CCB-63ED-4C53-861C-1742536059CC"
tempmnt=/mnt
# bootstrap necessary packages
setup-apkrepos -1
apk add --virtual .disk-deps cryptsetup zfs sfdisk e2fsprogs
# setup disks
if ! zpool list "$zfsvol" >/dev/null 2>/dev/null; then
# setup disk
for disk in $disks; do
sfdisk -q --wipe always --wipe-partitions always $disk <<EOF
label: gpt
sector-size: 4096
grain: 4096
name=boot, size=100MiB, type=linux, attrs="LegacyBIOSBootable"
name=root, size=31251552216, type=$luks_type
EOF
done
zfsdevs=
i=0
for dev in $encdevs; do
cryptsetup luksFormat -q \
--type=luks2 \
--sector-size=4096 \
--cipher=aes-xts-plain64 \
--pbkdf=argon2id \
--iter-time=5000 \
--integrity=none \
"$dev"
cryptsetup luksOpen "$dev" $zfsvol$i
zfsdevs="$zfsdevs /dev/mapper/$zfsvol$i"
i=$((i+1))
done
# setup boot
mkfs.ext2 -q -F -L boot -m 0 "$bootdev"
# setup pool
zpool create -f \
-m none -R "$tempmnt" \
-o ashift=12 \
-O compression=lz4 \
-O atime=off \
-O redundant_metadata=most \
-O devices=off \
-O encryption=off \
-O xattr=sa \
"$zfsvol" raidz1 $zfsdevs
fi
# setup volumes
if ! zfs list "$zfsvol"/da >/dev/null 2>/dev/null; then
zfs create \
-o canmount=noauto \
-o mountpoint=/ \
-o atime=off \
-o acltype=posix \
"$zfsvol"/da
zfs create \
-o canmount=noauto \
-o mountpoint=/store \
-o atime=off \
-o exec=off \
"$zfsvol"/storage
zfs create \
-o canmount=noauto \
-o mountpoint=/home \
-o atime=off \
"$zfsvol"/storage/home
fi
# mount volumes
if ! mount | grep -q "$tempmnt"; then
zfs mount umi/da
fi
mkdir -p "$tempmnt"/boot
if ! mount | grep -q "$tempmnt"/boot; then
mount -t ext2 "$bootdev" "$tempmnt"/boot
fi
apk del .disk-deps
# install Alpine
rootdevs=
for dev in $encdevs; do
rootdevs="$rootdevs${rootdevs:+:}UUID=$(blkid "$dev" | grep -Eo ' UUID="[^"]+"' | cut -d'"' -f2)"
done
cmdline="quiet rootfstype=zfs rootflags=noatime zfs luks binit_net_if=eth0 binit_net_addr=$netaddr binit_net_gw=$netgw sshd sshd_port=422 enc_root=$rootdevs"
if ! test -f "$tempmnt"/sbin/apk; then
cat > /tmp/answers <<EOF
KEYMAPOPTS="us us"
HOSTNAMEOPTS="-n $hostname"
INTERFACESOPTS="auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address ${netaddr%%/*}
netmask 255.255.255.0
gateway $netgw
"
DNSOPTS="-d $hostname 9.9.9.9"
TIMEZONEOPTS="-z UTC"
APKREPOSOPTS="-f"
SSHDOPTS="-c openssh"
NTPOPTS="-c busybox"
PROXYOPTS="none"
DISKOPTS="-k $kernflavour $tempmnt"
BOOTLOADER=syslinux
DISKLABEL=gpt
KERNELOPTS="$cmdline"
LBUOPTS="none"
APKCACHEOPTS="/var/cache/apk"
EOF
setup-alpine -f /tmp/answers
rm -f /tmp/answers
fi
# finish up the install
chroot "$tempmnt" /bin/sh <<EOF
#!/bin/sh
set -e
apk add zfs-$kernflavour
# build unlocking initramfs
for mod in $bootmodules; do
if ! grep -q "^\$mod\\\$" /etc/modules; then
echo "\$mod" >> /etc/modules
fi
done
mkdir -p /usr/src
if ! test -d /usr/src/newer-initramfs; then
apk add --virtual .newer-initramfs-deps git
cd /usr/src
git clone https://weeaboo.software/Shiz/newer-initramfs
cd newer-initramfs
git checkout "$initramfsrev"
fi
if ! test -f /boot/newer-initramfs.img.gz; then
apk add --virtual .newer-initramfs-deps build-base linux-headers
cd /usr/src/newer-initramfs
echo "$bootkey" > secrets/authorized_keys
./mkbase.sh /boot/newer-initramfs.img.gz
fi
if ! test -f /boot/newer-modules.img.gz; then
cd /usr/src/newer-initramfs
kernver="\$(apk info -L linux-$kernflavour | grep '^lib/modules/' | cut -d/ -f3 | uniq)"
./mkmod.sh /boot/newer-modules.img.gz "\$kernver"
fi
if apk info -e .newer-initramfs-deps; then
apk del .newer-initramfs-deps
fi
# setup unlocking initramfs to replace default
if ! grep -q 'disable_trigger=true' /etc/mkinitfs/mkinitfs.conf; then
echo "disable_trigger=true" >> /etc/mkinitfs/mkinitfs.conf
fi
cat /boot/newer-initramfs.img.gz /boot/newer-modules.img.gz > /boot/initramfs-"$kernflavour"
if ! grep -q "$cmdline" /etc/update-extlinux.conf; then
sed -i -e 's/^default_kernel_opts=.*/default_kernel_opts="'"$cmdline"'"/g' /etc/update-extlinux.conf
fi
update-extlinux
# setup access to system post-boot
if ! test -f /root/.ssh/authorized_keys; then
mkdir -p /root/.ssh
echo "$bootkey" > /root/.ssh/authorized_keys
fi
EOF
# finally, fix bootloader
dd bs=440 conv=notrunc count=1 if="$tempmnt"/usr/share/syslinux/gptmbr.bin of="$bootdisk"
  1. Boot your server into a rescue environment;
  2. Download both scripts to a root shell and edit their configuration section to match yours;
  3. Run ./enter-alpine.sh install-alpine.sh;
  4. If all goes well, reboot, wait for the network to come up and ssh -p 422 <server-ip>;
  5. You can now remote unlock the server by running unlock-luks once per disk; if successful, the boot shell will exit and the server will continue the boot sequence.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment