生产实践:
使用脚本、工具批量操作服务器做免密及修改密码
学习技巧:
Shell 脚本、sshpass、parallel-ssh及ansible工具使用
脚本内容:
使用脚本、工具批量操作服务器做免密及修改密码,常用于服务器初始化及批量操作。
一、sshpass使用
1、确保本地机器已安装sshpass
工具
apt install sshpass # Ubuntu/Debian yum install sshpass # CentOS/RHEL
2、准备服务器列表文件(如servers.txt),格式为:用户名@IP地址:端口 密码
例如:
root@192.168.1.100:22 password1 admin@192.168.1.101:2222 password2
批量配置SSH免密登录
#!/bin/bash # 生成SSH密钥对(如果尚未生成) if [ ! -f ~/.ssh/id_rsa ]; then ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa fi # 读取服务器列表 while read line; do # 提取信息 server=$(echo $line | cut -d' ' -f1) password=$(echo $line | cut -d' ' -f2) # 分离用户名、IP和端口 user=$(echo $server | cut -d'@' -f1) ip_port=$(echo $server | cut -d'@' -f2) ip=$(echo $ip_port | cut -d':' -f1) port=$(echo $ip_port | cut -d':' -f2) port=${port:-22} # 默认SSH端口22 echo "正在配置 $user@$ip:$port ..." # 使用sshpass复制公钥到远程服务器 sshpass -p "$password" ssh-copy-id -o StrictHostKeyChecking=no -p $port $user@$ip # 测试免密登录 ssh -p $port $user@$ip "echo 'SSH免密登录配置成功!'" echo "$user@$ip:$port 配置完成" echo "------------------------------------" done < servers.txt
批量修改服务器密码
#!/bin/bash # 读取新密码 read -s -p "请输入新密码: " new_password echo read -s -p "再次确认新密码: " new_password_confirm echo if [ "$new_password" != "$new_password_confirm" ]; then echo "两次输入的密码不一致,请重试!" exit 1 fi # 读取服务器列表 while read line; do # 提取信息 server=$(echo $line | cut -d' ' -f1) old_password=$(echo $line | cut -d' ' -f2) # 分离用户名、IP和端口 user=$(echo $server | cut -d'@' -f1) ip_port=$(echo $server | cut -d'@' -f2) ip=$(echo $ip_port | cut -d':' -f1) port=$(echo $ip_port | cut -d':' -f2) port=${port:-22} # 默认SSH端口22 echo "正在修改 $user@$ip:$port 的密码..." # 使用sshpass登录并修改密码 sshpass -p "$old_password" ssh -o StrictHostKeyChecking=no -p $port $user@$ip \ "echo -e '$old_password\n$new_password\n$new_password' | passwd" # 测试新密码 sshpass -p "$new_password" ssh -o StrictHostKeyChecking=no -p $port $user@$ip \ "echo '密码修改成功!'" echo "$user@$ip:$port 密码修改完成" echo "------------------------------------" done < servers.txt
二、parallel-ssh使用
1、确保本地机器已安装parallel-ssh
工具
apt install pssh # Ubuntu/Debian yum install pssh # CentOS/RHEL # 手动编译安装 # 下载源码 wget https://github.com/lilydjwg/pssh/archive/refs/tags/v2.3.1.tar.gz tar xvf v2.3.1.tar.gz cd pssh-2.3.1 # 安装依赖和编译 apt install python3-setuptools python3 setup.py install
2、parallel-ssh基本语法及使用
parallel-ssh [选项] -H "主机1 主机2 ..." -i "要执行的命令"
核心参数说明
参数 | 作用 |
---|---|
-H | 指定主机列表(用空格分隔),如 -H "user@host1 user@host2" |
-h | 从文件读取主机列表(每行一个主机),如 -h hosts.txt |
-i | 实时显示命令输出(交互模式) |
-l | 指定远程主机的用户名,如 -l root |
-A | 手动输入SSH密码(默认使用密钥认证) |
-p | 并发连接数(默认32),如 -p 10 |
-t | SSH超时时间(秒),如 -t 15 |
-o | 将输出保存到指定目录(每主机一个文件),如 -o /tmp/output |
-O | 指定SSH配置选项(如 -O StrictHostKeyChecking=no 跳过主机密钥检查) |
-x | 传递额外的SSH参数,如 -x "-o ConnectTimeout=5","-p 2222" |
-v | 显示详细错误信息 |
相关工具
parallel-scp
:批量上传文件到多台主机。parallel-rsync
:使用rsync协议批量同步文件。parallel-slurp
:从多台主机下载文件。parallel-nuke
:批量终止远程进程。
批量配置SSH免密登录
步骤1:生成SSH密钥对(控制机)
若尚未生成密钥,执行:
ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa
-N ""
:设置空密码(根据需求可选是否加密密钥)。生成的密钥对:
~/.ssh/id_rsa
(私钥)和~/.ssh/id_rsa.pub
(公钥)。
步骤2:创建主机列表文件
将目标主机 IP 或域名写入文件 hosts.txt
,每行一个:
echo -e "192.168.1.101\n192.168.1.102\n192.168.1.103" > hosts.txt 或者 seq -f "192.168.1.%01g" 101 103 > hosts.txt
步骤3:批量推送公钥
使用 parallel-ssh
或 parallel-scp
结合命令完成公钥分发:
方法1:直接追加公钥到目标主机
# 使用 pssh 执行远程命令(需输入密码) parallel-ssh -h hosts.txt -l <用户名> -A -i \ "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo $(cat ~/.ssh/id_rsa.pub) >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
-l <用户名>
:替换为目标主机的 SSH 用户名。-A
:提示手动输入密码(所有主机密码需相同)。命令分解:
mkdir -p ~/.ssh
:创建目录(若不存在)。chmod 700 ~/.ssh
:设置目录权限。echo 公钥内容 >> ~/.ssh/authorized_keys
:追加公钥。chmod 600 ~/.ssh/authorized_keys
:设置文件权限。
方法2:通过临时文件上传(更安全)
# 1. 将公钥复制到临时文件 cat ~/.ssh/id_rsa.pub > /tmp/my_key.pub # 2. 上传公钥文件到目标主机 parallel-scp -h hosts.txt -l <用户名> -A /tmp/my_key.pub /tmp/ # 3. 追加公钥到 authorized_keys 并修复权限 parallel-ssh -h hosts.txt -l <用户名> -A -i \ "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat /tmp/my_key.pub >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && rm /tmp/my_key.pub"
步骤4:验证免密登录
# 随机挑选一台主机测试 parallel-ssh -h hosts.txt -l <用户名> -i "hostname" ln -s /usr/bin/paraller-ssh /usr/local/bin/pssh pssh -h hosts.txt -i "ifconfig eth0 | grep netmask | awk '{print \$2;system(\"cat /etc/hostname\")}' | xargs"
若无需输入密码且返回主机名,则配置成功!
批量配置SSH免密登录
将以下脚本保存为 auto_ssh_keys.sh
,替换 <用户名>
并赋予执行权限:
#!/bin/bash USER="<用户名>" # 替换为目标主机的用户名 HOSTS_FILE="hosts.txt" # 生成密钥对(若不存在) if [ ! -f ~/.ssh/id_rsa.pub ]; then ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa fi # 分发公钥 cat ~/.ssh/id_rsa.pub > /tmp/ssh_temp.pub parallel-scp -h $HOSTS_FILE -l $USER -A /tmp/ssh_temp.pub /tmp/ parallel-ssh -h $HOSTS_FILE -l $USER -A -i \ "mkdir -p ~/.ssh && chmod 700 ~/.ssh && \ cat /tmp/ssh_temp.pub >> ~/.ssh/authorized_keys && \ chmod 600 ~/.ssh/authorized_keys && \ rm /tmp/ssh_temp.pub" # 清理临时文件 rm /tmp/ssh_temp.pub # 验证 echo "验证免密登录:" parallel-ssh -h $HOSTS_FILE -l $USER -i "echo 'SSH免密配置成功!'"
批量修改服务器密码
#!/bin/bash HOSTS_FILE="hosts.txt" GPG_PASSPHRASE="YourGPGPassphrase" # 替换为你的GPG密码 # 生成随机密码函数 generate_password() { tr -dc 'A-Za-z0-9!@#$%^&*' < /dev/urandom | head -c 16 } # 修改密码并记录 while read host; do USER=$(whoami) # 或从hosts.txt解析用户名 NEW_PASS=$(generate_password) echo "修改 $host 的密码..." # 执行修改(需sudo权限) parallel-ssh -H "$host" -i \ "echo '$USER:$NEW_PASS' | sudo chpasswd" && \ echo "$host:$USER:$NEW_PASS" >> /tmp/temp_passwords.txt # 检查是否成功 if [ $? -eq 0 ]; then echo "[SUCCESS] $host 密码已更新" else echo "[FAILED] $host 密码修改失败" fi done < "$HOSTS_FILE" # 加密存储密码文件 gpg -c --batch --passphrase "$GPG_PASSPHRASE" /tmp/temp_passwords.txt && \ mv /tmp/temp_passwords.txt.gpg ./server_passwords.gpg && \ rm /tmp/temp_passwords.txt echo "所有主机密码已更新,加密文件:server_passwords.gpg"
gpg加解密使用:
-d
:解密模式。-o
:指定输出文件名。--batch
:非交互式(避免提示)。--passphrase
:直接提供密码(安全性较低,仅用于测试)。
# 加解密 echo "新密码: 111111" | gpg -c --batch --passphrase "123456" > passwords.gpg gpg -o decrypted_file.txt --decrypt passwords.gpg # 解密后自动处理内容 gpg --batch --passphrase "YourGPGPassphrase" -d passwords.gpg | while read -r line; do host=$(echo "$line" | cut -d':' -f1) user=$(echo "$line" | cut -d':' -f2) pass=$(echo "$line" | cut -d':' -f3) echo "主机 $host 的用户 $user 密码已提取" done
三、ansible使用
批量配置SSH免密登录及修改服务器密码
1. 准备工作
首先确保:
已安装Ansible
所有目标机器可以通过SSH访问(使用密码或现有密钥)
有一个inventory文件列出所有目标机器
示例inventory文件 (hosts.ini
):
[servers] server1 ansible_host=192.168.1.101 server2 ansible_host=192.168.1.102 server3 ansible_host=192.168.1.103 [servers:vars] ansible_user=admin ansible_ssh_pass=oldpassword # 或者使用现有的SSH密钥
2. 创建Ansible playbook
创建 setup_ssh_trust.yml
文件:
--- - name: Setup SSH mutual trust and change user password hosts: servers become: yes vars: # 定义变量 new_password: "NewSecurePassword123!" # 要设置的新密码 ssh_key_path: "/home/{{ ansible_user }}/.ssh/id_rsa" ssh_pubkey_path: "{{ ssh_key_path }}.pub" authorized_keys_path: "/home/{{ ansible_user }}/.ssh/authorized_keys" tasks: # 任务1: 确保openssh-client已安装 - name: Ensure openssh-client is installed apt: name: openssh-client state: present when: ansible_os_family == 'Debian' - name: Ensure openssh-clients is installed (RedHat) yum: name: openssh-clients state: present when: ansible_os_family == 'RedHat' # 任务2: 生成SSH密钥对(如果不存在) - name: Generate SSH key pair if not exists become_user: "{{ ansible_user }}" community.crypto.openssh_keypair: path: "{{ ssh_key_path }}" type: rsa size: 2048 force: no # 不覆盖现有密钥 # 任务3: 收集所有主机的公钥 - name: Gather public keys from all hosts run_once: yes delegate_to: localhost block: - name: Create temp directory for keys tempfile: state: directory suffix: ansible_ssh_keys register: keys_tempdir - name: Fetch public keys from all hosts fetch: src: "{{ ssh_pubkey_path }}" dest: "{{ keys_tempdir.path }}/{{ inventory_hostname }}.pub" flat: yes delegate_to: "{{ item }}" loop: "{{ groups['servers'] }}" # 任务4: 创建包含所有主机公钥的authorized_keys文件 - name: Create combined authorized_keys file run_once: yes delegate_to: localhost vars: combined_keys_path: "{{ keys_tempdir.path }}/authorized_keys_combined" block: - name: Combine all public keys assemble: src: "{{ keys_tempdir.path }}" dest: "{{ combined_keys_path }}" regexp: ".*\.pub$" # 任务5: 分发组合的authorized_keys文件到所有主机 - name: Distribute authorized_keys to all hosts copy: src: "{{ combined_keys_path }}" dest: "{{ authorized_keys_path }}" owner: "{{ ansible_user }}" group: "{{ ansible_user }}" mode: '0600' delegate_to: localhost run_once: yes become: no - name: Push authorized_keys to each host copy: content: "{{ lookup('file', combined_keys_path) }}" dest: "{{ authorized_keys_path }}" owner: "{{ ansible_user }}" group: "{{ ansible_user }}" mode: '0600' become: yes become_user: "{{ ansible_user }}" # 任务6: 确保SSH目录权限正确 - name: Ensure .ssh directory permissions file: path: "/home/{{ ansible_user }}/.ssh" state: directory owner: "{{ ansible_user }}" group: "{{ ansible_user }}" mode: '0700' # 任务7: 修改用户密码 - name: Change user password user: name: "{{ ansible_user }}" password: "{{ new_password | password_hash('sha512') }}" update_password: always
3. 执行Playbook
运行以下命令执行配置:
ansible-playbook -i hosts.ini setup_ssh_trust.yml
4. 验证SSH互信
执行完成后,可以验证任意两台机器之间是否可以实现SSH免密登录:
ansible all -i hosts.ini -m ping
或者手动测试:
ssh admin@server1 hostname
5. 可选:更安全的密码管理
为了更安全地管理密码,建议:
使用Ansible Vault加密密码
创建vault加密的变量文件
创建加密的变量文件:
ansible-vault create vars/secrets.yml
内容示例:
new_password: "NewSecurePassword123!"
然后修改playbook,移除vars部分,改为:
vars_files: - vars/secrets.yml
然后使用以下命令运行playbook:
ansible-playbook -i hosts.ini setup_ssh_trust.yml --ask-vault-pass
其它操作
# ssh互信 ansible ssh-host -m authorized_key -a "user=root state=present key=\"{{ lookup('file', '/root/.ssh/id_rsa.pub') }} \"" -k --- - hosts: ssh-host user: root tasks: - name: sshkey-copy authorized_key: user=root key="{{ lookup('file', '/root/.ssh/id_rsa.pub') }}" - hosts: group_name tasks: - name: Enable SSH passwordless login authorized_key: user: user state: present key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" # 修改密码并配置sudoer - hosts: '{{ host_list }}' gather_facts: false vars: user: anzhihe password: "an39DWP6ZDwC." #python -c 'import crypt;print(crypt.crypt("anzhihe@2025","anzhihe"))' tasks: - name: adduser for anzhihe user: name={{ user }} comment="add debug user:anzhihe" password={{ password }} - name: Config /etc/sudoers lineinfile: dest=/etc/sudoers state=present line='{{ item }}' validate='visudo -cf %s' with_items: - "{{ user }} ALL=(ALL) NOPASSWD: ALL" - "Defaults: {{ user }} !requiretty" - name: check user shell: id anzhihe && grep anzhihe /etc/sudoers #ignore_errors: True - name: copy sudo file to remote host copy: src=/scripts/sudofile dest=/tmp/sudofile - name: attach sudofile to /etc/sudoers shell: cat /tmp/sudofile >> /etc/sudoers # 批量修改不同用户密码 --- - hosts: ssh-host gather_facts: false tasks: - name: change user passwd user: name={{ item.name }} password={{ item.chpass | password_hash('sha512') }} update_password=always with_items: - { name: 'root', chpass: 'kevin@123' } - { name: 'app', chpass: 'bjop123' } # 指定主机修改用户密码 # 需要注意脚本中"ens192"是客户机ip所在的网卡设备名称, 这个要根据自己实际环境去配置, 比如eth0, eth1等 - hosts: test-host remote_user: root tasks: - name: change password for root shell: echo '{{ item.password }}' |passwd --stdin root when: ansible_ens192.ipv4.address == '{{ item.ip }}' with_items: - { ip: "172.16.60.220", password: 'haha@123' } - { ip: "172.16.60.221", password: 'kevin@123' } - { ip: "172.16.60.222", password: 'bobo@123' }
注意事项
敏感信息及密码策略:
永远不要将密码明文存储在脚本或历史记录中
使用密码管理器或加密配置文件
考虑使用
ansible-vault
等工具加密敏感数据服务器列表文件包含明文密码,处理完毕后应立即删除
确保新密码符合安全策略(如包含特殊字符、长度≥12)
定期更换密码
最小权限原则要求:
.ssh
目录权限必须为700
authorized_keys
文件权限必须为600
不要使用root账户,除非绝对必要,为服务创建专用账户
记录所有批量操作,定期检查服务器登录日志
目标主机用户必须有
sudo
权限且配置了免密码sudo:# 在目标主机上执行: echo "$(whoami) ALL=(ALL) NOPASSWD: /usr/bin/chpasswd" | sudo tee /etc/sudoers.d/password_change
网络隔离:
操作期间确保网络环境安全(防止密码被截获)
确保所有目标主机 SSH 端口开放(默认22)
首次连接需接受主机密钥时,添加
-O StrictHostKeyChecking=no
。
参考: