diff --git a/bot_bottle/backend/firecracker/bottle.py b/bot_bottle/backend/firecracker/bottle.py index aff4fcf..c8bc62b 100644 --- a/bot_bottle/backend/firecracker/bottle.py +++ b/bot_bottle/backend/firecracker/bottle.py @@ -151,8 +151,13 @@ class FirecrackerBottle(Bottle): ["tar", "-C", host_parent, "-cf", "-", host_base], stdout=subprocess.PIPE, ) + # Pass the command as one arg: ssh space-joins everything after + # the host into a single string for the guest's login shell, so a + # `sh -c ` split would drop everything past the first word + # (the guest shell runs `` directly; stdin carries the + # tar). ssh = subprocess.run( - [*self._ssh(tty=False), "--", "sh", "-c", remote], + [*self._ssh(tty=False), "--", remote], stdin=tar.stdout, capture_output=True, text=True, check=False, ) tar.wait() diff --git a/bot_bottle/backend/firecracker/util.py b/bot_bottle/backend/firecracker/util.py index 15b0bb5..aa29e8a 100644 --- a/bot_bottle/backend/firecracker/util.py +++ b/bot_bottle/backend/firecracker/util.py @@ -268,6 +268,10 @@ def ssh_base_argv(private_key: Path, guest_ip: str) -> list[str]: return [ "ssh", "-i", str(private_key), + # Only offer the per-bottle key — don't let an agent or the + # operator's ~/.ssh/config inject other identities (newer + # OpenSSH otherwise may not reliably present the -i key). + "-o", "IdentitiesOnly=yes", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-o", "LogLevel=ERROR", @@ -301,9 +305,17 @@ if [ -n "$KEY" ]; then chown -R node:node /home/node/.ssh 2>/dev/null || true fi +# The rootless rootfs build (`docker export | tar` as a non-root user) +# can't preserve uid 0, so every path lands owned by the build uid, +# which maps to `node` (uid 1000) in-guest — including /root. dropbear +# (like OpenSSH) refuses root's authorized_keys unless the home dir is +# owned by root, so restore root's ownership of its own home. +chown -R 0:0 /root 2>/dev/null || true + mkdir -p /etc/dropbear /run -# -R: generate host keys on demand. -E: log to stderr (guest console). -/bb-dropbear -R -E -p 22 2>/dev/null & +# -R: generate host keys on demand. -E: log auth failures to stderr, +# captured in the host-side console.log for debugging. +/bb-dropbear -R -E -p 22 & # Reap zombies as PID 1. dropbear is always a child, so `wait` blocks # rather than busy-looping.