用 Dropbear 为 Buildroot ARM64 设备配置密钥登录与端口转发前几篇已经在 Ubuntu 20.04、Buildroot 2025.02.8 和 QEMU ARM64 环境中完成了服务启动、权限隔离、日志轮转与 TCP 重连实验。接下来解决设备远程维护中的一个基础问题怎样通过 SSH 安全登录目标系统并使用端口转发访问目标端可达的 TCP 服务。本文使用 Buildroot 提供的 Dropbear SSH 服务端。实验包括公钥登录、禁用密码登录、通过 QEMU user-mode 网络将主机本机端口转发到 guest 的 SSH 端口以及通过 SSH 本地转发访问 Ubuntu 主机上的 TCP 测试服务。安全边界本文为了验证方便以 root 的 SSH 公钥登录 QEMU guest并只把 QEMU 转发端口绑定到 Ubuntu 的127.0.0.1。不要把此配置不加审查地用于实体设备或暴露到局域网、互联网实际产品应使用专用非 root 管理账户、持久保存并保护主机密钥并制定访问控制和密钥轮换方案。一、理解两层转发本实验同时出现 QEMU 的hostfwd和 SSH 的-L。它们是两种不同的转发不要混为一谈Ubuntu SSH 客户端 127.0.0.1:2222 | QEMU hostfwd v QEMU guest Dropbear:22 | SSH -L 隧道中的目标连接 v 10.0.2.2:5001Ubuntu 主机上的 SSH 转发测试服务QEMUhostfwd把 Ubuntu 主机本机的 TCP2222转到 guest 的22使主机可以连接 Dropbear。SSH-L在 Ubuntu 本机监听18080连接进入 SSH 隧道后由 guest 连接10.0.2.2:5001。-R是反向转发监听端口建立在 SSH 服务端一侧。本篇解释方向不把它与 QEMUhostfwd当成同一功能。两个转发端口都绑定在127.0.0.1实验只允许同一 Ubuntu 主机访问不向局域网开放。二、环境与操作约定项目本文沿用的设置开发主机Ubuntu 20.04 x86_64 虚拟机Buildroot2025.02.8~/buildroot-2025.02.8输出目录~/buildroot-output-arm64-demo外部目录~/buildroot-external-demo标识ARM64_DEMORootfs overlay~/buildroot-external-demo/board/qemu-arm64-demo/rootfs-overlay目标系统QEMU ARM64BusyBox initSSH 服务端QEMU guest 中的 DropbearTCP 22Ubuntu 转发端口127.0.0.1:2222SSH 本地转发测试127.0.0.1:18080到10.0.2.2:5001默认命令在Ubuntu 主机执行标注QEMU 目标端的命令才在 ARM64 系统内执行。请沿用现有 Buildroot 输出目录和外部树不要重新生成 defconfig 或在 QEMU 正使用镜像时构建。Buildroot 2025.02.8 的 SysV 启动脚本/etc/init.d/S50dropbear会读取/etc/default/dropbear。它启动服务时会追加-R缺少 host key 时Dropbear 会在第一次收到 SSH 连接时按需生成所需密钥。服务端 host key 与 Ubuntu 上用于登录的用户密钥是两套不同密钥前者用于识别服务器后者用于证明客户端身份。三、检查环境并备份如果 QEMU 正在运行先在QEMU 目标端执行poweroff等待 QEMU 退出再在Ubuntu 主机执行exportDEMO_OUT$HOME/buildroot-output-arm64-demoexportDROPBEAR_OVERLAY$HOME/buildroot-external-demo/board/qemu-arm64-demo/rootfs-overlaytest-f$DEMO_OUT/.configprintfconfig check exit code: %s\n$?test-d$DROPBEAR_OVERLAYprintfoverlay check exit code: %s\n$?grep-E^BR2_(INIT_BUSYBOX|PACKAGE_DEBUG_DEMO)$DEMO_OUT/.config文件检查都应返回0且 BusyBox init 与前文服务仍启用。若此 Buildroot 输出由外部 defconfig 管理后续还要把 Dropbear 选项同步到实际使用的 defconfig避免下一次重新生成配置时丢失。先备份 Buildroot 配置和外部树中本篇会涉及的文件exportSSH_BACKUP$HOME/dropbear-before-ssh-$(date%Y%m%d-%H%M%S)mkdir-p$SSH_BACKUPcp-p$DEMO_OUT/.config$SSH_BACKUP/buildroot.configcp-a$DROPBEAR_OVERLAY$SSH_BACKUP/rootfs-overlayprintfBackup: %s\n$SSH_BACKUP确认备份命令成功后再继续。若 overlay 已有/root/.ssh/authorized_keys或/etc/default/dropbear先检查并备份其内容不要直接覆盖已有密钥或 Dropbear 参数。四、在 Ubuntu 主机生成登录密钥在Ubuntu 主机生成一对 Ed25519 用户密钥。私钥保留在 Ubuntu 主机不要复制到 Rootfs overlay、QEMU 镜像或版本库install-d-m700$HOME/.sshexportSSH_KEY$HOME/.ssh/buildroot-qemu-dropbear-ed25519if[-e$SSH_KEY]||[-e$SSH_KEY.pub];thenprintfKey path already exists; choose a different SSH_KEY.\n2exit1fissh-keygen-ted25519-a64-f$SSH_KEY-Cbuildroot-qemu-dropbear按提示设置私钥口令输入时终端不会回显字符。若选择留空私钥就没有口令保护应严格保管文件权限并在实验后妥善删除或归档。若目标路径已有密钥文件先选择新路径或确认备份避免覆盖。本次实际输出确认密钥对已生成用户名路径已用$HOME简写省略了用户专属的 fingerprint 和 randomartGenerating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in $HOME/.ssh/buildroot-qemu-dropbear-ed25519 Your public key has been saved in $HOME/.ssh/buildroot-qemu-dropbear-ed25519.pub该输出确认密钥对已生成下一步只会把.pub公钥安装到 guest私钥留在 Ubuntu 主机。生成成功尚不代表 SSH 登录已验证。将公钥放进 guest 的 rootfs overlay并设置权限install-d-m700$DROPBEAR_OVERLAY/root/.sshif[-e$DROPBEAR_OVERLAY/root/.ssh/authorized_keys];thenprintfauthorized_keys already exists; inspect and append the new public key without replacing existing entries.\n2exit1fiinstall-m600$SSH_KEY.pub\$DROPBEAR_OVERLAY/root/.ssh/authorized_keysinstall-d-m755$DROPBEAR_OVERLAY/etc/defaultprintf%s\nDROPBEAR_ARGS-s\$DROPBEAR_OVERLAY/etc/default/dropbearchmod644$DROPBEAR_OVERLAY/etc/default/dropbear-s禁用密码登录公钥认证仍可使用。Rootfs overlay 只包含公钥不包含$SSH_KEY私钥。若已有authorized_keys应先备份并把新公钥追加到原文件而不是覆盖其他管理员密钥。五、启用 Dropbear 并重建镜像在Ubuntu 主机运行配置界面cd$HOME/buildroot-2025.02.8||exit1makeO$DEMO_OUTBR2_EXTERNAL$HOME/buildroot-external-demomenuconfig在菜单中启用Target packages - Networking applications - dropbear在 Dropbear 子菜单中本实验按以下方式选择菜单项选择原因dropbear勾选安装 SSH 服务端client programs不勾选SSH 客户端使用 Ubuntu 主机上的sshguest 不需要再安装一份disable reverse DNS lookups建议勾选本地 QEMU 实验不依赖反向 DNS避免登录时等待名称查询optimize for size保持默认本实验不以缩小镜像为目标log dropbear access to wtmp/lastlog不勾选本实验不需要登录历史数据库enable legacy crypto不勾选不启用已淘汰的旧加密算法path to custom localoptions.h definitions file留空本实验不需要自定义编译宏保存配置并退出。密码认证不是在此菜单中控制后面通过/etc/default/dropbear中的DROPBEAR_ARGS-s禁用密码登录同时保留公钥认证。确认服务端选项grep^BR2_PACKAGE_DROPBEAR$DEMO_OUT/.config本轮 Ubuntu 主机实际输出为$ grep ^BR2_PACKAGE_DROPBEAR $DEMO_OUT/.config BR2_PACKAGE_DROPBEARy这确认 Dropbear 服务端选项已启用。如配置由外部 defconfig 维护请把该选项并入实际 defconfig避免下次重新生成配置时丢失。不要运行make clean、distclean或重置整个配置。QEMU 必须已退出。重新构建(set-eucd$HOME/buildroot-2025.02.8makeO$DEMO_OUTBR2_EXTERNAL$HOME/buildroot-external-demo-j2)build_status$?printfBuild exit code: %s\n$build_status只有退出码为0才继续启动新镜像。本轮 Ubuntu 主机实际输出节选如下用户主目录以$HOME代替ln -sf rootfs.ext2 $DEMO_OUT/images/rootfs.ext4 Executing post-image script board/qemu/post-image.sh Build exit code: 0退出码0表示本次 Buildroot 构建及 post-image 脚本成功结束输出还显示rootfs.ext4是指向rootfs.ext2的符号链接。这只确认镜像构建成功Dropbear 启动、公钥登录和端口转发仍需按后续步骤在 QEMU 中验证。六、启动 QEMU 并检查 Dropbear在Ubuntu 主机启动 QEMU。与前文命令相比唯一的网络变化是在-netdev user中加入只绑定回环地址的 SSHhostfwdexportDEMO_OUT$HOME/buildroot-output-arm64-demo/usr/bin/qemu-system-aarch64\-Mvirt\-cpucortex-a53\-smp2\-m1G\-nographic\-kernel${DEMO_OUT:?请先设置 DEMO_OUT}/images/Image\-appendrootwait root/dev/vda consolettyAMA0\-drivefile$DEMO_OUT/images/rootfs.ext2,ifnone,formatraw,idhd0\-devicevirtio-blk-device,drivehd0\-netdevuser,idnet0,hostfwdtcp:127.0.0.1:2222-:22\-devicevirtio-net-device,netdevnet0QEMU 启动后终端被串口控制台占用。以root登录后以下检查在QEMU 目标端执行ps|grep[d]ropbearcat/etc/default/dropbearls-ld/root/.sshls-l/root/.ssh/authorized_keysls-l/etc/dropbear本轮 QEMU 目标端实际输出如下# ps | grep [d]ropbear 122 root /usr/sbin/dropbear -s -R # cat /etc/default/dropbear DROPBEAR_ARGS-s # ls -ld /root/.ssh drwxr-xr-x 2 root root 1024 Nov 2 05:25 /root/.ssh # ls -l /root/.ssh/authorized_keys -rw-r--r-- 1 root root 105 Nov 2 05:25 /root/.ssh/authorized_keys # ls -l /etc/dropbear total 0这确认 Dropbear 正在运行启动参数包含禁用密码登录的-s和按需生成 host key 的-R。初次检查发现.ssh权限为755、authorized_keys为644因此按下列步骤修正为本实验要求的700/600。首次 SSH 握手前/etc/dropbear为空是-R的预期行为。修正当前 guest 的公钥权限chownroot:root /root/.ssh /root/.ssh/authorized_keyschmod700/root/.sshchmod600/root/.ssh/authorized_keysls-ld/root/.sshls-l/root/.ssh/authorized_keys检查结果应显示/root/.ssh为drwx------authorized_keys为-rw-------。本轮修正后的实际输出为# chown root:root /root/.ssh /root/.ssh/authorized_keys # chmod 700 /root/.ssh # chmod 600 /root/.ssh/authorized_keys # ls -ld /root/.ssh drwx------ 2 root root 1024 Nov 2 05:25 /root/.ssh # ls -l /root/.ssh/authorized_keys -rw------- 1 root root 105 Nov 2 05:25 /root/.ssh/authorized_keys这确认当前运行的 guest 权限已修正无需重启 Dropbear。overlay 源文件的权限仍需按下方主机端步骤修正以便后续重建时保留。持久化权限上面的chown/chmod已立即修正当前运行的 guest。为让后续重建镜像也保留权限可在另一个Ubuntu 主机 shell修正 overlay 源文件不必为此先关闭 QEMU但修改 overlay 不会改变当前运行的 guest。DROPBEAR_OVERLAY是主机 shell 的变量不会传入 guest不要在 QEMU 的#提示符下执行以下命令。若之后要重建镜像必须先在 QEMU 目标端执行poweroff并确认 QEMU 退出再运行 Buildroot 构建exportDROPBEAR_OVERLAY$HOME/buildroot-external-demo/board/qemu-arm64-demo/rootfs-overlaychmod700$DROPBEAR_OVERLAY/root/.sshchmod600$DROPBEAR_OVERLAY/root/.ssh/authorized_keys在QEMU 目标端执行目录检查ls-ld/etc/dropbear readlink /etc/dropbear||truels-la/etc/dropbearls-la/var/run/dropbear本轮首次 SSH 连接前的实际输出如下# ls -ld /etc/dropbear drwxr-xr-x 2 root root 1024 Nov 2 05:38 /etc/dropbear # readlink /etc/dropbear # ls -la /etc/dropbear total 2 drwxr-xr-x 2 root root 1024 Nov 2 05:38 . drwxr-xr-x 8 root root 1024 Nov 2 05:38 .. # ls -la /var/run/dropbear ls: /var/run/dropbear: No such file or directoryreadlink没有输出说明当前/etc/dropbear是真实目录/var/run/dropbear不存在在可写 rootfs 下符合S50dropbear将该链接替换为实际目录的处理方式。该目录首次握手前为空是预期的host key 将由-R在首次连接时按需生成。可写 ext2 镜像会保存生成后的 host key。下面直接通过 Ubuntu 主机发起首次连接并在核对指纹后决定是否信任该 host key。七、核对 host key 并测试公钥登录本节的三个步骤都围绕首次 SSH 登录按顺序在标明的终端执行。保持 QEMU 运行。第一步从 Ubuntu 主机触发首次握手但先拒绝未知 host key。在 Ubuntu 主机另开一个终端执行exportSSH_KEY$HOME/.ssh/buildroot-qemu-dropbear-ed25519ssh-i$SSH_KEY\-oPreferredAuthenticationspublickey\-oPasswordAuthenticationno\-oStrictHostKeyCheckingask\-p2222root127.0.0.1首次连接会显示服务端 host key 指纹并询问是否继续。记录指纹在提示处输入no不要直接输入yes。客户端中止本次登录是预期结果首次握手已触发 Dropbear 生成并保存 host key。本次实测输出如下The authenticity of host [127.0.0.1]:2222 ([127.0.0.1]:2222) cant be established. ECDSA key fingerprint is SHA256:xkEIJasYUsWkwjIgYAEIZ7WuozHkqkwIoZXcSfgxYek. Are you sure you want to continue connecting (yes/no/[fingerprint])? no Host key verification failed.第二步回到 QEMU 目标端核对指纹。forhost_keyin/etc/dropbear/*_host_key;do[-f$host_key]||continueprintf%s\n$host_keydropbearkey-y-f$host_key|grepFingerprint:done本轮 QEMU 目标端的实际输出如下# for host_key in /etc/dropbear/*_host_key; do [ -f $host_key ] || continue printf %s\n $host_key dropbearkey -y -f $host_key | grep Fingerprint: done /etc/dropbear/dropbear_ecdsa_host_key Fingerprint: SHA256:xkEIJasYUsWkwjIgYAEIZ7WuozHkqkwIoZXcSfgxYek该 ECDSA 指纹与 Ubuntu 首次连接提示完全一致host key 核验通过。若循环没有输出 key 文件或指纹不一致则停止登录并检查-R、/etc/dropbear写入状态和 QEMU 镜像不要关闭 host key 校验来绕过问题。第三步指纹一致后再登录。在 Ubuntu 主机重新运行第一步的 SSH 命令再次提示时确认指纹一致并输入yes。公钥认证成功后应进入 Buildroot guest shell服务端配置-s密码认证被禁用。本例虽使用 root 公钥登录以便做教学检查但仅用于主机回环接口上的 QEMU 实验。真实设备应使用权限受限的专用管理账户并尽可能禁用 root 远程登录。可在 guest shell 中确认自己位于目标端并查看服务仍在运行uname-midpidof debug_demo本轮 SSH 登录后的 QEMU guest 实际输出如下# uname -m aarch64 # id uid0(root) gid0(root) groups0(root),10(wheel) # pidof debug_demo 128输出确认当前 shell 位于 ARM64 guest登录用户为 root且debug_demo进程仍在运行。若这些命令是在 SSH 登录后的 shell 中执行则公钥 SSH 登录已成功PID128是本轮 guest 中该进程的进程号。八、验证 SSH 本地端口转发前文的 Python 服务一次只处理一个连接debug_demo当前保持着到 TCP5000的连接因此服务不会接受 SSH 隧道测试的新连接直到该连接断开。这里单独使用 Ubuntu 主机 TCP5001做 SSH 转发测试原有5000服务保持不变。在Ubuntu 主机终端 D启动专用测试服务并保持运行。服务绑定0.0.0.0是为了让 QEMU guest 能访问10.0.2.2:5001同时也会接受 Ubuntu 虚拟机其他网络接口上的连接仅在可信、隔离的实验环境中临时运行不要为此配置额外的宿主机或公网端口映射测试后按CtrlC停止。python3-u-PY import socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((0.0.0.0, 5001)) server.listen(4) print(SSH test server listening on 0.0.0.0:5001, flushTrue) while True: connection, address server.accept() with connection: with connection.makefile(rb) as stream: line stream.readline(257) if line.endswith(b\n) and len(line) 256: response bACK line connection.sendall(response) print(freceived{line!r} sent{response!r}, flushTrue) elif line: print(fignored incomplete or oversized request from {address}, flushTrue) PY另开 Ubuntu 主机终端确认服务在监听ss-lntp|grep:5001应能看到0.0.0.0:5001处于LISTEN状态。确认后再启动 SSH 隧道。在Ubuntu 主机终端 C执行以下命令并保持前台运行exportSSH_KEY$HOME/.ssh/buildroot-qemu-dropbear-ed25519ssh-N\-oExitOnForwardFailureyes\-i$SSH_KEY\-p2222\-L127.0.0.1:18080:10.0.2.2:5001\root127.0.0.1-N表示不在 guest 启动远程 shell该 SSH 会话只维持转发。终端 C 无提示符、没有新输出是正常的。若端口18080已被占用换一个本地未使用端口并在下面的测试命令中同步修改。另开一个Ubuntu 主机终端用 Bash 的/dev/tcp发送一行并读取 ACKexec3/dev/tcp/127.0.0.1/18080printfssh-forward-check\n3IFSread-r-t5response3printfresponse%s\n$responseexec3-exec3-预期输出为responseACK ssh-forward-check本轮 Ubuntu 主机实测收到responseACK ssh-forward-check这确认路径为 Ubuntu 本机端口18080→ SSH 本地转发 → guest →10.0.2.2:5001→ 专用 Python 测试服务。服务终端同时应记录收到请求并发送 ACK。结束时分别在终端 C 按CtrlC关闭 SSH 隧道并在终端 D 按CtrlC停止专用测试服务这不会停止 Dropbear 或debug-demo。SSH 的-R与这里的-L方向相反-R在 Dropbear 所在端建立监听端口再把连接转回 SSH 客户端所在端。本实验只实际验证-L不要把-R或 QEMU 的hostfwd误认为已经测试。九、常见故障排查现象检查方向Connection refused连接127.0.0.1:2222确认 QEMU 的hostfwd将本机127.0.0.1:2222转到 guest22在 guest 检查 Dropbear 是否启动和监听Permission denied (publickey)确认公钥行在 guest 的/root/.ssh/authorized_keys私钥与.pub配对检查目录/文件 owner 和权限确认/etc/default/dropbear中参数为-s而不是禁用公钥的选项REMOTE HOST IDENTIFICATION HAS CHANGED不要关闭校验先在 guest 控制台核对 host key 指纹。确认镜像确实重建后再清理known_hosts中[127.0.0.1]:2222的旧记录SSH 能登录但-L报绑定失败Ubuntu 本机端口18080已占用改用另一空闲端口且确认本地绑定为127.0.0.1channel 1: open failed: connect failed: Connection refused或隧道建立但读不到 ACK-L最后一段目标地址由 guest 连接确认 Ubuntu 主机专用 Python 测试服务正在0.0.0.0:5001监听、guest 可访问10.0.2.2:5001且换行协议一致局域网其他机器无法连接本文将 QEMU 转发和 SSH 本地转发都绑定在127.0.0.1这是预期限制不要直接改为0.0.0.0暴露服务排查时可在 Ubuntu 客户端增加-vvv获取 SSH 连接诊断诊断输出可能包含用户名、路径、主机 key 指纹和网络信息公开前应先审查并脱敏。十、实验边界与发布前记录本篇演示的是 QEMU 本机回环场景下的 Dropbear 公钥登录和 SSH-L。它不覆盖真实网卡、DHCP、无线网络、VPN、外网防火墙、专用管理账户、密钥撤销/轮换、SSH agent 转发或生产设备的持久化密钥管理。-s禁用密码登录不等于完整安全加固root 公钥登录仅为本实验便利不建议直接用于产品设备。截至本轮Buildroot 构建、guest 的 Dropbear 启动状态、host key 指纹核验、公钥登录和 SSH 本地端口转发 ACK 均已有实测结果并记录在文中。其余未提供实测结果的内容仍按预期行为描述不应误认为已在本次实验中验证。十一、小结通过在 Buildroot 中启用 Dropbear、把 Ubuntu 用户公钥放入 rootfs overlay并以-s禁用密码登录可以在 QEMU ARM64 中建立 SSH 公钥登录。本篇还通过只绑定127.0.0.1的 QEMUhostfwd接入 guest SSH再用 SSH-L将主机本机端口安全转发到 guest 可达的主机 TCP 服务。QEMU 端口映射、SSH 本地转发与 SSH 反向转发是不同机制理解各自的监听端和连接发起端是避免配置错误和意外暴露服务的关键。