linux密钥登录脚本

元气满满
2026-01-23 / 0 评论 / 0 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2026年03月12日,已超过229天没有更新,若内容或图片失效,请留言反馈。

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

评论 (0)

取消