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

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

第3章 密钥对与基本连接

3.1 SSH 密钥对基础

SSH 密钥对由两部分组成:

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

工作原理:

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

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


3.2 生成密钥对

ssh-keygen 基本用法

# 生成 Ed25519 密钥(推荐)
ssh-keygen -t ed25519 -C "your_email@example.com"

交互过程:

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静默模式
-aKDF 轮数(越大暴力破解越难)-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 user@192.168.1.100

# 使用 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 user@192.168.1.100

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 admin@203.0.113.10

ssh dev
ssh internal-web
ssh internal-db

配置参数详解

参数说明示例
Host匹配模式(支持通配符)Host *, Host web-*
HostName实际主机名或 IPHostName 192.168.1.100
User登录用户名User admin
PortSSH 端口Port 2222
IdentityFile私钥文件路径IdentityFile ~/.ssh/id_work
ProxyJump跳板机ProxyJump jump@bastion
ProxyCommand自定义代理命令ProxyCommand nc %h %p
ForwardAgentAgent 转发ForwardAgent yes
LocalForward本地端口转发LocalForward 8080 localhost:80
RemoteForward远程端口转发RemoteForward 9090 localhost:3000
DynamicForwardSOCKS 代理DynamicForward 1080
ServerAliveInterval心跳间隔(秒)ServerAliveInterval 60
ServerAliveCountMax心跳失败次数ServerAliveCountMax 3
StrictHostKeyChecking主机密钥检查StrictHostKeyChecking ask
UserKnownHostsFileknown_hosts 路径UserKnownHostsFile ~/.ssh/known_hosts
AddKeysToAgent自动添加到 AgentAddKeysToAgent yes
Compression启用压缩Compression yes
TCPKeepAliveTCP 保活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/config600用户客户端配置文件
~/.ssh/id_*600用户私钥文件
~/.ssh/id_*.pub644用户公钥文件
~/.ssh/authorized_keys600用户授权公钥列表
~/.ssh/known_hosts644用户已知主机列表
/etc/ssh/sshd_config600root服务端配置文件
/etc/ssh/ssh_host_*_key600root主机私钥
/etc/ssh/ssh_host_*_key.pub644root主机公钥
# 一键修复所有 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 证书认证体系。