196 lines
6.0 KiB
Bash
196 lines
6.0 KiB
Bash
|
|
#!/bin/bash
|
|||
|
|
# 多节点互相同步SSH密钥脚本(支持从文件读取IP、指定用户和密码)
|
|||
|
|
|
|||
|
|
# ==================== 颜色与样式定义 ====================
|
|||
|
|
GREEN="\033[32m" # 成功/完成
|
|||
|
|
YELLOW="\033[33m" # 进行中/提示
|
|||
|
|
RED="\033[31m" # 错误/失败
|
|||
|
|
BLUE="\033[34m" # 标题/分隔线
|
|||
|
|
CYAN="\033[36m" # 信息/说明
|
|||
|
|
NC="\033[0m" # 重置颜色
|
|||
|
|
|
|||
|
|
# 打印分隔线
|
|||
|
|
print_sep() {
|
|||
|
|
echo -e "${BLUE}------------------------------------------------${NC}"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ==================== 参数解析与校验 ====================
|
|||
|
|
# 解析命令行参数
|
|||
|
|
while [[ $# -gt 0 ]]; do
|
|||
|
|
case "$1" in
|
|||
|
|
--file=*)
|
|||
|
|
IP_FILE="${1#*=}"
|
|||
|
|
shift
|
|||
|
|
;;
|
|||
|
|
--user=*)
|
|||
|
|
SSH_USER="${1#*=}"
|
|||
|
|
shift
|
|||
|
|
;;
|
|||
|
|
--passwd=*)
|
|||
|
|
SSH_PASSWD="${1#*=}"
|
|||
|
|
shift
|
|||
|
|
;;
|
|||
|
|
*)
|
|||
|
|
echo -e "${RED}未知参数: $1${NC}"
|
|||
|
|
exit 1
|
|||
|
|
;;
|
|||
|
|
esac
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
# 检查必要参数
|
|||
|
|
if [ -z "$IP_FILE" ] || [ -z "$SSH_USER" ] || [ -z "$SSH_PASSWD" ]; then
|
|||
|
|
echo -e "\n${YELLOW}用法:${NC} --file=IP文件路径 --user=用户名 --passwd=密码"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# 检查IP文件是否存在
|
|||
|
|
if [ ! -f "$IP_FILE" ]; then
|
|||
|
|
echo -e "${RED}错误:IP文件 $IP_FILE 不存在${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# 从文件读取IP列表(去重、过滤空行)
|
|||
|
|
NODES=()
|
|||
|
|
while IFS= read -r ip; do
|
|||
|
|
if [ -n "$ip" ] && ! [[ " ${NODES[@]} " =~ " $ip " ]]; then
|
|||
|
|
NODES+=("$ip")
|
|||
|
|
fi
|
|||
|
|
done < "$IP_FILE"
|
|||
|
|
|
|||
|
|
if [ ${#NODES[@]} -eq 0 ]; then
|
|||
|
|
echo -e "${RED}错误:IP文件 $IP_FILE 中未找到有效IP${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# ==================== 核心功能函数 ====================
|
|||
|
|
# 安装sshpass(处理自动输入密码)
|
|||
|
|
install_sshpass() {
|
|||
|
|
echo -e "\n${YELLOW}【步骤1/3】检查并安装sshpass工具...${NC}"
|
|||
|
|
if ! command -v sshpass &> /dev/null; then
|
|||
|
|
echo -e " ${YELLOW}→ sshpass未安装,正在安装...${NC}"
|
|||
|
|
if command -v apt &> /dev/null; then
|
|||
|
|
apt update -y >/dev/null && apt install -y sshpass >/dev/null
|
|||
|
|
elif command -v yum &> /dev/null; then
|
|||
|
|
yum install -y sshpass >/dev/null
|
|||
|
|
else
|
|||
|
|
echo -e " ${RED}✗ 未找到apt或yum,无法安装sshpass${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
# 验证安装结果
|
|||
|
|
if command -v sshpass &> /dev/null; then
|
|||
|
|
echo -e " ${GREEN}✓ sshpass安装成功${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e " ${RED}✗ sshpass安装失败,请手动安装后重试${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
echo -e " ${GREEN}✓ sshpass已安装${NC}"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 在目标节点生成SSH密钥(若不存在)
|
|||
|
|
generate_key() {
|
|||
|
|
local node=$1
|
|||
|
|
echo -e " ${YELLOW}→ 处理节点 $node...${NC}"
|
|||
|
|
# 远程生成密钥(静默模式)
|
|||
|
|
sshpass -p "$SSH_PASSWD" ssh -o StrictHostKeyChecking=no ${SSH_USER}@$node << EOF >/dev/null 2>&1
|
|||
|
|
if [ ! -f ~/.ssh/id_rsa ]; then
|
|||
|
|
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
|
|||
|
|
fi
|
|||
|
|
EOF
|
|||
|
|
# 检查执行结果
|
|||
|
|
if [ $? -eq 0 ]; then
|
|||
|
|
echo -e " ${GREEN}✓ 密钥生成完成(已存在则跳过)${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e " ${RED}✗ 生成失败(可能密码错误或节点不可达)${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 获取目标节点的公钥
|
|||
|
|
get_public_key() {
|
|||
|
|
local node=$1
|
|||
|
|
# 静默获取公钥,忽略错误输出
|
|||
|
|
sshpass -p "$SSH_PASSWD" ssh -o StrictHostKeyChecking=no ${SSH_USER}@$node "cat ~/.ssh/id_rsa.pub" 2>/dev/null
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 将公钥追加到目标节点的authorized_keys
|
|||
|
|
append_public_key() {
|
|||
|
|
local pub_key="$1"
|
|||
|
|
local target_node=$2
|
|||
|
|
# 远程执行追加公钥操作
|
|||
|
|
sshpass -p "$SSH_PASSWD" ssh -o StrictHostKeyChecking=no ${SSH_USER}@$target_node << EOF >/dev/null 2>&1
|
|||
|
|
mkdir -p ~/.ssh
|
|||
|
|
chmod 700 ~/.ssh
|
|||
|
|
if ! grep -q "$pub_key" ~/.ssh/authorized_keys 2>/dev/null; then
|
|||
|
|
echo "$pub_key" >> ~/.ssh/authorized_keys
|
|||
|
|
chmod 600 ~/.ssh/authorized_keys
|
|||
|
|
fi
|
|||
|
|
EOF
|
|||
|
|
# 反馈结果
|
|||
|
|
if [ $? -eq 0 ]; then
|
|||
|
|
echo -e " ${GREEN}→ 同步成功${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e " ${RED}→ 同步失败${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ==================== 主流程 ====================
|
|||
|
|
main() {
|
|||
|
|
# 欢迎信息
|
|||
|
|
clear
|
|||
|
|
print_sep
|
|||
|
|
echo -e "${BLUE} 多节点SSH密钥互相同步工具 ${NC}"
|
|||
|
|
print_sep
|
|||
|
|
echo -e " ${CYAN}节点列表:${NC} ${NODES[*]}"
|
|||
|
|
echo -e " ${CYAN}操作用户:${NC} $SSH_USER"
|
|||
|
|
echo -e " ${CYAN}开始时间:${NC} $(date +'%Y-%m-%d %H:%M:%S')"
|
|||
|
|
print_sep
|
|||
|
|
|
|||
|
|
# 1. 安装依赖工具
|
|||
|
|
install_sshpass
|
|||
|
|
print_sep
|
|||
|
|
|
|||
|
|
# 2. 为所有节点生成密钥
|
|||
|
|
node_count=${#NODES[@]}
|
|||
|
|
echo -e "\n${YELLOW}【步骤2/3】为所有节点生成SSH密钥(共 $node_count 个节点)...${NC}"
|
|||
|
|
for i in "${!NODES[@]}"; do
|
|||
|
|
echo -e "\n 节点 ${i+1}/$node_count: ${NODES[$i]}"
|
|||
|
|
generate_key ${NODES[$i]}
|
|||
|
|
done
|
|||
|
|
print_sep
|
|||
|
|
|
|||
|
|
# 3. 收集公钥并互相同步
|
|||
|
|
echo -e "\n${YELLOW}【步骤3/3】公钥互相同步(共 $node_count 个节点)...${NC}"
|
|||
|
|
for i in "${!NODES[@]}"; do
|
|||
|
|
current_node=${NODES[$i]}
|
|||
|
|
echo -e "\n 处理第 ${i+1}/$node_count 个节点: $current_node"
|
|||
|
|
|
|||
|
|
# 获取当前节点公钥
|
|||
|
|
echo -e " ${YELLOW}→ 获取公钥...${NC}"
|
|||
|
|
pub_key=$(get_public_key $current_node)
|
|||
|
|
if [ -z "$pub_key" ]; then
|
|||
|
|
echo -e " ${RED}✗ 无法获取 $current_node 的公钥${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# 同步到所有节点
|
|||
|
|
echo -e " ${YELLOW}→ 同步到所有节点...${NC}"
|
|||
|
|
for target in "${NODES[@]}"; do
|
|||
|
|
echo -e " 目标节点: $target"
|
|||
|
|
append_public_key "$pub_key" $target
|
|||
|
|
done
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
# 完成提示
|
|||
|
|
print_sep
|
|||
|
|
echo -e "\n${GREEN}=== 所有操作完成!===${NC}"
|
|||
|
|
echo -e " ${CYAN}验证方法:${NC} 在任意节点执行 'ssh ${NODES[1]}' 测试免密登录"
|
|||
|
|
echo -e " ${CYAN}结束时间:${NC} $(date +'%Y-%m-%d %H:%M:%S')"
|
|||
|
|
print_sep
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 执行主流程
|
|||
|
|
main
|