
告别手动输入密码用Linux Expect脚本批量管理服务器5分钟搞定SSH免密登录每次面对几十台新服务器需要配置SSH免密登录时手动逐台输入密码就像在键盘上跑马拉松。我曾亲眼目睹同事因为输错一个字符不得不重头开始整个流程的绝望表情。这种重复劳动不仅消耗时间更消磨工程师的创造力。Expect脚本正是为解放双手而生。它能模拟人类交互行为自动处理密码输入、首次连接确认等繁琐步骤。结合Shell循环我们可以在5分钟内完成过去需要数小时的工作。更重要的是这套方案具备生产级可靠性——错误重试机制、超时控制、日志记录一应俱全。1. 环境准备与基础配置1.1 安装Expect工具链主流Linux发行版通常只需一条命令即可完成安装。对于基于RPM的系统sudo yum install -y expect tclDebian/Ubuntu用户则使用sudo apt-get update sudo apt-get install -y expect验证安装是否成功which expect expect -v1.2 服务器清单规范化管理创建server_list.txt文件管理目标服务器信息建议采用以下格式192.168.1.101 root Pssw0rd1 192.168.1.102 admin Secure#123 10.0.0.15 ubuntu Ubuntu!2023各字段含义IP地址服务器网络标识用户名SSH登录账号密码对应账号的认证凭证安全提示务必设置该文件权限为600避免密码泄露chmod 600 server_list.txt2. 核心脚本开发2.1 基础版免密登录脚本创建auto_ssh_copy_id.exp文件#!/usr/bin/expect set ip [lindex $argv 0] set user [lindex $argv 1] set password [lindex $argv 2] set timeout 15 spawn ssh-copy-id $user$ip expect { # 处理首次连接确认 yes/no { send yes\r exp_continue } # 匹配密码提示 password: { send $password\r } # 处理已存在密钥的情况 already exist { send_user Key already exists on $ip\n exit 0 } timeout { send_user Connection to $ip timed out\n exit 1 } } expect { Now try logging into the machine { send_user Successfully configured $ip\n } eof }2.2 增强版批量处理脚本创建batch_ssh_setup.sh作为主控脚本#!/bin/bash LOG_FILEssh_setup_$(date %Y%m%d).log SERVER_LISTserver_list.txt { echo Batch SSH Setup Started at $(date) total$(wc -l $SERVER_LIST) success0 fail0 while read -r line || [[ -n $line ]]; do ip$(echo $line | awk {print $1}) user$(echo $line | awk {print $2}) password$(echo $line | awk {print $3}) echo Processing $ip... if ./auto_ssh_copy_id.exp $ip $user $password; then echo $ip: Configuration successful | tee -a $LOG_FILE ((success)) else echo $ip: Configuration failed | tee -a $LOG_FILE ((fail)) fi done $SERVER_LIST echo Summary echo Total servers: $total echo Success: $success echo Failed: $fail echo Detailed log saved to $LOG_FILE } | tee -a $LOG_FILE3. 生产环境增强策略3.1 多因素错误处理机制完善后的Expect脚本应包含以下容错措施#!/usr/bin/expect set max_retry 3 set retry_count 0 set ip [lindex $argv 0] set user [lindex $argv 1] set password [lindex $argv 2] set timeout 20 proc attempt_connection {} { global ip user password retry_count max_retry spawn ssh-copy-id $user$ip expect { yes/no { send yes\r exp_continue } password: { send $password\r exp_continue } Now try logging into the machine { return 0 } Permission denied { if {$retry_count $max_retry} { incr retry_count send_user Retry $retry_count for $ip\n attempt_connection } else { return 1 } } timeout { if {$retry_count $max_retry} { incr retry_count send_user Timeout, retry $retry_count for $ip\n attempt_connection } else { return 1 } } eof } } set result [attempt_connection] if {$result 0} { send_user Successfully configured SSH for $ip\n exit 0 } else { send_user Failed to configure SSH for $ip after $max_retry attempts\n exit 1 }3.2 性能优化技巧当处理大规模服务器集群时考虑以下优化方案优化方向具体措施预期效果并行处理使用GNU parallel或xargs -P参数减少总执行时间连接复用配置SSH ControlMaster降低连接建立开销密钥分发预先生成密钥对并分发避免重复生成密钥网络优化检查并优化网络路由提高传输速度日志分级实现DEBUG/INFO/WARN级别日志便于问题排查并行处理示例cat server_list.txt | parallel -j 10 ./auto_ssh_copy_id.exp {1} {2} {3} :::: -4. 安全与维护最佳实践4.1 安全加固方案密码管理改进使用Ansible Vault或HashiCorp Vault加密存储密码采用临时令牌替代固定密码访问控制强化# 限制SSH密钥使用范围 echo from192.168.1.0/24 ssh-rsa AAAAB3Nza... ~/.ssh/authorized_keys审计日志配置# 记录SSH登录事件 echo SyslogFacility AUTHPRIV /etc/ssh/sshd_config echo LogLevel VERBOSE /etc/ssh/sshd_config4.2 日常维护脚本创建定期检查脚本verify_ssh_access.sh#!/bin/bash SERVER_LISTserver_list.txt TIMEOUT5 CHECK_COMMANDhostname while read -r line; do ip$(echo $line | awk {print $1}) user$(echo $line | awk {print $2}) if ssh -o ConnectTimeout$TIMEOUT -o BatchModeyes $user$ip $CHECK_COMMAND /dev/null 21; then echo $ip: SSH access OK else echo $ip: SSH access FAILED fi done $SERVER_LIST在实际运维中这套方案将服务器初始化时间从平均3小时缩短到5分钟。有个细节值得注意当处理超过50台服务器时建议将超时时间调整为30秒以上避免网络波动导致批量失败。