ssh-keyscan
收集主机 SSH 公钥的工具
补充说明
ssh-keyscan 是 OpenSSH 套件中的一个工具,用于批量收集远程主机的 SSH 公钥。它通过非交互方式连接 SSH 服务器并获取其主机密钥,常用于初始化 known_hosts 文件、搭建 SSH 信任网络或自动化部署场景。
相较于手动 ssh 连接后确认指纹,ssh-keyscan 可以批量、自动化地收集多台主机的公钥,无需逐个交互确认。
语法
ssh-keyscan [选项] [主机列表...]
选项
-4 强制使用 IPv4 地址
-6 强制使用 IPv6 地址
-f <文件> 从指定文件中读取主机列表(每行一个)
-H 对 known_hosts 中的主机名进行哈希处理
-p <端口> 指定连接远程主机的端口(默认 22)
-T <秒数> 指定连接尝试的超时时间(默认 5 秒)
-t <类型> 指定要获取的密钥类型(rsa/dsa/ecdsa/ed25519)
-v 调试模式,打印详细信息
密钥类型
# 支持的密钥类型
-t rsa RSA 密钥
-t dsa DSA 密钥(已不推荐)
-t ecdsa ECDSA 密钥
-t ed25519 Ed25519 密钥
# 获取所有类型(默认行为,不加 -t)
ssh-keyscan hostname
# 指定多种类型
ssh-keyscan -t rsa,ed25519 hostname
基础用法
# 获取主机的所有公钥
ssh-keyscan example.com
# 获取指定类型的公钥(推荐)
ssh-keyscan -t ed25519 example.com
# 指定端口
ssh-keyscan -p 2222 example.com
# 指定超时时间
ssh-keyscan -T 10 example.com
# 调试模式
ssh-keyscan -v example.com
# 哈希主机名(保护隐私)
ssh-keyscan -H example.com
批量收集
# 从文件读取主机列表
cat hosts.txt
# 192.168.1.1
# 192.168.1.2
# server.example.com
ssh-keyscan -f hosts.txt
# 指定多个主机
ssh-keyscan host1 host2 host3
# 扫描子网(使用循环)
for ip in $(seq 1 20); do
ssh-keyscan -t ed25519 192.168.1.$ip
done
# 扫描 IP 段并合并结果
ssh-keyscan -t ed25519 192.168.1.{1..20}
更新 known_hosts
# 将公钥追加到 known_hosts(追加模式)
ssh-keyscan -t ed25519 hostname >> ~/.ssh/known_hosts
# 哈希主机名后追加
ssh-keyscan -H -t ed25519 hostname >> ~/.ssh/known_hosts
# 覆盖写入(先备份再写入)
ssh-keyscan -t ed25519 hostname > ~/.ssh/known_hosts
# 追加到系统级 known_hosts
ssh-keyscan -t ed25519 hostname | sudo tee -a /etc/ssh/ssh_known_hosts
实际应用场景
1. 自动化部署 - 预先建立信任
# 在部署脚本中预先添加主机密钥
#!/bin/bash
HOSTS="server1 server2 server3"
for host in $HOSTS; do
ssh-keyscan -H -t ed25519 $host >> ~/.ssh/known_hosts 2>/dev/null
done
# 这样后续 ssh/scp/rsync 等操作就不会弹出确认提示
2. 批量添加集群节点
# 集群初始化时批量添加所有节点
NODES=("node1.local" "node2.local" "node3.local" "node4.local")
for node in "${NODES[@]}"; do
echo "收集 $node 的公钥..."
ssh-keyscan -H -t ed25519 "$node" >> ~/.ssh/known_hosts 2>/dev/null
done
echo "所有节点公钥已添加"
3. 清理并重建 known_hosts
# 备份旧的 known_hosts
cp ~/.ssh/known_hosts ~/.ssh/known_hosts.bak
# 清空文件
> ~/.ssh/known_hosts
# 重新收集所有常用主机的公钥
ssh-keyscan -H -t ed25519 \
github.com \
gitlab.com \
bitbucket.org \
server1.example.com \
server2.example.com >> ~/.ssh/known_hosts
# 验证
ssh-keygen -l -f ~/.ssh/known_hosts
4. 配合 Ansible 批量管理
# 在 Ansible 部署前置任务中使用
# playbook.yml 中的 pre_tasks:
# - name: 收集主机公钥
# shell: |
# ssh-keyscan -H -t ed25519 {{ inventory_hostname }} >> ~/.ssh/known_hosts
# delegate_to: localhost
# changed_when: false
与相关命令配合
# 检查 known_hosts 内容
ssh-keygen -l -f ~/.ssh/known_hosts
# 删除特定主机的旧密钥
ssh-keygen -R hostname
# 重新收集并添加
ssh-keyscan -H -t ed25519 hostname >> ~/.ssh/known_hosts
# 一键刷新:删除旧密钥 + 收集新密钥
ssh-keygen -R hostname && ssh-keyscan -H -t ed25519 hostname >> ~/.ssh/known_hosts
# 验证连接是否正常
ssh -o StrictHostKeyChecking=accept-new user@hostname "uptime"
注意事项
# 安全风险:ssh-keyscan 不验证密钥真实性
# 可能受到中间人攻击(MITM),建议配合以下方式使用:
# 1. 首次连接后手动验证指纹
ssh-keyscan hostname | ssh-keygen -l -f -
# 2. 对比已知指纹(从安全渠道获取)
# 服务器提供的指纹:SHA256:xxxxxx...
ssh-keyscan -t ed25519 hostname 2>/dev/null | ssh-keygen -l -f - | grep -q "SHA256:xxxxxx"
# 3. 仅用于内部信任网络
# 4. 结合 DNSSEC 使用(SSHFP 记录)
常见问题
# 连接超时
# 增加超时时间
ssh-keyscan -T 30 hostname
# 端口不通
# 确认服务器 SSH 端口并指定
ssh-keyscan -p 2222 hostname
# 获取不到特定类型的密钥
# 确认服务器支持该类型,不加 -t 获取所有类型
ssh-keyscan hostname
# 输出格式不对
# 正常输出格式:hostname algorithm base64key
# 若服务端返回异常,尝试调试模式查看
ssh-keyscan -v hostname 2>&1
输出格式
# 标准输出格式:
<hostname> <算法> <base64编码的公钥>
# 示例:
server.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDy...
server.example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ...
参数
主机列表:指定要收集公钥的主机名或 IP 地址列表。