Shell脚本如何统一修改服务器密码

wen 实用脚本 2

本文目录导读:

Shell脚本如何统一修改服务器密码

  1. 目录导读
  2. 问题背景:为什么需要统一修改服务器密码?
  3. 核心思路:Shell脚本统一修改密码的三种方法
  4. 前置准备:服务器清单、SSH免密登录配置
  5. 方法一:基于expect的交互式密码修改脚本(稳定可靠)
  6. 方法二:基于sshpass的非交互式批量修改(快速高效)
  7. 方法三:结合Ansible(或类似工具)的拓扑扩展
  8. 安全性警示:不可忽视的细节
  9. 常见问题问答(QA)
  10. 总结与最佳实践:自动化运维的演进方向

目录导读

  1. 问题背景:为什么需要统一修改密码?
  2. 核心思路:Shell脚本统一修改密码的三种方法
  3. 前置准备:服务器清单、SSH免密登录配置
  4. 基于expect的交互式密码修改脚本
  5. 基于sshpass的非交互式批量修改
  6. 结合Ansible(或类似工具)的拓扑扩展
  7. 安全性警示:密码复杂度、日志清除与权限控制
  8. 常见问题问答:密码同步失败、密钥失效等场景
  9. 总结与最佳实践:自动化运维的演进方向

问题背景:为什么需要统一修改服务器密码?

在企业运维或安全审计场景中,常常需要定期或紧急统一修改一批服务器的root或管理员密码

  • 安全事件后紧急轮换所有服务器密码
  • 季度合规审计要求密码更新
  • 员工离职后统一重置服务器访问凭证

传统手动登录每台服务器修改密码的方式不仅效率极低(往往耗费数小时甚至数天),而且极易遗漏、输错密码或产生不一致。Shell脚本结合自动化工具成为唯一的可行解。


核心思路:Shell脚本统一修改密码的三种方法

方法 原理 适用场景 依赖
expect 模拟交互式输入密码 通用,兼容性强,但速度较慢 需安装expect
sshpass 非交互式密码传递 快速批量,但密码明文写入脚本 需安装sshpass
Ansible + user模块 声明式配置管理 成熟运维体系;可结合playbook 需部署Ansible管控节点

本文重点讲解最通用的Shell + expectShell + sshpass方法,并给出可直接Copy的脚本。


前置准备:服务器清单、SSH免密登录配置

无论采用哪种方法,都需要一个「服务器IP清单」文件,server_list.txt

168.1.10
192.168.1.11
192.168.1.12

建议在运行脚本前,先配置SSH密钥对免密登录(除非你明确要使用密码认证),配置方法:

ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -N ""
for ip in $(cat server_list.txt); do ssh-copy-id -i ~/.ssh/id_rsa.pub root@$ip; done

🚫 注意:如果原密码不是统一密码,脚本将无法自动登录,此时需配合-o StrictHostKeyChecking=no等参数实现首次连接自动接受指纹。


方法一:基于expect的交互式密码修改脚本(稳定可靠)

脚本文件change_pwd_expect.sh

#!/bin/bash
# 定义新密码(建议外部传入,不硬编码)
NEW_PASSWORD="YourNewP@ssw0rd2024"
# 原密码(若有统一原密码,可在此定义;若无则需逐个指定)
OLD_PASSWORD="OldP@ss123"
# 读取服务器列表
for HOST in $(cat server_list.txt); do
    echo "正在修改 $HOST 的密码..."
    # 使用 expect 自动化交互
    expect << EOF
        set timeout 10
        spawn ssh root@$HOST "echo 'root:$NEW_PASSWORD' | chpasswd"
        expect {
            "password:" {
                send "$OLD_PASSWORD\r"
                exp_continue
            }
            "New password:" {
                send "$NEW_PASSWORD\r"
                exp_continue
            }
            "Retype new password:" {
                send "$NEW_PASSWORD\r"
                exp_continue
            }
            eof {
                puts "密码修改成功: $HOST"
            }
            timeout {
                puts "超时: $HOST"
                exit 1
            }
        }
EOF
done

运行方式

chmod +x change_pwd_expect.sh && ./change_pwd_expect.sh

优点:适用于任何Linux发行版(chpasswd通用),且不依赖额外工具。
缺点:交互过程可能导致速度稍慢;当服务器超过100台时建议增加超时控制。


方法二:基于sshpass的非交互式批量修改(快速高效)

安装sshpass(若未安装):

  • CentOS/RHEL: yum install -y sshpass
  • Ubuntu/Debian: apt-get install -y sshpass
  • macOS: brew install sshpass

脚本文件change_pwd_sshpass.sh

#!/bin/bash
NEW_PASSWORD="YourNewP@ssw0rd2024"
OLD_PASSWORD="OldP@ss123"
for HOST in $(cat server_list.txt); do
    echo "正在修改 $HOST 的密码..."
    sshpass -p "$OLD_PASSWORD" ssh -o StrictHostKeyChecking=no root@$HOST "echo 'root:$NEW_PASSWORD' | chpasswd"
    if [ $? -eq 0 ]; then
        echo "✅ $HOST 密码修改成功"
    else
        echo "❌ $HOST 密码修改失败"
    fi
done

安全建议:切勿在脚本中直接硬编码密码,推荐从环境变量或加密文件中读取,

OLD_PASSWORD=$(cat /tmp/pwd_file | openssl enc -aes-256-cbc -d -pass pass:yourkey)

性能对比:该方法比expect快3~5倍,但前提是目标服务器chpasswd命令可用且初始密码统一。


方法三:结合Ansible(或类似工具)的拓扑扩展

如果你有Ansible环境,可以用一行命令完成:

ansible all -i server_list.txt -m shell -a "echo 'root:{{ new_password }}' | chpasswd" -e "new_password=YourNewP@ssw0rd2024

但请注意:若原密码不统一,需要先在/etc/ansible/hosts中配置ansible_ssh_pass变量,更推荐使用ansible-vault加密密码。


安全性警示:不可忽视的细节

1 密码复杂度与加密

  • 批量修改时,务必将新密码先通过openssl passwd -6生成SHA-512哈希,推荐命令:
    NEW_HASH=$(openssl passwd -6 "YourNewP@ssw0rd2024")
    usermod -p "$NEW_HASH" root
  • 同时在脚本中增加密码强度校验函数,防止弱密码。

2 日志与痕迹清理

  • 修改后立即清除脚本中明文密码痕迹:
    sed -i 's/NEW_PASSWORD=".*"/NEW_PASSWORD="REDACTED"/' change_pwd_sshpass.sh
  • 建议使用script -q -c "ssh root@$HOST '...'"记录日志,但日志文件要加密存储。

3 权限与执行者

  • 脚本所在目录权限应该为700,属主为root。
  • 禁止将脚本放置在/tmp等可写目录。

常见问题问答(QA)

Q1:某台服务器地址变更,脚本失败,怎么快速定位?
A:在循环中增加错误输出重定向:

echo "===== $HOST =====" >> success.log 2>> fail.log

Q2:密码修改后,SSH提示“Permission denied”,但脚本显示成功?
A:原因可能包括:

  • chpasswd未生效(有些发行版需重启SSH服务) → 脚本中加入 systemctl restart sshd
  • 密码中包含特殊字符被shell解析 → 使用单引号包裹密码

Q3:我有2000+台机器,脚本太慢怎么办?
A:采用并行处理:

for HOST in $(cat server_list.txt); do
    (sshpass -p "$OLD_PASSWORD" ssh root@$HOST "..." &)
done
wait

Q4:能否只修改部分服务器的密码(如根据标签)?
A:将服务器列表文件按分组拆分,或在IP前加标签列,用grep筛选。


总结与最佳实践:自动化运维的演进方向

场景 推荐方案
10台以下临时需求 手动+ expect 脚本
10~100台批量修改 sshpass + 密码文件加密
100台以上或长期运维 Ansible + Vault + CI/CD
安全级别极高环境 基于证书认证(彻底免密)或一次性动态密码

最后提醒:不要在任何公开仓库(如GitHub)上传包含明文密码的脚本,如果需要放在代码仓库,务必使用.gitignore排除密码文件,或采用ansible-vaultsops等工具加密。

真正的自动化,不是写了一堆脚本,而是让脚本本身具备可审计、可回溯、可容错的能力。

抱歉,评论功能暂时关闭!