Last active
October 21, 2019 15:21
-
-
Save egeneralov/c4e152bd96de81a7584aa0e2c189c074 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
| #!/bin/bash -xe | |
| # Disk wipe | |
| sgdisk --zap-all ${DEV:-/dev/sda} | |
| # Disk partitioning | |
| sgdisk -og ${DEV:-/dev/sda} | |
| sgdisk -n 1:2048:+128M -t 1:fd00 ${DEV:-/dev/sda} | |
| sgdisk -n 128:-3M:0 -t 128:ef02 ${DEV:-/dev/sda} | |
| sgdisk -n 2:0:0 -t 2:fd00 ${DEV:-/dev/sda} | |
| # kernel reload disk partitions | |
| partprobe ${DEV:-/dev/sda} | |
| sleep 2 | |
| # create crypt partition | |
| echo -n ${PASSWD:-ok} | cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 luksFormat ${DEV:-/dev/sda}2 - | |
| # unlock crypt partition | |
| echo -n ${PASSWD:-ok} | cryptsetup luksOpen ${DEV:-/dev/sda}2 rootfs - | |
| # format /boot/ | |
| yes | mkfs.ext2 -L boot -I 128 ${DEV:-/dev/sda}1 | |
| # format / | |
| mkfs.ext4 /dev/mapper/rootfs | |
| # mount | |
| mount /dev/mapper/rootfs /mnt/ | |
| mkdir -p /mnt/boot | |
| mount ${DEV:-/dev/sda}1 /mnt/boot | |
| # cleanup | |
| rm -rf /mnt/{boot/,}lost+found | |
| # system installation | |
| debootstrap \ | |
| --include=linux-base,linux-image-amd64,linux-headers-amd64,grub-pc,cryptsetup,initramfs-tools,mdadm,openssh-server,busybox,dropbear-initramfs,locales,locales,kbd,netmask,console-setup,netmask,kmod,ssh-askpass,lvm2 \ | |
| --arch=amd64 \ | |
| --no-check-certificate \ | |
| --no-check-gpg \ | |
| ${DIST:-buster} \ | |
| /mnt \ | |
| http://deb.debian.org/debian | |
| # configure | |
| echo "rootfs UUID=$(blkid -s UUID -o value ${DEV:-/dev/sda}2) none luks" > /mnt/etc/crypttab | |
| cat > /mnt/etc/fstab << EOF | |
| proc /proc proc defaults 0 0 | |
| UUID=$(blkid -s UUID -o value ${DEV:-/dev/sda}1) /boot ext2 defaults 0 0 | |
| UUID=$(blkid -s UUID -o value /dev/mapper/rootfs) / ext4 defaults 0 1 | |
| EOF | |
| # prepare to chroot | |
| mount -o bind /dev /mnt/dev | |
| mount -t sysfs /sys /mnt/sys | |
| mount -t proc /proc /mnt/proc | |
| # mtab | |
| cp /proc/mounts /mnt/etc/mtab | |
| # configure | |
| echo "nameserver 8.8.8.8" > /mnt/etc/resolv.conf | |
| echo "${HOSTNAME:-$(hostname)}" > /mnt/etc/hostname | |
| # security updates | |
| echo "deb http://security.debian.org/ ${DIST:-buster}/updates main" >> /mnt/etc/apt/sources.list | |
| chroot /mnt apt-get update -q | |
| chroot /mnt apt-get upgrade -qy | |
| chroot /mnt apt-get clean -yq | |
| # ssh access | |
| mkdir -p /mnt/root/.ssh/ | |
| echo "$(cat ~/.ssh/authorized_keys | head -n 1)" > /mnt/root/.ssh/authorized_keys | |
| chmod 700 /mnt/root/.ssh/ | |
| chmod 600 /mnt/root/.ssh/authorized_keys | |
| # networking | |
| cat << EOF > /mnt/etc/systemd/network/wired.network | |
| [Match] | |
| Name=e* | |
| [Network] | |
| DHCP=ipv4 | |
| EOF | |
| chroot /mnt systemctl enable systemd-networkd | |
| chroot /mnt systemctl enable systemd-resolved | |
| rm /mnt/etc/resolv.conf | |
| chroot /mnt ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf | |
| # hcloud patch | |
| [ -f /mnt/usr/share/initramfs-tools/scripts/functions.orig ] || cp /mnt/usr/share/initramfs-tools/scripts/functions{,.orig} | |
| wget https://gist.githubusercontent.com/egeneralov/c4e152bd96de81a7584aa0e2c189c074/raw/f5d62ab15389a134deced426e7895d999aa4cbb7/functions -O /mnt/usr/share/initramfs-tools/scripts/functions | |
| # dropbear | |
| sed -i "s/^#CRYPTSETUP=$/CRYPTSETUP=y/" /mnt/etc/cryptsetup-initramfs/conf-hook | |
| echo "no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command=\"/bin/cryptroot-unlock\" $(cat ~/.ssh/authorized_keys | head -n 1)" > /mnt/etc/dropbear-initramfs/authorized_keys | |
| sed -i "s/^#DROPBEAR_OPTIONS=$/DROPBEAR_OPTIONS=\"-p 22 -s -j -k -I 60\"/" /mnt/etc/dropbear-initramfs/config | |
| chroot /mnt update-initramfs -u -k all | |
| echo "GRUB_CMDLINE_LINUX_DEFAULT=\"ip=dhcp\"" >> /mnt/etc/default/grub | |
| # grub | |
| chroot /mnt grub-install ${DEV:-/dev/sda} | |
| chroot /mnt update-grub | |
| # locales | |
| sed -i 's/.*en_US.UTF-8 UTF-8.*/en_US.UTF-8 UTF-8/g' /mnt/etc/locale.gen | |
| chroot /mnt locale-gen | |
| echo "LC_ALL=en_US.UTF-8" > /mnt/etc/environment | |
| echo "" > /mnt/etc/motd | |
| # stop journald -> syslog spam (: | |
| cat << EOF > /mnt/etc/systemd/journald.conf | |
| [Journal] | |
| Storage=auto | |
| ForwardToSyslog=no | |
| ForwardToKMsg=no | |
| ForwardToConsole=no | |
| ForwardToWall=no | |
| EOF | |
| # clear unmount all | |
| mount | grep mnt | awk '{print $3}' | tac | xargs -n 1 umount | |
| cryptsetup luksClose rootfs | |
| # write to disk | |
| sync |
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
| # -*- shell-script -*- | |
| _log_msg() | |
| { | |
| if [ "$quiet" = "y" ]; then return; fi | |
| printf "$@" | |
| } | |
| log_success_msg() | |
| { | |
| _log_msg "Success: $@\n" | |
| } | |
| log_failure_msg() | |
| { | |
| _log_msg "Failure: $@\n" | |
| } | |
| log_warning_msg() | |
| { | |
| _log_msg "Warning: $@\n" | |
| } | |
| log_begin_msg() | |
| { | |
| _log_msg "Begin: $@ ... " | |
| } | |
| log_end_msg() | |
| { | |
| _log_msg "done.\n" | |
| } | |
| panic() | |
| { | |
| local console rest | |
| if command -v chvt >/dev/null 2>&1; then | |
| chvt 1 | |
| fi | |
| echo "$@" | |
| # Disallow console access | |
| if [ -n "${panic}" ]; then | |
| echo "Rebooting automatically due to panic= boot argument" | |
| sleep ${panic} | |
| reboot | |
| exit # in case reboot fails, force kernel panic | |
| fi | |
| run_scripts /scripts/panic | |
| # Try to use setsid, which will enable job control in the shell | |
| # and paging in more | |
| if command -v setsid >/dev/null 2>&1; then | |
| read console rest </proc/consoles | |
| if [ "${console}" = "tty0" ]; then | |
| # Need to choose a specific VT | |
| console="tty1" | |
| fi | |
| # We don't have 'setsid -c' so we need to setsid, open | |
| # the tty, and finally exec an interactive shell | |
| REASON="$@" PS1='(initramfs) ' setsid sh -c "exec sh -i <>/dev/${console} 1>&0 2>&1" | |
| else | |
| REASON="$@" PS1='(initramfs) ' sh -i </dev/console >/dev/console 2>&1 | |
| fi | |
| } | |
| maybe_break() | |
| { | |
| case ",$break," in | |
| *,$1,*) | |
| if [ "$1" = "top" ]; then | |
| # udev is not yet running, so load keyboard drivers | |
| if [ "${quiet}" = "y" ]; then | |
| opts="-q" | |
| else | |
| opts="-v" | |
| fi | |
| modprobe ${opts} -a i8042 atkbd ehci-pci ehci-orion \ | |
| ehci-hcd ohci-hcd ohci-pci uhci-hcd usbhid xhci \ | |
| xhci-pci xhci-hcd | |
| sleep 2 | |
| for modalias in /sys/bus/hid/devices/*/modalias; do | |
| if [ -f "${modalias}" ]; then | |
| modprobe ${opts} -b "$(cat ${modalias})" | |
| fi | |
| done | |
| fi | |
| panic "Spawning shell within the initramfs" | |
| ;; | |
| esac | |
| } | |
| render() | |
| { | |
| eval "echo -n \${$@}" | |
| } | |
| # For boot time only; this is overridden at build time in hook-functions | |
| run_scripts() | |
| { | |
| initdir=${1} | |
| [ ! -d ${initdir} ] && return | |
| shift | |
| . ${initdir}/ORDER | |
| } | |
| # Load custom modules first | |
| load_modules() | |
| { | |
| if [ -e /conf/modules ]; then | |
| cat /conf/modules | while read m; do | |
| # Skip empty lines | |
| if [ -z "$m" ]; then | |
| continue | |
| fi | |
| # Skip comments - d?ash removes whitespace prefix | |
| com=$(printf "%.1s" "${m}") | |
| if [ "$com" = "#" ]; then | |
| continue | |
| fi | |
| modprobe $m | |
| done | |
| fi | |
| } | |
| # lilo compatibility | |
| parse_numeric() { | |
| case $1 in | |
| *:*) | |
| # Does it match /[0-9]*:[0-9]*/? | |
| minor=${1#*:} | |
| major=${1%:*} | |
| case $major$minor in | |
| *[!0-9]*) | |
| # No. | |
| return | |
| ;; | |
| esac | |
| ;; | |
| "" | *[!A-Fa-f0-9]*) | |
| # "", "/*", etc. | |
| return | |
| ;; | |
| *) | |
| # [A-Fa-f0-9]* | |
| value=$(( 0x${1} )) | |
| minor=$(( (${value} & 0xff) | (${value} >> 12) & 0xfff00 )) | |
| major=$(( (${value} >> 8) & 0xfff )) | |
| ;; | |
| esac | |
| ROOT="/dev/block/${major}:${minor}" | |
| } | |
| # Parameter: device node to check | |
| # Echos fstype to stdout | |
| # Return value: indicates if an fs could be recognized | |
| get_fstype () | |
| { | |
| local FS FSTYPE FSSIZE RET | |
| FS="${1}" | |
| # blkid has a more complete list of file systems, | |
| # but fstype is more robust | |
| FSTYPE="unknown" | |
| eval $(fstype "${FS}" 2> /dev/null) | |
| if [ "$FSTYPE" = "unknown" ]; then | |
| FSTYPE=$(blkid -o value -s TYPE "${FS}") | |
| fi | |
| RET=$? | |
| if [ -z "${FSTYPE}" ]; then | |
| FSTYPE="unknown" | |
| fi | |
| echo "${FSTYPE}" | |
| return ${RET} | |
| } | |
| configure_networking() | |
| { | |
| if [ -n "${BOOTIF}" ]; then | |
| # pxelinux sets BOOTIF to a value based on the mac address of the | |
| # network card used to PXE boot, so use this value for DEVICE rather | |
| # than a hard-coded device name from initramfs.conf. this facilitates | |
| # network booting when machines may have multiple network cards. | |
| # pxelinux sets BOOTIF to 01-$mac_address | |
| # strip off the leading "01-", which isn't part of the mac | |
| # address | |
| temp_mac=${BOOTIF#*-} | |
| # convert to typical mac address format by replacing "-" with ":" | |
| bootif_mac="" | |
| IFS='-' | |
| for x in $temp_mac ; do | |
| if [ -z "$bootif_mac" ]; then | |
| bootif_mac="$x" | |
| else | |
| bootif_mac="$bootif_mac:$x" | |
| fi | |
| done | |
| unset IFS | |
| # look for devices with matching mac address, and set DEVICE to | |
| # appropriate value if match is found. | |
| for device in /sys/class/net/* ; do | |
| if [ -f "$device/address" ]; then | |
| current_mac=$(cat "$device/address") | |
| if [ "$bootif_mac" = "$current_mac" ]; then | |
| DEVICE=${device##*/} | |
| break | |
| fi | |
| fi | |
| done | |
| fi | |
| # networking already configured thus bail out | |
| [ -n "${DEVICE}" ] && [ -e /run/net-"${DEVICE}".conf ] && return 0 | |
| wait_for_udev 10 | |
| # support ip options see linux sources | |
| # Documentation/filesystems/nfs/nfsroot.txt | |
| # Documentation/frv/booting.txt | |
| for ROUNDTTT in 2 3 4 6 9 16 25 36 64 100; do | |
| # The NIC is to be configured if this file does not exist. | |
| # Ip-Config tries to create this file and when it succeds | |
| # creating the file, ipconfig is not run again. | |
| for x in /run/net-"${DEVICE}".conf /run/net-*.conf ; do | |
| [ -e "$x" ] && break 2 | |
| done | |
| case ${IP} in | |
| none|off) | |
| # Do nothing | |
| ;; | |
| ""|on|any) | |
| # Bring up device | |
| ipconfig -t ${ROUNDTTT} "${DEVICE}" | |
| ;; | |
| dhcp|bootp|rarp|both) | |
| ipconfig -t ${ROUNDTTT} -c ${IP} -d "${DEVICE}" | |
| ;; | |
| *) | |
| ipconfig -t ${ROUNDTTT} -d $IP | |
| # grab device entry from ip option | |
| NEW_DEVICE=${IP#*:*:*:*:*:*} | |
| if [ "${NEW_DEVICE}" != "${IP}" ]; then | |
| NEW_DEVICE=${NEW_DEVICE%%:*} | |
| else | |
| # wrong parse, possibly only a partial string | |
| NEW_DEVICE= | |
| fi | |
| if [ -n "${NEW_DEVICE}" ]; then | |
| DEVICE="${NEW_DEVICE}" | |
| fi | |
| ;; | |
| esac | |
| done | |
| IP=$(ip -o -f inet addr show | awk '/scope global/ {print $4}' | awk -F \/ '{print $1}') | |
| ip route add 172.31.1.1/32 src ${IP} dev ens3 | |
| ip route add 0.0.0.0/0 via 172.31.1.1 dev ens3 | |
| # source ipconfig output | |
| if [ -n "${DEVICE}" ]; then | |
| # source specific bootdevice | |
| . /run/net-${DEVICE}.conf | |
| else | |
| # source any interface... | |
| # ipconfig should have quit after first response | |
| . /run/net-*.conf | |
| fi | |
| } | |
| # Wait for queued kernel/udev events | |
| wait_for_udev() | |
| { | |
| command -v udevadm >/dev/null 2>&1 || return 0 | |
| udevadm settle ${1:+--timeout=$1} | |
| } | |
| # Find a specific fstab entry | |
| # $1=mountpoint | |
| # $2=fstype (optional) | |
| # returns 0 on success, 1 on failure (not found or no fstab) | |
| read_fstab_entry() { | |
| # Not found by default. | |
| found=1 | |
| for file in ${rootmnt}/etc/fstab; do | |
| if [ -f "$file" ]; then | |
| while read MNT_FSNAME MNT_DIR MNT_TYPE MNT_OPTS MNT_FREQ MNT_PASS MNT_JUNK; do | |
| case "$MNT_FSNAME" in | |
| ""|\#*) | |
| continue; | |
| ;; | |
| esac | |
| if [ "$MNT_DIR" = "$1" ]; then | |
| if [ -n "$2" ]; then | |
| [ "$MNT_TYPE" = "$2" ] || continue; | |
| fi | |
| found=0 | |
| break 2 | |
| fi | |
| done < "$file" | |
| fi | |
| done | |
| return $found | |
| } | |
| # Resolve device node from a name. This expands any LABEL or UUID. | |
| # $1=name | |
| # Resolved name is echoed. | |
| resolve_device() { | |
| DEV="$1" | |
| case "$DEV" in | |
| LABEL=* | UUID=* | PARTLABEL=* | PARTUUID=*) | |
| DEV="$(blkid -l -t "$DEV" -o device)" || return 1 | |
| ;; | |
| esac | |
| [ -e "$DEV" ] && echo "$DEV" | |
| } | |
| # Check a file system. | |
| # $1=device | |
| # $2=mountpoint (for diagnostics only) | |
| # $3=type (may be "auto") | |
| _checkfs_once() | |
| { | |
| DEV="$1" | |
| NAME="$2" | |
| TYPE="$3" | |
| if [ "$NAME" = "/" ] ; then | |
| NAME="root" | |
| fi | |
| FSCK_LOGFILE=/run/initramfs/fsck.log | |
| FSCK_STAMPFILE=/run/initramfs/fsck-${NAME#/} | |
| if [ "${TYPE}" = "auto" ]; then | |
| TYPE="$(get_fstype "${DEV}")" | |
| fi | |
| FSCKCODE=0 | |
| if ! command -v fsck >/dev/null 2>&1; then | |
| log_warning_msg "fsck not present, so skipping $NAME file system" | |
| return | |
| fi | |
| if [ "$fastboot" = "y" ] ; then | |
| log_warning_msg "Fast boot enabled, so skipping $NAME file system check." | |
| return | |
| fi | |
| if [ "$forcefsck" = "y" ] | |
| then | |
| force="-f" | |
| else | |
| force="" | |
| fi | |
| if [ "$fsckfix" = "y" ] | |
| then | |
| fix="-y" | |
| elif [ "$fsckfix" = "n" ] | |
| then | |
| fix="-n" | |
| else | |
| fix="-a" | |
| fi | |
| spinner="" | |
| if [ -z "${debug}" ]; then | |
| spinner="-C" | |
| fi | |
| if [ "${quiet}" = n ] | |
| then | |
| log_begin_msg "Will now check $NAME file system" | |
| logsave -a -s $FSCK_LOGFILE fsck $spinner $force $fix -V -t $TYPE $DEV | |
| FSCKCODE=$? | |
| log_end_msg | |
| else | |
| log_begin_msg "Checking $NAME file system" | |
| logsave -a -s $FSCK_LOGFILE fsck $spinner $force $fix -T -t $TYPE $DEV | |
| FSCKCODE=$? | |
| log_end_msg | |
| fi | |
| # NOTE: "failure" is defined as exiting with a return code of | |
| # 4, possibly or-ed with other flags. A return code of 1 | |
| # indicates that file system errors were corrected but that | |
| # the boot may proceed. | |
| # | |
| if [ "$FSCKCODE" -eq 32 ] | |
| then | |
| log_warning_msg "File system check was interrupted by user" | |
| elif [ $((FSCKCODE & 4)) -eq 4 ] | |
| then | |
| log_failure_msg "File system check of the $NAME filesystem failed" | |
| return 1 | |
| elif [ "$FSCKCODE" -gt 1 ] | |
| then | |
| log_warning_msg "File system check failed but did not detect errors" | |
| sleep 5 | |
| else | |
| > $FSCK_STAMPFILE | |
| fi | |
| return 0 | |
| } | |
| checkfs() | |
| { | |
| while ! _checkfs_once "$@"; do | |
| panic "The $2 filesystem on $1 requires a manual fsck" | |
| done | |
| } | |
| # Mount a file system. We parse the information from the fstab. This | |
| # should be overridden by any boot script which can mount arbitrary | |
| # filesystems such as /usr. This default implementation delegates to | |
| # local or nfs based upon the filesystem type. | |
| # $1=mountpoint mount location | |
| mountfs() | |
| { | |
| type=local | |
| read_fstab_entry "$1" | |
| if [ "${MNT_TYPE}" = "nfs" ] || [ "${MNT_TYPE}" = "nfs4" ]; then | |
| type=nfs | |
| fi | |
| ${type}_mount_fs "$1" | |
| } | |
| # Mount the root file system. It should be overridden by all | |
| # boot scripts. | |
| mountroot() | |
| { | |
| : | |
| } | |
| # Run /scripts/${boot}-top. This should be overridden by all boot | |
| # scripts. | |
| mount_top() | |
| { | |
| : | |
| } | |
| # Run /scripts/${boot}-premount. This should be overridden by all boot | |
| # scripts. | |
| mount_premount() | |
| { | |
| : | |
| } | |
| # Run /scripts/${boot}-bottom. This should be overridden by all boot | |
| # scripts. | |
| mount_bottom() | |
| { | |
| : | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment