diff --git a/bin/prod/ssh-keygen-boot b/bin/prod/ssh-keygen-boot new file mode 100755 index 0000000..b1db572 --- /dev/null +++ b/bin/prod/ssh-keygen-boot @@ -0,0 +1,40 @@ +#!/bin/bash + +set -euo pipefail + +LOG_FILE="${LOG_FILE:-/var/log/reflash.log}" +KEY_DIR="${REFLASH_SSH_KEY_DIR:-/mnt/usb/ssh_host_keys}" + +info() { + echo "[info] $1" >> "$LOG_FILE" + echo "$1" +} + +# Build-time SSH host key generation (a side effect of installing +# openssh-server) would bake identical keys into every image and every board +# flashed from it. Keys are deleted at build time instead, and restored (or +# generated once and saved) here from the USB drive - the one thing on this +# board that actually persists across reboots, unlike the initrd root fs. + +# On a freshly-flashed drive, /mnt/usb's partition doesn't exist yet - it's +# normally created by expand-usb, which the Go server calls on its own +# startup. This unit runs before reflash.service specifically so it has +# /mnt/usb to itself first, which means that hasn't happened yet here. +# expand-usb is idempotent (a no-op once the partition already exists), so +# calling it again from reflash.service afterward is harmless. +expand-usb + +mount-unmount-usb mounted rw + +if [ -f "$KEY_DIR/ssh_host_rsa_key" ]; then + info "Restoring SSH host keys from USB storage" + cp "$KEY_DIR"/ssh_host_* /etc/ssh/ +else + info "No saved SSH host keys on USB storage - generating and saving new ones" + ssh-keygen -A + mkdir -p "$KEY_DIR" + cp /etc/ssh/ssh_host_* "$KEY_DIR/" +fi + +mount-unmount-usb unmounted +info "SSH host keys ready" diff --git a/mkimage.sh b/mkimage.sh index 1b8941f..7fc4620 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -180,6 +180,13 @@ RemainAfterExit=yes [Install] EOF +# Installing openssh-server generated SSH host keys as a side effect - baked +# into this one build, they'd be identical across every image and every +# board flashed from it (#80). Delete them; ssh-keygen-boot.service (set up +# below, outside the chroot) restores or generates them from USB storage +# on boot instead. +rm -f /etc/ssh/ssh_host_* + # Clean up rm -rf /usr/sbin/policy-rc.d rm ./*.deb @@ -253,6 +260,30 @@ cat < "${ROOTFSDIR}"/initrd/etc/systemd/resolved.conf.d/mdns.conf MulticastDNS=yes EOF +# This board's root fs runs from initrd and doesn't persist writes across +# reboots, so keys generated straight into /etc/ssh would be regenerated +# (and thus change) every boot. ssh-keygen-boot restores/saves them against +# /mnt/usb instead - the one thing that actually persists - so a given board +# keeps a stable identity while still not sharing a key with every other +# image/board (#80). Ordered before both ssh.service and reflash.service so +# it has /mnt/usb to itself - mount-unmount-usb has no locking of its own. +cat <"${ROOTFSDIR}"/initrd/etc/systemd/system/ssh-keygen-boot.service +[Unit] +Description=Restore or generate persistent SSH host keys from USB storage (see #80) +Before=ssh.service reflash.service +ConditionPathExists=!/etc/ssh/ssh_host_rsa_key + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/ssh-keygen-boot +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +EOF + +systemctl enable ssh-keygen-boot --root="${ROOTFSDIR}"/initrd + cat <"${ROOTFSDIR}"/initrd/etc/systemd/system/reflash.service [Unit] Description=Refactor flashing server