强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

SSH 服务器完全指南 / 第3章 密钥对与基本连接

第3章 密钥对与基本连接

3.1 SSH 密钥对基础

SSH 密钥对由两部分组成:

组成部分 存储位置 能否共享
私钥 (Private Key) 客户端本地 ❌ 绝对不能
公钥 (Public Key) 部署到服务器 ✅ 可以分发给任何人

工作原理:

客户端                              服务器
  │  用私钥签名挑战 ──────────────────>│
  │                                    │  用公钥验证签名
  │  ────────────────────────────────  │
  │  签名有效,身份确认 ─────────────>│
  │                                    │
  │<══ 加密会话建立,允许登录 ═══════>│

核心原则: 公钥可以公开,私钥必须保密。拥有私钥 = 拥有身份。


3.2 生成密钥对

ssh-keygen 基本用法

# 生成 Ed25519 密钥(推荐)
ssh-keygen -t ed25519 -C "[email protected]"

交互过程:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519): [回车使用默认]
Enter passphrase (empty for no passphrase): [输入密码短语,强烈建议设置]
Enter same passphrase again: [再次输入密码短语]
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx user@hostname
The key's randomart image is:
+--[ED25519 256]--+
|    .  .          |
|   o o. .         |
|  . + o.          |
|   . o o          |
|    o = oS        |
|   . = +..        |
|    = E ..        |
|   o =.oo         |
|  .+.oB*          |
+----[SHA256]-----+

不同算法的密钥生成

# Ed25519(推荐 - 256 bit,速度快,安全性高)
ssh-keygen -t ed25519 -C "comment" -f ~/.ssh/id_ed25519

# RSA 4096(兼容性最好,适合老系统)
ssh-keygen -t rsa -b 4096 -C "comment" -f ~/.ssh/id_rsa

# ECDSA(折中选择)
ssh-keygen -t ecdsa -b 256 -C "comment" -f ~/.ssh/id_ecdsa

密钥生成参数对照

参数 说明 示例
-t 密钥类型 ed25519, rsa, ecdsa
-b 密钥位数(RSA/ECDSA) 4096, 256
-C 注释(通常用邮箱) "user@host"
-f 输出文件路径 ~/.ssh/id_ed25519
-N 密码短语(空字符串表示无密码) "mypassphrase"""
-q 静默模式
-a KDF 轮数(越大暴力破解越难) -a 100

批量生成(脚本场景)

# 无交互式生成密钥(适合自动化脚本)
ssh-keygen -t ed25519 \
    -f /home/deploy/.ssh/id_ed25519 \
    -N "strong-passphrase-here" \
    -C "deploy@ci-server" \
    -q

3.3 密钥文件详解

文件结构

# 查看公钥内容
cat ~/.ssh/id_ed25519.pub

# 示例输出:
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx user@host

# 公钥结构:
# [算法类型] [Base64编码的密钥数据] [注释]
# 私钥文件内容(仅供参考,切勿分享)
cat ~/.ssh/id_ed25519

# 结构:
# -----BEGIN OPENSSH PRIVATE KEY-----
# [Base64 编码的私钥数据]
# -----END OPENSSH PRIVATE KEY-----

文件权限要求

SSH 对密钥文件的权限非常严格:

# .ssh 目录:仅所有者可访问(700)
chmod 700 ~/.ssh

# 私钥文件:仅所有者可读写(600)
chmod 600 ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_rsa

# 公钥文件:所有人可读(644)
chmod 644 ~/.ssh/id_ed25519.pub
chmod 644 ~/.ssh/id_rsa.pub

# authorized_keys 文件
chmod 600 ~/.ssh/authorized_keys

# known_hosts 文件
chmod 644 ~/.ssh/known_hosts

# config 文件
chmod 600 ~/.ssh/config

# 查看当前权限
ls -la ~/.ssh/

期望的输出:

drwx------  2 user user 4096 Jan  1 10:00 .
-rw-------  1 user user  411 Jan  1 10:00 config
-rw-------  1 user user  749 Jan  1 10:00 id_ed25519
-rw-r--r--  1 user user  106 Jan  1 10:00 id_ed25519.pub
-rw-------  1 user user  444 Jan  1 10:00 authorized_keys
-rw-r--r--  1 user user  888 Jan  1 10:00 known_hosts

⚠️ 警告: 如果 SSH 检测到私钥权限过宽(如 644),它会拒绝使用该密钥并发出警告。


3.4 使用 SSH 客户端连接

基本连接

# 最简单的连接方式
ssh user@hostname

# 指定端口
ssh -p 2222 user@hostname

# 使用 IP 地址
ssh [email protected]

# 使用 IPv6
ssh user@2001:db8::1

连接过程详解

# 使用 -v 查看详细连接过程
ssh -v user@hostname

输出关键阶段:

# 1. 解析主机名
debug1: Connecting to hostname [192.168.1.100] port 22.

# 2. 协议版本协商
debug1: Remote protocol version 2.0, remote software version OpenSSH_9.0

# 3. 密钥交换
debug1: SSH2_MSG_KEXINIT sent
debug1: kex: algorithm: curve25519-sha256

# 4. 主机密钥验证
debug1: Host 'hostname' is known and matches the ED25519 host key.
# 或
The authenticity of host 'hostname' can't be established.
ED25519 key fingerprint is SHA256:xxxxx.

# 5. 用户认证
debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519 SHA256:xxxxx
debug1: Server accepts key: /home/user/.ssh/id_ed25519 ED25519 SHA256:xxxxx

# 6. 会话建立
debug1: Authentication succeeded (publickey).

常用 SSH 客户端参数

参数 说明 示例
-p 指定端口 -p 2222
-i 指定私钥 -i ~/.ssh/id_work
-v 调试模式(可叠加 -vvv) -vvv
-o 设置选项 -o StrictHostKeyChecking=no
-J 跳板机 -J jump@bastion
-L 本地端口转发 -L 8080:localhost:80
-R 远程端口转发 -R 9090:localhost:3000
-D 动态端口转发 -D 1080
-N 不打开 Shell -N
-f 后台运行 -f
-T 禁用伪终端 -T
-t 强制分配伪终端 -t
-A 启用 Agent 转发 -A
-X 启用 X11 转发 -X
-C 启用压缩 -C

常用运行模式

# 执行单条命令(不进入交互 Shell)
ssh user@host "uname -a && uptime"

# 执行多条命令
ssh user@host << 'EOF'
    cd /var/log
    tail -n 20 syslog
    df -h
EOF

# 后台运行长时间命令
ssh user@host "nohup /opt/scripts/backup.sh > /tmp/backup.log 2>&1 &"

# 不打开 Shell(仅做端口转发)
ssh -N -L 8080:localhost:80 user@host

# 保持连接(配合 -f 后台运行)
ssh -fN -L 8080:localhost:80 user@host

3.5 主机密钥验证

首次连接信任

首次连接某台服务器时,SSH 会提示确认主机指纹:

The authenticity of host '192.168.1.100' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

安全做法:通过带外渠道(如服务器控制台、云平台控制面板)验证指纹:

# 在服务器上查看主机密钥指纹
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
# 输出:256 SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx root@server (ED25519)

ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub
# 输出:4096 SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx root@server (RSA)

known_hosts 文件

已接受的主机密钥存储在 ~/.ssh/known_hosts 中:

# 查看已知主机
cat ~/.ssh/known_hosts

# 删除特定主机的密钥(主机密钥变更时需要)
ssh-keygen -R 192.168.1.100

# 删除所有已知主机(谨慎使用)
rm ~/.ssh/known_hosts

主机密钥变更处理

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.

这个警告可能意味着:

情况 处理方式
服务器重装了系统 确认后删除旧密钥
服务器更换了主机密钥 确认后删除旧密钥
IP 地址被重新分配 确认后删除旧密钥
中间人攻击 不要继续连接!
# 安全地处理主机密钥变更
# 1. 通过带外渠道确认新密钥
# 2. 删除旧密钥
ssh-keygen -R 192.168.1.100
# 3. 重新连接并接受新密钥
ssh [email protected]

3.6 SSH 客户端配置文件

~/.ssh/config 文件可以大大简化 SSH 使用:

基本配置

# ~/.ssh/config

# 全局默认设置
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes
    IdentityFile ~/.ssh/id_ed25519

# 生产服务器
Host production
    HostName 203.0.113.10
    User admin
    Port 2222
    IdentityFile ~/.ssh/id_prod

# 开发服务器
Host dev
    HostName 192.168.1.50
    User developer
    ForwardAgent yes

# 跳板机 + 内网服务器
Host bastion
    HostName bastion.example.com
    User jumpuser
    IdentityFile ~/.ssh/id_bastion

Host internal-*
    User internaluser
    ProxyJump bastion
    IdentityFile ~/.ssh/id_internal

Host internal-web
    HostName 10.0.0.10

Host internal-db
    HostName 10.0.0.20
    Port 5432

使用配置

# 使用别名连接(等同于完整的 ssh 命令)
ssh production
# 等同于:ssh -p 2222 -i ~/.ssh/id_prod [email protected]

ssh dev
ssh internal-web
ssh internal-db

配置参数详解

参数 说明 示例
Host 匹配模式(支持通配符) Host *, Host web-*
HostName 实际主机名或 IP HostName 192.168.1.100
User 登录用户名 User admin
Port SSH 端口 Port 2222
IdentityFile 私钥文件路径 IdentityFile ~/.ssh/id_work
ProxyJump 跳板机 ProxyJump jump@bastion
ProxyCommand 自定义代理命令 ProxyCommand nc %h %p
ForwardAgent Agent 转发 ForwardAgent yes
LocalForward 本地端口转发 LocalForward 8080 localhost:80
RemoteForward 远程端口转发 RemoteForward 9090 localhost:3000
DynamicForward SOCKS 代理 DynamicForward 1080
ServerAliveInterval 心跳间隔(秒) ServerAliveInterval 60
ServerAliveCountMax 心跳失败次数 ServerAliveCountMax 3
StrictHostKeyChecking 主机密钥检查 StrictHostKeyChecking ask
UserKnownHostsFile known_hosts 路径 UserKnownHostsFile ~/.ssh/known_hosts
AddKeysToAgent 自动添加到 Agent AddKeysToAgent yes
Compression 启用压缩 Compression yes
TCPKeepAlive TCP 保活 TCPKeepAlive yes
ConnectTimeout 连接超时(秒) ConnectTimeout 10
LogLevel 日志级别 LogLevel VERBOSE
RequestTTY 伪终端分配 RequestTTY force
SendEnv 发送环境变量 SendEnv LANG LC_*
SetEnv 设置环境变量 SetEnv MY_VAR=value

Host 匹配模式

# 精确匹配
Host myserver

# 通配符匹配
Host *.example.com          # 匹配所有 example.com 子域名
Host 192.168.1.*            # 匹配 192.168.1.0/24 网段
Host web-*                  # 匹配 web- 开头的名称

# 多个模式
Host web-* db-* cache-*

# 全局匹配(必须放在最后)
Host *

3.7 ssh-agent 密钥管理

ssh-agent 是一个后台进程,用于缓存私钥的密码短语,避免每次都输入。

基本使用

# 启动 ssh-agent
eval "$(ssh-agent -s)"
# 输出:Agent pid 12345

# 添加密钥到 agent
ssh-add ~/.ssh/id_ed25519
# 输入密码短语

# 查看已加载的密钥
ssh-add -l

# 删除所有已加载的密钥
ssh-add -D

# 删除特定密钥
ssh-add -d ~/.ssh/id_ed25519.pub

自动启动 ssh-agent

~/.bashrc~/.zshrc 中添加:

# 自动启动 ssh-agent(避免重复启动)
if [ -z "$SSH_AUTH_SOCK" ]; then
    eval "$(ssh-agent -s)" > /dev/null 2>&1
fi

GNOME Keyring / KDE Wallet

桌面环境通常自动管理 ssh-agent:

# 检查是否在使用桌面环境的 agent
echo $SSH_AUTH_SOCK
# GNOME: /run/user/1000/keyring/ssh
# KDE: /tmp/ssh-xxxxx/agent.pid

# 如果需要使用独立的 agent,设置环境变量
export SSH_AUTH_SOCK=~/.ssh/ssh_agent.sock

3.8 SSH 实用技巧

使用 SSH 执行远程命令

# 单条命令
ssh user@host "ps aux | grep nginx"

# 多条命令
ssh user@host "cd /var/log && ls -la && tail -5 syslog"

# 交互式脚本
ssh -t user@host "sudo bash -c 'apt update && apt upgrade -y'"

# 将本地脚本传到远程执行
ssh user@host 'bash -s' < local_script.sh

# 执行需要 sudo 的命令(使用 -t 分配终端)
ssh -t user@host "sudo systemctl restart nginx"

文件传输快捷方式

# scp 基本用法
scp localfile.txt user@host:/remote/path/
scp user@host:/remote/file.txt ./

# 目录传输
scp -r localdir/ user@host:/remote/path/

# rsync over SSH(推荐,支持增量传输)
rsync -avz -e ssh localdir/ user@host:/remote/path/

# 限速传输(避免占满带宽)
rsync -avz --bwlimit=1000 -e ssh largefile user@host:/tmp/

SSH 连接复用(ControlMaster)

避免重复建立连接,加速后续连接:

# ~/.ssh/config
Host *
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

# 创建 socket 目录
mkdir -p ~/.ssh/sockets

效果:

# 第一次连接:正常建立(约 1-2 秒)
ssh user@host
# 连接建立完成

# 第二次连接:复用已有连接(几乎瞬时)
ssh user@host
# 立即进入

# 查看已有连接
ssh -O check user@host

# 关闭已有连接
ssh -O exit user@host

3.9 SSH 加速连接

连接慢的常见原因

原因 解决方案
DNS 反向解析 在服务端设置 UseDNS no
GSSAPI 认证 设置 GSSAPIAuthentication no
主机密钥检查 设置 StrictHostKeyChecking accept-new
网络延迟 使用 ControlMaster 复用连接

客户端优化配置

# ~/.ssh/config
Host *
    # 启用连接复用
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

    # 跳过 DNS 反向解析
    AddressFamily inet

    # 禁用 GSSAPI
    GSSAPIAuthentication no

    # 保持连接
    ServerAliveInterval 60
    ServerAliveCountMax 3

    # 使用压缩(带宽有限时)
    Compression yes

服务端优化配置

# /etc/ssh/sshd_config

# 禁用 DNS 反向解析(显著加速登录)
UseDNS no

# 禁用 GSSAPI(除非你使用 Kerberos)
GSSAPIAuthentication no

3.10 SSH 文件权限清单

路径 权限 所有者 说明
~/.ssh/ 700 用户 SSH 配置目录
~/.ssh/config 600 用户 客户端配置文件
~/.ssh/id_* 600 用户 私钥文件
~/.ssh/id_*.pub 644 用户 公钥文件
~/.ssh/authorized_keys 600 用户 授权公钥列表
~/.ssh/known_hosts 644 用户 已知主机列表
/etc/ssh/sshd_config 600 root 服务端配置文件
/etc/ssh/ssh_host_*_key 600 root 主机私钥
/etc/ssh/ssh_host_*_key.pub 644 root 主机公钥
# 一键修复所有 SSH 权限
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config ~/.ssh/id_* ~/.ssh/authorized_keys
chmod 644 ~/.ssh/id_*.pub ~/.ssh/known_hosts

扩展阅读


下一章: 第4章 密钥认证与证书 → 深入学习 authorized_keys 管理、SSH 证书认证体系。