Shell脚本如何批量推送SSH公钥

wen 实用脚本 2

本文目录导读:

Shell脚本如何批量推送SSH公钥

  1. 方法1:使用 ssh-copy-id 命令(推荐)
  2. 方法2:使用 expect 实现交互式推送
  3. 方法3:使用循环 + ssh 命令手动创建
  4. 方法4:使用 Ansible(生产环境推荐)
  5. 安全建议

我来介绍几种批量推送SSH公钥的方法:

方法1:使用 ssh-copy-id 命令(推荐)

创建批量推送脚本 batch-ssh-copy.sh

#!/bin/bash
# 主机列表文件格式: user@host:port
HOSTS_FILE="hosts.txt"
SSH_KEY="${HOME}/.ssh/id_rsa.pub"
SSH_PASSWORD="your_password_here"
# 检查必要文件
if [ ! -f "$HOSTS_FILE" ]; then
    echo "错误:主机列表文件 $HOSTS_FILE 不存在"
    echo "格式:user@host:port 或 user@host"
    exit 1
fi
if [ ! -f "$SSH_KEY" ]; then
    echo "错误:SSH公钥文件 $SSH_KEY 不存在"
    exit 1
fi
# 安装 sshpass(如果需要密码认证)
if ! command -v sshpass &> /dev/null; then
    echo "正在安装 sshpass..."
    if [[ "$OSTYPE" == "darwin"* ]]; then
        brew install hudochenkov/sshpass/sshpass
    else
        apt-get install -y sshpass || yum install -y sshpass
    fi
fi
# 读取主机列表并批量推送
while IFS= read -r line; do
    # 跳过注释和空行
    [[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
    # 解析主机信息
    if [[ "$line" == *":"* ]]; then
        user_host="${line%:*}"
        port="${line##*:}"
    else
        user_host="$line"
        port="22"
    fi
    echo "正在推送公钥到: $user_host (端口: $port)"
    # 推送公钥
    sshpass -p "$SSH_PASSWORD" ssh-copy-id \
        -i "$SSH_KEY" \
        -p "$port" \
        -o StrictHostKeyChecking=no \
        "$user_host" 2>&1
    if [ $? -eq 0 ]; then
        echo "✓ 成功: $user_host"
    else
        echo "✗ 失败: $user_host"
    fi
    echo "---"
done < "$HOSTS_FILE"
echo "批量推送完成!"

hosts.txt 文件格式示例:

# 格式:user@host:port 或 user@host
root@192.168.1.10:2222
admin@192.168.1.11
deploy@192.168.1.12:2222

方法2:使用 expect 实现交互式推送

安装 expect:

# Ubuntu/Debian
apt-get install expect
# CentOS/RHEL
yum install expect

创建脚本 ssh-copy-expect.sh

#!/bin/bash
HOSTS_FILE="hosts.txt"
SSH_KEY="${HOME}/.ssh/id_rsa.pub"
PASSWORD="your_password"
if [ ! -f "$HOSTS_FILE" ]; then
    echo "错误:主机列表文件不存在"
    exit 1
fi
# 读取主机列表
while IFS= read -r host; do
    [[ "$host" =~ ^#.*$ || -z "$host" ]] && continue
    echo "处理主机: $host"
    # 使用 expect 自动交互
    expect << EOF
    set timeout 10
    spawn ssh-copy-id -i $SSH_KEY $host
    expect {
        "yes/no" { send "yes\r"; exp_continue }
        "password:" { send "$PASSWORD\r" }
        "Permission denied" { exit 2 }
        eof
    }
    expect eof
    catch wait result
    exit [lindex \$result 3]
EOF
    if [ $? -eq 0 ]; then
        echo "✓ 成功: $host"
    else
        echo "✗ 失败: $host"
    fi
done < "$HOSTS_FILE"
echo "完成!"

方法3:使用循环 + ssh 命令手动创建

#!/bin/bash
# 服务器列表
HOSTS=(
    "root@192.168.1.10:2222"
    "admin@192.168.1.11"
    "deploy@192.168.1.12"
)
PUBLIC_KEY=$(cat ~/.ssh/id_rsa.pub)
PASSWORD="your_password"
for host_info in "${HOSTS[@]}"; do
    # 解析主机信息
    IFS=':' read -r host port <<< "$host_info"
    port=${port:-22}
    echo "推送到: $host (端口: $port)"
    # 创建 .ssh 目录并设置权限
    sshpass -p "$PASSWORD" ssh -p "$port" -o StrictHostKeyChecking=no "$host" \
        "mkdir -p ~/.ssh && chmod 700 ~/.ssh" 2>&1
    # 添加公钥
    sshpass -p "$PASSWORD" ssh -p "$port" "$host" \
        "echo '$PUBLIC_KEY' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys" 2>&1
    if [ $? -eq 0 ]; then
        echo "✓ 成功: $host"
    else
        echo "✗ 失败: $host"
    fi
done

方法4:使用 Ansible(生产环境推荐)

创建 inventory.ini

[servers]
server1 ansible_host=192.168.1.10 ansible_user=root ansible_port=2222
server2 ansible_host=192.168.1.11 ansible_user=admin
server3 ansible_host=192.168.1.12 ansible_user=deploy
[servers:vars]
ansible_ssh_pass=your_password
ansible_ssh_common_args='-o StrictHostKeyChecking=no'

创建 push-keys.yml

---
- name: 批量推送SSH公钥
  hosts: servers
  gather_facts: no
  tasks:
    - name: 确保 .ssh 目录存在
      file:
        path: ~/.ssh
        state: directory
        mode: '0700'
    - name: 添加公钥到 authorized_keys
      authorized_key:
        user: "{{ ansible_user }}"
        state: present
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

运行:

ansible-playbook -i inventory.ini push-keys.yml

安全建议

  1. 使用密钥认证:尽量避免明文密码

  2. 限制权限

    chmod 600 ~/.ssh/authorized_keys
    chmod 700 ~/.ssh
    chmod 600 script.sh  # 如果脚本包含密码
  3. 使用配置文件:考虑使用 ~/.ssh/config

    Host server1
        HostName 192.168.1.10
        Port 2222
        User root
        IdentityFile ~/.ssh/id_rsa
  4. 日志记录:添加操作日志

    LOG_FILE="ssh_push_$(date +%Y%m%d_%H%M%S).log"
    # 在脚本中使用 tee 记录日志
    echo "信息" | tee -a "$LOG_FILE"

选择最适合你场景的方法,推荐优先使用方法1或方法4(生产环境)。

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