背景介绍
企业A新入职了一位资深网络管理专家,经过一周的了解,发现公司现在的网络情况非常糟糕,所有的同事都可以从线下办公网访问线上生产服务器进行操作,有稳定性风险。现在网络组要进行网络权限隔离,使线下不能直接访问线上,影响运维的日常生产问题排查。于是,组长和网络管理人员对此事进行沟通,最终结论是网络组给运维组开放一个访问入口,让运维组申请2台服务器作为中控机并申请办公网访问权限,以后访问生产的机器都要先登录任意一台中控机,然后在SSH到目标主机上。
解决方案
现在线上有500台服务器,如果每次排查问题都从中控机上手动输入密码非常影响效率。现在需要开发批量分发秘钥的脚本,实现SSH免密登录。
基础环境
两台服务器,一台模拟中控机,一台模拟生产机器,操作系统Linux,发行版本不限制。
假设中控机IP地址是10.0.1.67,生产机器是10.0.1.66
环境准备好后,先生成ssh秘钥
# -q: 安静模式
# -t: 指定秘钥算法
# -b: 秘钥长度
# -C: 注释
# -f: 生成的秘钥对文件名
ssh-keygen -q -t rsa -b 4096 -C 'zhushiyang@ops.com' -f /root/.ssh/id_rsa -P ''
然后准备ipfile.list文件,每行一个IP地址
# 这里要更新地址,10.0.1.68是不存在的地址
cat >ipfile.list << EOF
10.0.1.68
10.0.1.66
EOF
脚本内容
文件名:ssh_distribution.sh
#!/bin/bash
#######################################
# 脚本名称: ssh_distribution.sh
# 脚本版本: v1.0
# 功能描述: ssh秘钥批量自动分发
# 参数说明: sh ssh_distribution.sh
# 核心逻辑: 从文件中读取IP地址,先检测
# 连通性,然后进行秘钥分发
# 依赖工具: sshpass|ssh-copy-id|ssh-keygen
# 脚本作者: shiyang.zhu
# 联系邮箱: zhushiyang@ops.com
# 创建时间: 2023-03-13
#######################################
#######################################
# 全局变量:
# SCRIPT_DIR 脚本所在目录
# SCRIPT_NAME 脚本名称
# LOG_DIR 日志目录
# LOG_FILE 日志文件
# IP_FILE 每行一个IP地址
# CMD_SSHCOPYID ssh-copy-id命令
# SSH_PUBLIC_KEY ssh公钥
# SSH_PORT ssh端口
# SSH_PASS ssh密码
#######################################
SCRIPT_DIR=$(dirname $(readlink -f "$0"))
SCRIPT_NAME="$0"
LOG_DIR=/var/log/shell/${SCRIPT_NAME}
LOG_FILE=${LOG_DIR}/$(date +%Y-%m-%d).log
IP_FILE="${SCRIPT_DIR}/ipfile.list"
CMD_SSHCOPYID="/usr/bin/ssh-copy-id"
CMD_SSHPASS="/usr/bin/sshpass"
SSH_PUBLIC_KEY="/root/.ssh/id_rsa.pub"
SSH_PORT="22"
SSH_PASS="toor"
[ ! -d ${LOG_DIR} ] && mkdir -p ${LOG_DIR}
# 错误日志函数
function err_log() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: [ERROR] $@" |tee -a ${LOG_FILE}
}
# 正常日志函数
function log(){
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: [INFO] $@" |tee -a ${LOG_FILE}
}
#######################################
# 依赖命令检查函数
# 局部变量:
# CMDS: 依赖命令列表,使用空格分隔
#######################################
function check_cmd(){
local CMDS="sshpass"
for CMD in ${CMDS};do
local CHECK_RESULT=$(rpm -qa ${CMD}|wc -l)
if [[ ${CHECK_RESULT} -eq 0 ]];then
err_log "${CMD}命令不存在,请手动进行安装: yum install -y ${CMD}!"
fi
done
}
check_cmd
# 判断${IP_FILE}是否存在
if [ ! -f ${IP_FILE} ];then
err_log "${IP_FILE}不存在"
exit 1
fi
# 判断${SSH_PUBLIC_KEY}是否存在
if [ ! -f ${SSH_PUBLIC_KEY} ];then
err_log "${SSH_PUBLIC_KEY}不存在"
exit 1
fi
#######################################
# SSH秘钥批量自动分发
# 局部变量:
# IPADDR: IP地址
# CHECK_RESULT_CODE: 探活状态码
# DIST_RESULT_CODE: 分发结果
#######################################
function sshDistribution(){
local IPADDR="$1"
local CHECK_RESULT_CODE=$(ping -c 2 ${IPADDR} >/dev/null;echo $?)
if [ "${CHECK_RESULT_CODE}" = "0" ];then
# -i: 公钥文件
# -p: SSH端口号
# -o stricthostkeychecking=no: 关闭首次Yes检查
local DIST_RESULT_CODE=$("${CMD_SSHPASS}" -p "${SSH_PASS}" "${CMD_SSHCOPYID}" -i "${SSH_PUBLIC_KEY}" \
-p "${SSH_PORT}" -o "stricthostkeychecking=no" root@${IPADDR} >/dev/null 2>&1; echo $?)
if [ "${DIST_RESULT_CODE}" = "0" ];then
log "主机${IPADDR}秘钥分发成功"
else
err_log "主机${IPADDR}秘钥分发失败"
fi
else
err_log "${IPADDR}无法连通"
continue
fi
}
# 遍历IP进行秘钥分发
for i in `cat ${IP_FILE}|xargs`
do
sshDistribution ${i}
done
预期结果
执行sh ssh_distribution.sh
命令
正常情况下,出现如下提示,日志文件存放在/var/log/shell/ssh_distribution.sh/年-月-日.log
然后使用ssh root@10.0.1.66
进行登录
当仅不存在ipfile.list文件时,出现如下报错
当仅不存在ssh秘钥文件时,出现如下报错