ssh公钥批量分发本质是将专用密钥对的公钥自动写入目标服务器的~/.ssh/authorized_keys文件,关键在于绕过首次连接的交互(密码输入、主机确认),并适配无ssh-copy-id、禁用密码登录等约束;需生成独立密钥对(推荐ed25519)、用sshpass或expect实现免交互推送,并验证权限与登录有效性。

SSH 公钥的批量分发本质是把本地私钥对应的公钥,自动、安全地写入目标服务器指定用户的 ~/.ssh/authorized_keys 文件中。关键不在“分发动作”本身,而在于如何绕过首次连接时的交互(密码输入、yes/no 主机确认),并适配不同环境约束(如无 ssh-copy-id、禁用密码登录、非 root 用户等)。
准备专用密钥对,避免混用
不要复用已有密钥(如日常登录用的 id_rsa)。为批量管理单独生成一对密钥,便于权限隔离和事后审计:
- 用更安全的 Ed25519 算法:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_batch -N "" -C "batch-admin" - 生成后检查:私钥
id_ed25519_batch必须严格保护(chmod 600),公钥id_ed25519_batch.pub用于分发 - 若目标系统较老(如 CentOS 6),可退而使用 RSA:
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_batch -N ""
用 sshpass 实现免交互密码推送(最通用)
当目标服务器仍允许密码登录时,这是最简单可靠的批量方式。需提前安装 sshpass:
- CentOS/RHEL:
yum install -y sshpass;Ubuntu/Debian:apt install -y sshpass - 假设有主机列表
servers.txt,每行格式为user@ip或user@ip:port - 执行命令一次性分发:
while read host; do sshpass -p 'your_password' \ ssh-copy-id -i ~/.ssh/id_ed25519_batch.pub \ -o StrictHostKeyChecking=no \ "$host" done - 注意:
-o StrictHostKeyChecking=no跳过首次主机指纹确认;密码明文写在脚本里有风险,生产环境建议改用变量或读取加密文件
用 expect 脚本应对无 ssh-copy-id 或特殊交互场景
某些精简系统(如容器、嵌入式设备)可能没装 ssh-copy-id,或需要处理多级提示(如 sudo 密码、二次确认)。这时用 expect 更灵活:
- 示例脚本片段(保存为
pushkey.exp):#!/usr/bin/expect -f set timeout 30 set host [lindex $argv 0] set user [lindex $argv 1] set pass [lindex $argv 2] set keyfile [lindex $argv 3] spawn ssh $user@$host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" expect { "yes/no" { send "yes\r"; exp_continue } "password:" { send "$pass\r" } } expect eof - 调用方式:
./pushkey.exp 192.168.1.100 root mypass ~/.ssh/id_ed25519_batch.pub - 优势:不依赖
ssh-copy-id,可嵌入任意 shell 命令;劣势:需额外安装 expect,脚本维护成本略高
分发后验证与加固建议
公钥写入成功不等于能立刻免密登录,还需检查几处:
- 登录测试:
ssh -i ~/.ssh/id_ed25519_batch -o IdentitiesOnly=yes user@ip uptime,加IdentitiesOnly=yes防止客户端自动尝试其他密钥干扰 - 检查服务端权限:
~/.ssh目录应为700,authorized_keys应为600,否则 SSH 会拒绝读取 - 若已禁用密码登录(
PasswordAuthentication no),务必确保公钥分发 100% 成功后再 reload sshd,否则可能锁死 - RDP 与 SSH 是两类协议,Windows 服务器的远程接入控制需另配 Windows 组策略或 WinRM,不能靠 SSH 密钥解决










