AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

sshpass —— 密码登录自动化(仅限"首次推 key"场景)

一句话定义

sshpass 是个非常小的工具,作用只有一个:在脚本里把密码喂给 ssh,跳过那个交互式的密码提示。

OpenSSH 客户端本身故意不接受 -p <password> 这种参数(安全设计 —— 防止密码出现在 ps 输出和 shell history 里)。sshpass 是个绕过这个限制的小hack。

典型场景

90% 的合理使用就一个:拿到一批全新机器,第一次推公钥时,没法用 key 登(因为 key 还没推过去),只能用密码。这时用 sshpass 在脚本里自动化推 key,推完立刻关密码登录。

Day0 §2.1:

PUBKEY=$(cat ~/.ssh/id_rsa.pub)
for ip in 10.0.24.28 10.0.24.29 10.0.24.30 10.0.24.31 10.0.24.32; do
  sshpass -p "$IP_PWD" ssh -o StrictHostKeyChecking=accept-new root@$ip "
    mkdir -p /root/.ssh && chmod 700 /root/.ssh
    grep -qxF '$PUBKEY' /root/.ssh/authorized_keys 2>/dev/null \
      || echo '$PUBKEY' >> /root/.ssh/authorized_keys
    chmod 600 /root/.ssh/authorized_keys
  "
done

绝对不应该用 sshpass 的场景:

  • 日常运维(key + ssh-agent 完全够)
  • 生产部署(必须用 key 或更严的认证)
  • 把密码写在 git 仓库的脚本里(密码泄漏 = 机器沦陷)

安装

# Ubuntu / Debian
apt-get install -y sshpass

# macOS(Homebrew 默认不收,因为它"不安全")
brew install hudochenkov/sshpass/sshpass

# CentOS / RHEL(需要 EPEL)
yum install -y epel-release
yum install -y sshpass

brew 官方不收的原因:维护者觉得 sshpass 鼓励了不好的做法(把密码写脚本里)。要装得走第三方 tap,或者别用 macOS 跑这种脚本(拉个 Linux VM)。


三种"喂密码"方式

按安全性排序,越往后越安全。

1. -p <password> —— 命令行参数(最不安全)

sshpass -p 'MyPassw0rd' ssh root@host

问题:

  • ps aux | grep sshpass 会看到密码(任何能登录这台机器的人都能 sniff)
  • 写进 shell history(.bash_history、.zsh_history)
  • 容易被 git commit 进代码库

只用于一次性、纯本机、马上要删 history 的场景。

2. -f <file> —— 从文件读

echo 'MyPassw0rd' > /tmp/pw
chmod 600 /tmp/pw
sshpass -f /tmp/pw ssh root@host
rm /tmp/pw

比 -p 好:不出现在 ps 输出。但密码以明文落盘,依然不理想。

3. -e —— 从环境变量 SSHPASS 读(推荐)

export SSHPASS='MyPassw0rd'
sshpass -e ssh root@host
unset SSHPASS

# 或者一次性,密码只在子进程里
SSHPASS='MyPassw0rd' sshpass -e ssh root@host

环境变量不出现在 ps、不写文件。配合 read -s 输入更安全:

read -s -p "Password: " SSHPASS
export SSHPASS
for ip in ...; do
  sshpass -e ssh root@$ip 'echo OK'
done
unset SSHPASS

read -s 不回显密码到屏幕。Day0 推 key 脚本应该这么写。


完整推 key 工作流(建议这么干)

#!/bin/bash
set -euo pipefail

read -s -p "IDC machine password: " SSHPASS
export SSHPASS
echo

PUBKEY=$(cat ~/.ssh/id_ed25519.pub)
IPS=(10.0.24.28 10.0.24.29 10.0.24.30 10.0.24.31 10.0.24.32)

for ip in "${IPS[@]}"; do
  echo "=== $ip ==="
  sshpass -e ssh \
    -o StrictHostKeyChecking=accept-new \
    -o ConnectTimeout=10 \
    root@"$ip" "
      mkdir -p /root/.ssh && chmod 700 /root/.ssh
      grep -qxF '$PUBKEY' /root/.ssh/authorized_keys 2>/dev/null \
        || echo '$PUBKEY' >> /root/.ssh/authorized_keys
      chmod 600 /root/.ssh/authorized_keys
    " && echo "  ✅ key pushed" || echo "  ❌ failed"
done

unset SSHPASS

# 验证:每台机器用 key 都能登
for ip in "${IPS[@]}"; do
  ssh -o BatchMode=yes -o ConnectTimeout=5 root@"$ip" 'echo OK' \
    && echo "$ip: ✅ key works" \
    || echo "$ip: ❌ key broken"
done

关键点:

  • read -s 输入密码不回显
  • set -euo pipefail 让脚本一遇到错就退出(避免某台失败但继续推后面的)
  • StrictHostKeyChecking=accept-new:首次自动信任并写 known_hosts
  • ConnectTimeout=10:默认 TCP 重试好几分钟,加超时让脚本快速失败
  • grep -qxF ... || 实现幂等(详见 ssh-keygen.md)
  • 推完立刻验证 key 工作(BatchMode=yes 禁交互),确认 OK 之后再关密码

常见踩坑

坑 1:推 key 成功了,但马上 PasswordAuthentication no,结果 key 不工作

顺序不能反。正确顺序:

  1. 推 key
  2. 用 ssh -o BatchMode=yes 验证 key 能登
  3. 确认验证通过后,再去关 PasswordAuthentication(见 sshd.md)

如果 key 没工作就关了密码 → 你既不能用密码登、也不能用 key 登 → 锁外面。

坑 2:密码里有特殊字符($, !, `)

sshpass -p 'My$ecret!' ssh root@host        # 单引号是必须的
sshpass -p "My$ecret!" ssh root@host        # ❌ $ecret 被 shell 当变量展开(多半为空)

含 $ 或 ` 的密码:用单引号。

坑 3:sshpass 报 "command not found"

-bash: sshpass: command not found

很多发行版默认不装。apt-get install -y sshpass。

坑 4:sshpass 报 "Permission denied",密码明明对

可能是远端禁用了 keyboard-interactive、或者只允许公钥。先用普通 ssh root@host 手动试一次,看远端到底允许什么认证方式:

ssh -v -o PreferredAuthentications=password root@host
# Authentications that can continue: publickey
# 说明远端禁了密码

这种机器你根本不需要 sshpass —— 它已经强制 key 了。

坑 5:first connection 的 host key 提示卡住

sshpass -e ssh root@host         # ❌ 卡在 "Are you sure you want to continue?"

sshpass 喂的是登录密码,不是这个提示的"yes"回答。加 StrictHostKeyChecking=accept-new 让 ssh 自动信任首次:

sshpass -e ssh -o StrictHostKeyChecking=accept-new root@host

坑 6:CI 环境里把密码 commit 进了 .env 或脚本

经典事故。CI 跑得好好的,过了一年某个新员工把 repo 设成 public 或者 fork 出去 → 密码泄漏。

防御:

  • 用 CI 平台的 secret 机制(GitHub Actions secrets、GitLab CI variables)
  • 任何脚本里都用 ${SSHPASS} 读环境变量,不在文件里写明文
  • 不要 commit .env:.gitignore 加 .env、*.password、secrets/*

更彻底的:根本不要用 sshpass 进 CI。CI 部署用 SSH key(CI 提供的 deploy key 机制),key 不会泄漏的同时还能精确撤销。


替代方案

Ansible(首选)

ansible all -i hosts -m authorized_key \
  -a "user=root state=present key='$(cat ~/.ssh/id_ed25519.pub)'" \
  -k                    # -k 提示输入密码

-k 一次性输密码,Ansible 帮你处理所有节点。无需 sshpass。

ssh-copy-id

for ip in ...; do
  ssh-copy-id -i ~/.ssh/id_ed25519.pub root@$ip
done

每台机器交互式问一次密码。机器多就累,机器少(≤5)足够。

直接走 cloud-init / IDC console 注入 key

很多 IDC 创建机器时可以选"注入 SSH 公钥"。这是最佳做法 —— 机器开出来就有 key,根本不需要密码登录这一步。


关联命令

  • ssh —— sshpass 只是 ssh 前面的一个 wrapper
  • ssh-keygen —— 先生成 key 才有可推的公钥
  • sshd —— 推完 key 之后关密码登录的服务端配置
  • ansible / ssh-copy-id —— 生产环境的更好替代
在 GitHub 上编辑此页