使用脚本、工具批量操作服务器做免密登录及修改密码

  • 生产实践:

    使用脚本、工具批量操作服务器做免密及修改密码

  • 学习技巧:

    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
-tSSH超时时间(秒),如 -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. 可选:更安全的密码管理

为了更安全地管理密码,建议:

  1. 使用Ansible Vault加密密码

  2. 创建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' }

注意事项

  1. 敏感信息及密码策略

    • 永远不要将密码明文存储在脚本或历史记录中

    • 使用密码管理器或加密配置文件

    • 考虑使用ansible-vault等工具加密敏感数据

    • 服务器列表文件包含明文密码,处理完毕后应立即删除

    • 确保新密码符合安全策略(如包含特殊字符、长度≥12)

    • 定期更换密码

  2. 最小权限原则要求

    • .ssh 目录权限必须为 700

    • authorized_keys 文件权限必须为 600

    • 不要使用root账户,除非绝对必要,为服务创建专用账户

    • 记录所有批量操作,定期检查服务器登录日志

    • 目标主机用户必须有 sudo 权限且配置了免密码sudo:

      # 在目标主机上执行:
      echo "$(whoami) ALL=(ALL) NOPASSWD: /usr/bin/chpasswd" | sudo tee /etc/sudoers.d/password_change
  3. 网络隔离

    • 操作期间确保网络环境安全(防止密码被截获)

    • 确保所有目标主机 SSH 端口开放(默认22)

    • 首次连接需接受主机密钥时,添加 -O StrictHostKeyChecking=no


参考:

anzhihe 安志合个人博客,版权所有 丨 如未注明,均为原创 丨 转载请注明转自:https://chegva.com/6406.html | ☆★★每天进步一点点,加油!★★☆ | 

您可能还感兴趣的文章!

发表评论

电子邮件地址不会被公开。 必填项已用*标注