Skip to content

Instantly share code, notes, and snippets.

@hashbrowncipher
Last active December 30, 2017 12:01
Show Gist options
  • Save hashbrowncipher/1dae932af83b58b51655a88ddad0ee4a to your computer and use it in GitHub Desktop.
Save hashbrowncipher/1dae932af83b58b51655a88ddad0ee4a to your computer and use it in GitHub Desktop.
An imager based on s3gof3r, for reimaging EC2 nodes without losing their instance store
#!/bin/bash
set -x
set -o errexit
set -o nounset
set -o pipefail
#------- end of header (relevant for root/kernel.sh, below)
readonly INITRD_DIR=initrd
readonly SSH_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIyK5qcNzv65trF8pdiLZbnBS6NLJqiHhGSQo6veOswH"
readonly KERNEL_VERSION="4.13.0-21-generic"
readonly SCRIPT_LOCATION="$(readlink -f "${BASH_SOURCE}")"
base() {
cp -a ../"${INITRD_DIR}.bak" "${INITRD_DIR}" ||
debootstrap \
--include "openssh-server less vim-tiny iproute2 kmod udev ca-certificates" \
--variant=minbase \
xenial "${INITRD_DIR}"
cd "${INITRD_DIR}"
cat << EOF > etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu xenial main universe
deb http://archive.ubuntu.com/ubuntu xenial-security main universe
EOF
head -n6 "${SCRIPT_LOCATION}" > root/kernel.sh
cat >> root/kernel.sh <<EOF
cd /root
apt update
apt install liblz4-tool
apt download "linux-image-${KERNEL_VERSION}"
dpkg -x *.deb /
depmod "${KERNEL_VERSION}"
systemctl enable systemd-networkd.service
systemctl enable systemd-resolved.service
systemctl enable systemd-networkd-wait-online.service
sed -ie 's/^root:\*:/root::/' /etc/shadow
EOF
chmod +x root/kernel.sh
chroot . /root/kernel.sh
cp boot/vmlinuz* ../vmlinuz
cat <<EOF > etc/systemd/network/all.network
[Network]
DHCP=yes
EOF
mkdir root/.ssh
echo "${SSH_KEY}" > root/.ssh/authorized_keys
cat <<EOF > etc/systemd/system/generate_ssh_keys.service
[Unit]
Description=Generate SSH keys
Before=ssh.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/generate_ssh_host_keys
EOF
cat <<EOF > etc/systemd/system/install_from_s3.service
[Unit]
Description=Install an image from S3
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/install_from_s3
Restart=always
RestartSec=60
StandardOutput=journal+console
EOF
ln -s "/etc/systemd/system/install_from_s3.service" "etc/systemd/system/multi-user.target.wants"
ln -s "/etc/systemd/system/generate_ssh_keys.service" "etc/systemd/system/multi-user.target.wants"
cat <<EOF > usr/local/bin/generate_ssh_host_keys
#!/bin/bash
ssh-keygen -q -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa
ssh-keygen -q -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa
ssh-keygen -q -f /etc/ssh/ssh_host_ecdsa_key -N '' -t ecdsa
ssh-keygen -q -f /etc/ssh/ssh_host_ed25519_key -N '' -t ed25519
EOF
chmod +x usr/local/bin/generate_ssh_host_keys
ln -sf /run/systemd/resolve/resolv.conf etc/resolv.conf
rm -rf -- \
boot/vmlinuz* \
etc/ssh/ssh_host_*_key* \
etc/hostname \
root/* \
usr/share/doc \
usr/share/i18n \
usr/share/locale \
var/cache/apt \
var/lib/dpkg/info \
var/lib/apt \
var/log
cat "${SCRIPT_LOCATION}" > root/build.sh
chmod +x root/build.sh
mkdir var/lib/dpkg/info
cd ..
}
installer() {
GOF3R_FILENAME="gof3r_0.5.0_linux_amd64.tar.gz"
curl -LO "https://github.com/rlmcpherson/s3gof3r/releases/download/v0.5.0/${GOF3R_FILENAME}"
echo "d88f199d1580d8c8cac26ba39e15dc6e2126d20e56c3894bd37a226e8b3e665c ${GOF3R_FILENAME}" | sha256sum -c
cd "${INITRD_DIR}"
ln -s /sbin/init init
tar -C usr/bin --strip-components=1 -xzvf "../${GOF3R_FILENAME}"
rm "../${GOF3R_FILENAME}"
cat > usr/local/bin/install_from_s3 <<"EOF"
#!/bin/bash -x
set -o errexit
set -o nounset
set -o pipefail
read -a cmdline < /proc/cmdline
for arg in "${cmdline[@]}"; do
case "${arg}" in
root=UUID=*)
root="/dev/disk/by-uuid/${arg#root=UUID=}"
;;
root=*)
root="${arg#root=}"
;;
source=*)
IFS=/ read -r bucket key <<< "${arg#source=}"
;;
esac
done
echo "Bucket: ${bucket}"
echo "Key: ${key}"
echo "Root: ${root}"
gof3r get -b "${bucket}" -k "${key}" | lz4 -d > "${root}"
exec reboot -f
EOF
chmod +x usr/local/bin/install_from_s3
find . -print0 | cpio -o -H newc -R 0:0 --null | gzip > ../initrd.gz
cd ..
rm -r "${INITRD_DIR}"
}
local_bootloader() {
read -a cmdline < /proc/cmdline
new_cmdline=()
for arg in "${cmdline[@]}"; do
case "${arg}" in
root=*)
new_cmdline+=("${arg}")
;;
esac
done
new_cmdline+=("$@")
mkdir grub
cat <<EOF > grub/grub.cfg
linux /boot/vmlinuz ${new_cmdline[@]}
initrd /boot/initrd.gz
boot
EOF
}
image_bootloader() {
truncate -s100m image
mkfs.ext4 image
mkdir rootfs
loopdev="$(losetup --show -f image)"
uuid="$(blkid -s UUID -o value "${loopdev}")"
mount "${loopdev}" rootfs
mkdir rootfs/boot
cp vmlinuz initrd.gz rootfs/boot
grub-install --boot-directory rootfs/boot --force "${loopdev}"
cat <<EOF > rootfs/boot/grub/grub.cfg
linux /boot/vmlinuz root=UUID=$uuid $@
initrd /boot/initrd.gz
boot
EOF
umount rootfs
rm -r rootfs
losetup -d "${loopdev}"
}
while ! DEBIAN_FRONTEND=noninteractive apt install -y debootstrap liblz4-tool curl cpio grub-pc; do
apt update
# don't loop multiple times
[ -z "${i:-}" ] && i=1
done
rm -rf build
mkdir build
cd build
base
installer
local_bootloader "$@"
image_bootloader "$@"
lz4 image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment