- Boot your server into a rescue environment;
- Download both scripts to a root shell and edit their configuration section to match yours;
- Run
./enter-alpine.sh install-alpine.sh
; - If all goes well, reboot, wait for the network to come up and
ssh -p 422 <server-ip>
; - 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.
Last active
April 4, 2022 13:03
-
-
Save shizmob/3b8538f4da1406be077ad13b5f656a58 to your computer and use it in GitHub Desktop.
Installing Alpine with LUKS and ZFS from just a rescue environment
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
#!/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 |
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
#!/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" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment