一、使用场景
在进行软件项目的实施部署过程中,经常需要在多个主机节点间登录操作,如果多个主机节点间已经配置了免密登录的话,将会对软件多主机节点实施部署工作效率有很大提高,例如已经免登录配置的服务器可以使用ansible-playbook自动化运维工具进行批量节点操作。那么怎么实现多个主机节点间批量配置免密登录呢?
二、免密配置
基于密钥配置主机192.168.1.1与主机192.168.1.2间的SSH免密登录步骤如下:
1、在192.168.1.1上生成一对密钥(公钥/私钥)
基于空口令使用ssh-keygen工具生成公钥和私钥生成一个新的ssh密钥,以实现无密码登录:
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
2、在192.168.1.1将公钥发送给主机192.168.1.2,使用ssh-copy-id或scp命令:
在主机192.168.1.1上用ssh-copy-id命令:
ssh-copy-id root@192.168.1.2
或者在主机192.168.1.2上使用scp命令:
scp root@192.168.1.1:~/.ssh/id_rsa.pub id_rsa.pub.192.168.1.1 cat id_rsa.pub.192.168.1.1 >>~/.ssh/authorized_keys
注:(1)经过ssh-copy-id后接收公钥的192.168.1.2主机会把公钥追加到对应用户(这里为root)的$HOME/.ssh/authorized_keys文件中;(2)使用scp命令记得需要将id_rsa.pub内容追加到$HOME/.ssh/authorized_keys文件中。
三、批量配置
实现步骤如下:
(1)读取配置文件
(2)本地密钥对不存在则创建密钥
(3)登陆到各个主机上,使用ssh-keygen工具生成公钥和私钥
(4)拷贝将每个主机上的id_rsa.pub拷贝到本地,并汇总至authorized_keys
(5)将本地authorized_keys分发到每个主机上
四、脚本实现
(1)准备配置文件account.txt
192.168.1.1 root 123321 192.168.1.2 root 123321 192.168.1.3 root 123321 192.168.1.4 root 123321
(2)免登录配置脚本 (需要安装 expect)
#!/bin/bash ############################################ # Function : 配置账号免登录(完整版本) # Author : tang # Date : 2020-04-21 # # Usage: sh auto_ssh_login.sh ./account.txt # ############################################ FILENAME=$1 if [ ! -n "$FILENAME" ]; then echo "[ERROR]: no host ip address account file supplied!!!" echo "Usage : $0 [host_ip_account.txt]" exit 1 fi # 读取配置文件 HOSTSADDR=() USERNAMES=() PASSWORDS=() while read line; do if [ ! -n "$line" ]; then break 1 fi ip=$(echo $line | cut -d " " -f1) # 提取文件中的ip地址 user_name=$(echo $line | cut -d " " -f2) # 提取文件中的用户名 pass_word=$(echo $line | cut -d " " -f3) # 提取文件中的密码 #echo "IP:$ip User:$user_name Password:$pass_word" if [ ! -n "$ip" ]; then echo "[ERROR]: File content format error,reason get [ip address] empty" exit 1 fi if [ ! -n "$user_name" ]; then echo "[ERROR]: File content format error,reason get [user name] empty" exit 1 fi if [ ! -n "$pass_word" ]; then echo "[ERROR]: File content format error,reason get [password] empty" exit 1 fi if [ "$ip" == "$user_name" ]; then echo "[ERROR]: File content format error,reason invalid file format" exit 1 fi HOSTSADDR[${#HOSTSADDR[*]}]=$ip USERNAMES[${#USERNAMES[*]}]=$user_name PASSWORDS[${#PASSWORDS[*]}]=$pass_word done <$FILENAME # 本地密钥对不存在则创建密钥 [ ! -f ~/.ssh/id_rsa.pub ] && ssh-keygen -t rsa -p '' &>/dev/null # 首先登陆到各个主机上,使用ssh-keygen工具生成公钥和私钥 echo "#### [1] call ssh-keygen to generate key..." for ((i = 0; i < ${#HOSTSADDR[@]}; i++)); do ip=${HOSTSADDR[$i]} user_name=${USERNAMES[$i]} pass_word=${PASSWORDS[$i]} echo "IP:$ip User:$user_name Password:$pass_word" expect <<EOF spawn ssh $user_name@$ip "rm -rf ~/.ssh; ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa -q" expect { "yes/no" { send "yes ";exp_continue} "password" { send "$pass_word "} } expect eof EOF done # 其次,拷贝将每个主机上的id_rsa.pub拷贝到本地,并汇总至authorized_keys echo "#### [2] copy remote public key to local..." TMP_AUTHORIZED_KEYS="./.id_rsa.pub.$ip.tmp" for ((i = 0; i < ${#HOSTSADDR[@]}; i++)); do ip=${HOSTSADDR[$i]} user_name=${USERNAMES[$i]} pass_word=${PASSWORDS[$i]} echo "IP:$ip User:$user_name Password:$pass_word" TMP_FILE="./.id_rsa.pub.$ip.tmp" expect <<EOF spawn scp $user_name@$ip:~/.ssh/id_rsa.pub $TMP_FILE expect { "yes/no" { send "yes ";exp_continue} "password" { send "$pass_word "} } expect eof EOF cat $TMP_FILE >>~/.ssh/authorized_keys rm -f $TMP_FILE done # 最后,将本地authorized_keys分发到每个主机上 echo "#### [3] send local key to each host..." for ((i = 0; i < ${#HOSTSADDR[@]}; i++)); do ip=${HOSTSADDR[$i]} user_name=${USERNAMES[$i]} pass_word=${PASSWORDS[$i]} echo "IP:$ip User:$user_name Password:$pass_word" CMD="scp /root/.ssh/authorized_keys root@$ip:/root/.ssh/authorized_keys" if [ "$user_name" != "root" ]; then CMD="scp /home/$user_name/.ssh/authorized_keys $user_name@$ip:/home/$user_name/.ssh/authorized_keys" fi expect <<EOF spawn $CMD expect { "yes/no" { send "yes ";exp_continue} "password" { send "$pass_word "} } expect eof EOF done echo "[INFO]: config auto ssh success!"