linux密钥登录脚本
vim update_keygen.sh
#!/usr/bin/env bash
# ---------------------------
# 颜色定义
# ---------------------------
YELLOW='\e[93m' # 黄色(信息提示)
GREEN='\033[32m' # 绿色(成功提示)
RED='\033[31m' # 红色(错误提示)
RESET='\e[0m' # 重置颜色
YELLOWS='\033[1;33m'
RESETS='\033[0m'
# ---------------------------
# 日志输出函数
# ---------------------------
#黄色
inst_msg() {
local msg="$1"
local datetime=$(date +"%Y-%m-%d %H:%M:%S")
echo -e "${YELLOW}INFO: [${datetime}] ${msg}${RESET}"
}
#
infos_msg() {
local msg="$1"
local datetime=$(date +"%Y-%m-%d %H:%M:%S")
echo -e "${YELLOWS}\033[5mINFO: [${datetime}] ${msg}\033[25m${RESETS}"
}
#绿色
info_msg() {
local msg="$1"
local datetime=$(date +"%Y-%m-%d %H:%M:%S")
echo -e "${GREEN}INFO: [${datetime}] ${msg}${RESET}"
}
#红色
err_msg() {
local msg="$1"
local datetime=$(date +"%Y-%m-%d %H:%M:%S")
echo -e "${RED}ERRO: [${datetime}] ${msg}${RESET}" >&2
#exit 1
}
create_sshd() {
local SSH_DIR="$HOME/.ssh"
local AUTH_KEYS_FILE="$SSH_DIR/authorized_keys"
# 1. 确保.ssh目录存在
mkdir -p "$SSH_DIR"
chmod 700 "$SSH_DIR"
# 2. 确保 authorized_keys 文件存在
touch "$AUTH_KEYS_FILE"
chmod 600 "$AUTH_KEYS_FILE"
# 3. 提示用户输入公钥
echo "请粘贴 id_rsa.pub 公钥内容(一行),按 Enter 结束输入:"
echo "提示: 公钥格式为: ssh-rsa AAAA... comment"
echo "或者以 ssh-ed25519、ecdsa-sha2-nistp256 开头"
echo "按 Ctrl+D 退出输入"
echo "----------------------------------------"
# 读取公钥(支持多行,但实际上公钥通常是一行)
local PUB_KEY
PUB_KEY=$(cat)
# 如果用户按 Ctrl+D 直接退出,PUB_KEY 可能为空
if [ -z "$PUB_KEY" ]; then
read -r -p "未输入公钥,是否跳过? [y/N]: " SKIP_INPUT
if [[ "${SKIP_INPUT:-n}" =~ ^[Yy]$ ]]; then
info_msg "跳过公钥配置"
return 0
else
err_msg "公钥输入被取消"
return 1
fi
fi
# 4. 清理公钥字符串(去除首尾空白,合并多行)
# 公钥可能被粘贴成多行,需要合并成一行
PUB_KEY=$(echo "$PUB_KEY" | tr -d '\r' | sed ':a;N;$!ba;s/\n//g' | xargs)
if [ -z "$PUB_KEY" ]; then
err_msg "错误: 公钥内容无效或为空"
return 1
fi
# 5. 验证公钥格式
info_msg "正在验证公钥格式..."
# 检查是否是有效的SSH公钥格式
local IS_VALID_KEY=false
# SSH 公钥常见类型
if [[ "$PUB_KEY" =~ ^ssh-(rsa|dss|ed25519) ]]; then
IS_VALID_KEY=true
elif [[ "$PUB_KEY" =~ ^ecdsa-sha2-nistp ]]; then
IS_VALID_KEY=true
else
# 尝试解析密钥类型
local KEY_TYPE
KEY_TYPE=$(echo "$PUB_KEY" | awk '{print $1}')
case "$KEY_TYPE" in
ssh-rsa|ssh-dss|ssh-ed25519|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521)
IS_VALID_KEY=true
;;
*)
# 如果不是标准格式,检查是否有三个字段(类型 密钥 注释)
local FIELD_COUNT
FIELD_COUNT=$(echo "$PUB_KEY" | wc -w)
if [ "$FIELD_COUNT" -ge 2 ]; then
# 至少有两个字段,可能是有效的
IS_VALID_KEY=true
info_msg "检测到非标准格式,但继续处理..."
fi
;;
esac
fi
if [ "$IS_VALID_KEY" = false ]; then
err_msg "错误: 无效的SSH公钥格式"
echo "示例格式: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... user@host"
return 1
fi
# 6. 提取公钥的关键部分用于查重(类型 + 密钥,不含注释)
local KEY_FOR_CHECK
KEY_FOR_CHECK=$(echo "$PUB_KEY" | awk '{print $1" "$2}')
# 7. 检查公钥是否已存在
if [ -f "$AUTH_KEYS_FILE" ]; then
# 检查是否已有相同密钥(不考虑注释)
if grep -qF "$KEY_FOR_CHECK" "$AUTH_KEYS_FILE" 2>/dev/null; then
# 获取已存在的完整行
local EXISTING_LINE
EXISTING_LINE=$(grep -F "$KEY_FOR_CHECK" "$AUTH_KEYS_FILE" | head -1)
info_msg "公钥已存在于 authorized_keys 文件中:"
echo "$EXISTING_LINE"
read -r -p "是否仍然添加? [y/N]: " ADD_ANYWAY
if [[ ! "${ADD_ANYWAY:-n}" =~ ^[Yy]$ ]]; then
info_msg "跳过添加重复公钥"
return 0
fi
fi
fi
# 8. 添加公钥
echo "$PUB_KEY" >> "$AUTH_KEYS_FILE"
# 9. 确保文件权限正确
chmod 600 "$AUTH_KEYS_FILE"
# 10. 显示添加结果
inst_msg "公钥已成功添加到 ~/.ssh/authorized_keys"
info_msg "添加的公钥:"
echo "$PUB_KEY"
# 11. 显示统计信息
echo -e "\n----------------------------------------"
info_msg "当前 authorized_keys 文件状态:"
if [ -f "$AUTH_KEYS_FILE" ]; then
local KEY_COUNT
KEY_COUNT=$(grep -c -E '^(ssh-|ecdsa-)' "$AUTH_KEYS_FILE" 2>/dev/null || echo "0")
info_msg "授权公钥总数: $KEY_COUNT"
# 显示最后添加的几个密钥
if [ "$KEY_COUNT" -gt 0 ]; then
info_msg "最近添加的公钥:"
tail -5 "$AUTH_KEYS_FILE" | while read -r line; do
echo " - $(echo "$line" | awk '{print $NF}')"
done
fi
fi
echo "----------------------------------------"
return 0
}
update_config(){
# 备份原始配置文件
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
# 删除所有冲突的配置项
sed -i -E "/^(#\s*)?(PubkeyAuthentication|PasswordAuthentication|ChallengeResponseAuthentication|UsePAM|PermitRootLogin)/d" /etc/ssh/sshd_config
# 添加新的安全配置
echo "PubkeyAuthentication yes" >> /etc/ssh/sshd_config
echo "PasswordAuthentication no" >> /etc/ssh/sshd_config
echo "ChallengeResponseAuthentication no" >> /etc/ssh/sshd_config
echo "UsePAM no" >> /etc/ssh/sshd_config
echo "PermitRootLogin without-password" >> /etc/ssh/sshd_config
# 修改完配置文件后,需要重启 SSH 服务使配置生效
if systemctl restart sshd; then
info_msg "SSH服务重启成功"
else
err_msg "SSH服务重启失败"
return 1
fi
}
print_ssh_config_table() {
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
RESET='\033[0m'
# 检查是否有root权限,因为需要读取/etc/ssh/sshd_config
if [ "$(id -u)" -ne 0 ]; then
echo -e "${RED}错误: 需要root权限运行此脚本。请使用sudo命令。${RESET}"
exit 1
fi
# 从配置文件获取数据
config_data=$(grep -E "^(PubkeyAuthentication|PasswordAuthentication|ChallengeResponseAuthentication|UsePAM|PermitRootLogin)" /etc/ssh/sshd_config)
# 检查是否找到了配置项
if [ -z "$config_data" ]; then
echo -e "${RED}错误: 在/etc/ssh/sshd_config中未找到匹配的配置项。${RESET}"
exit 1
fi
# 计算配置项和值的最大长度
max_key_length=0
max_value_length=0
while IFS= read -r line; do
key=$(echo "$line" | awk '{print $1}')
value=$(echo "$line" | awk '{print $2}')
key_length=${#key}
value_length=${#value}
if [ $key_length -gt $max_key_length ]; then
max_key_length=$key_length
fi
if [ $value_length -gt $max_value_length ]; then
max_value_length=$value_length
fi
done <<< "$config_data"
# 确保列宽足够显示标题
if [ $max_key_length -lt 6 ]; then
max_key_length=6
fi
if [ $max_value_length -lt 3 ]; then
max_value_length=3
fi
# 添加一些边距
max_key_length=$((max_key_length + 2))
max_value_length=$((max_value_length + 2))
# 计算表格总宽度
table_width=$((max_key_length + max_value_length + 3)) # 3个竖线
# 生成横线
hline=$(printf '%*s' "$table_width" '' | tr ' ' '-')
# 打印表头
echo -e "\n${BLUE}SSH 安全配置信息:${RESET}"
echo -e "${BLUE}+${hline}+${RESET}"
printf "${YELLOW}| ${BLUE}%-${max_key_length}s${YELLOW} | ${BLUE}%-${max_value_length}s${YELLOW} |${RESET}\n" "配置项" "值"
echo -e "${BLUE}+${hline}+${RESET}"
# 打印每一行配置
while IFS= read -r line; do
key=$(echo "$line" | awk '{print $1}')
value=$(echo "$line" | awk '{print $2}')
# 根据值设置颜色
if [ "$value" = "yes" ] || [ "$value" = "without-password" ]; then
value_color="${GREEN}"
else
value_color="${RED}"
fi
# 打印行
printf "${YELLOW}| ${RESET}%-${max_key_length}s${YELLOW}| ${value_color}%-${max_value_length}s${YELLOW}|${RESET}\n" "$key" "$value"
done <<< "$config_data"
# 打印表尾
echo -e "${BLUE}+${hline}+${RESET}\n" | column -t
}
restore_root_password_login() {
local SSHD_CONFIG="/etc/ssh/sshd_config"
local BACKUP_FILE="${SSHD_CONFIG}.backup.$(date +%Y%m%d_%H%M%S)"
# 1. 检查文件是否存在
if [ ! -f "$SSHD_CONFIG" ]; then
err_msg "SSH 配置文件不存在: $SSHD_CONFIG"
return 1
fi
# 2. 备份原配置文件
info_msg "备份原配置文件..."
if cp "$SSHD_CONFIG" "$BACKUP_FILE"; then
inst_msg "配置文件已备份到: $BACKUP_FILE"
else
err_msg "备份失败,请检查权限"
return 1
fi
# 3. 显示当前配置
info_msg "当前 SSH 配置状态:"
echo "----------------------------------------"
grep -E "^(PermitRootLogin|PasswordAuthentication|ChallengeResponseAuthentication)" "$SSHD_CONFIG" | grep -v "^#" || echo "使用默认配置"
echo "----------------------------------------"
# 4. 修改配置
info_msg "正在修改 SSH 配置..."
# 临时文件
local TMP_FILE=$(mktemp)
# 处理配置项
cat "$SSHD_CONFIG" | while IFS= read -r line; do
# 注释掉现有的相关配置
case "$line" in
PermitRootLogin*)
echo "# $line # 已禁用,由脚本修改"
echo "PermitRootLogin yes"
;;
PasswordAuthentication*)
echo "# $line # 已禁用,由脚本修改"
echo "PasswordAuthentication yes"
;;
ChallengeResponseAuthentication*)
echo "# $line # 已禁用,由脚本修改"
echo "ChallengeResponseAuthentication yes"
;;
*)
echo "$line"
;;
esac
done > "$TMP_FILE"
# 如果文件中没有这些配置项,则添加
if ! grep -q "^PermitRootLogin" "$TMP_FILE"; then
echo "PermitRootLogin yes" >> "$TMP_FILE"
fi
if ! grep -q "^PasswordAuthentication" "$TMP_FILE"; then
echo "PasswordAuthentication yes" >> "$TMP_FILE"
fi
if ! grep -q "^ChallengeResponseAuthentication" "$TMP_FILE"; then
echo "ChallengeResponseAuthentication yes" >> "$TMP_FILE"
fi
# 5. 验证配置文件语法
info_msg "验证配置文件语法..."
if sshd -t -f "$TMP_FILE" 2>/dev/null; then
inst_msg "配置文件语法正确"
else
err_msg "配置文件语法错误,请检查"
sshd -t -f "$TMP_FILE"
rm -f "$TMP_FILE"
return 1
fi
# 6. 应用新配置
if cp "$TMP_FILE" "$SSHD_CONFIG"; then
chmod 600 "$SSHD_CONFIG"
inst_msg "新配置已写入"
else
err_msg "写入配置文件失败,请检查权限"
rm -f "$TMP_FILE"
return 1
fi
rm -f "$TMP_FILE"
# 7. 重启 SSH 服务
info_msg "重启 SSH 服务..."
if systemctl restart sshd 2>/dev/null || service sshd restart 2>/dev/null || /etc/init.d/ssh restart 2>/dev/null; then
inst_msg "SSH 服务重启成功"
else
err_msg "SSH 服务重启失败,请手动重启"
info_msg "请执行: systemctl restart sshd 或 service sshd restart"
fi
# 8. 显示修改后的配置
echo -e "\n----------------------------------------"
inst_msg "SSH 配置修改完成!"
info_msg "修改后的关键配置:"
grep -E "^(PermitRootLogin|PasswordAuthentication|ChallengeResponseAuthentication)" "$SSHD_CONFIG" | grep -v "^#"
echo "----------------------------------------"
# 9. 安全提示
echo -e "\n${YELLOW}⚠ 安全提示:${NC}"
echo "1. 已启用 root 密码登录"
echo "2. 请确保 root 密码足够复杂"
echo "3. 建议使用强密码或定期更换密码"
echo "4. 考虑使用 fail2ban 防止暴力破解"
echo "5. 如需禁用,可执行: PermitRootLogin no"
return 0
}
func_ifs(){
if [ $? -eq 0 ]; then
info_msg "SSH密钥登录设置成功"
# 验证配置
inst_msg "验证配置:"
echo -e "公钥认证: $(grep -q '^PubkeyAuthentication yes' /etc/ssh/sshd_config && echo -e "${GREEN}已启用${RESET}" || echo -e "${RED}未启用${RESET}")"
echo -e "密码认证: $(grep -q '^PasswordAuthentication no' /etc/ssh/sshd_config && echo -e "${GREEN}已禁用${RESET}" || echo -e "${RED}未禁用${RESET}")"
exit 0
else
err_msg "SSH密钥登录设置失败"
# 恢复备份
mv /etc/ssh/sshd_config.bak /etc/ssh/sshd_config
systemctl restart sshd
err_msg "已恢复原始SSH配置"
exit 127
fi
}
echo -e "\n配置菜单: \n1、配置免密登录并禁用root登录\n2、配置免密登录不禁用root登录\n3、恢复ssh root登录\n4、不配置退出"
read -r -p "选择配置[1-3]: " USERADDNAME
if [ -z "${USERADDNAME}" ]; then
err_msg "错误: 选择不能为空"
exit 1
fi
# 检查输入是否为数字
if ! [[ "${USERADDNAME}" =~ ^[0-9]+$ ]]; then
err_msg "错误: 请输入数字(1-3)"
exit 1
fi
case "${USERADDNAME}" in
1)
# 配置免密登录并禁用root登录
inst_msg "执行选项1: 配置免密登录并禁用root登录"
# 这里调用你的函数
# create_sshd
# update_config
# print_ssh_config_table
# func_ifs
info_msg "正在配置免密登录并禁用root登录..."
# 实际执行代码...
;;
2)
# 配置免密登录不禁用root登录
inst_msg "执行选项2: 配置免密登录不禁用root登录"
echo "请粘贴 id_rsa 私钥内容(支持多行),按两次 Ctrl+D 结束输入:"
info_msg "提示: 粘贴以 '-----BEGIN OPENSSH PRIVATE KEY-----' 开头的内容"
# 读取多行私钥
ID_RSANAME=$(cat)
if [ -z "${ID_RSANAME}" ]; then
err_msg "错误: 私钥内容不能为空"
exit 1
fi
# 验证私钥基本格式
if ! echo "${ID_RSANAME}" | grep -q "BEGIN.*PRIVATE KEY"; then
echo -e "\n"
info_msg "警告: 未检测到标准私钥开头标记,但继续处理..."
fi
echo -e "\n"
info_msg "私钥已接收,长度: ${#ID_RSANAME} 字符"
# 确保 ~/.ssh 目录存在
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# 检查私钥文件是否存在
if [ -f ~/.ssh/id_rsa ]; then
read -r -p "~/.ssh/id_rsa 文件已存在,是否替换它? [y/N]: " YES_RSA
if [ -z "${YES_RSA}" ]; then
YES_RSA="n" # 默认为不替换
fi
if [[ "${YES_RSA}" =~ ^[Yy]$ ]]; then
# 备份原文件
BACKUP_FILE="$HOME/.ssh/id_rsa.backup.$(date +%Y%m%d%H%M%S)"
cp ~/.ssh/id_rsa "${BACKUP_FILE}"
info_msg "原文件已备份到: ${BACKUP_FILE}"
# 写入新私钥
echo "${ID_RSANAME}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
inst_msg "私钥文件已替换"
# 可选: 生成公钥
# info_msg "正在生成公钥..."
# ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub 2>/dev/null
# if [ $? -eq 0 ]; then
# inst_msg "公钥已生成: ~/.ssh/id_rsa.pub"
# else
# err_msg "警告: 公钥生成失败,请检查私钥格式"
# fi
else
inst_msg "未替换私钥文件"
exit 0
fi
else
# 文件不存在,直接创建
echo "${ID_RSANAME}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
inst_msg "私钥文件已创建: ~/.ssh/id_rsa"
# 生成公钥
# info_msg "正在生成公钥..."
# ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub 2>/dev/null
# if [ $? -eq 0 ]; then
# inst_msg "公钥已生成: ~/.ssh/id_rsa.pub"
# else
# err_msg "警告: 公钥生成失败,请检查私钥格式"
# fi
fi
# 测试私钥有效性
info_msg "测试私钥有效性..."
ssh-keygen -l -f ~/.ssh/id_rsa >/dev/null 2>&1
if [ $? -eq 0 ]; then
inst_msg "私钥格式有效"
else
err_msg "警告: 私钥格式可能无效"
fi
create_sshd
;;
3)
restore_root_password_login
;;
4)
# 不配置退出
inst_msg "用户选择退出,即将退出!"
exit 0
;;
*)
err_msg "错误: 无效的选择,请输入 1、2、3、4"
exit 1
;;
esac
# 可选: 显示配置结果
echo -e "\n==============================="
info_msg "配置完成!"
if [ -f ~/.ssh/id_rsa ]; then
info_msg "私钥文件: ~/.ssh/id_rsa"
info_msg "权限: $(ls -l ~/.ssh/id_rsa | awk '{print $1}')"
# 显示密钥指纹
if command -v ssh-keygen >/dev/null 2>&1; then
info_msg "密钥指纹:"
ssh-keygen -l -f ~/.ssh/id_rsa 2>/dev/null || err_msg "无法获取密钥指纹"
fi
fi
echo "==============================="
bash update_keygen.sh
评论 (0)