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
|