SSH密钥登录配置实战:快速部署、密钥管理与自动化配置指南

一、SSH密钥登录快速配置

1.1 三步快速配置

SSH密钥登录配置只需要三个步骤:

1
2
3
4
5
6
7
8
# 第1步:生成密钥对
ssh-keygen -t ed25519 -C "your_email@example.com"

# 第2步:复制公钥到服务器
ssh-copy-id user@server

# 第3步:测试连接
ssh user@server

就这么简单!现在你已经可以通过密钥登录服务器了。

1.2 密钥生成详解

生成Ed25519密钥(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 基本命令
ssh-keygen -t ed25519 -C "your_email@example.com"

# 交互式生成(推荐)
ssh-keygen -t ed25519

# 输出示例:
# Generating public/private ed25519 key pair.
# Enter file in which to save the key (/Users/username/.ssh/id_ed25519):
# Enter passphrase (empty for no passphrase):
# Enter same passphrase again:
# Your identification has been saved in /Users/username/.ssh/id_ed25519
# Your public key has been saved in /Users/username/.ssh/id_ed25519.pub

生成RSA密钥(兼容性好)

1
2
3
4
5
# 生成4096位RSA密钥
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

# 生成并指定文件名
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_server -C "server1"

生成ECDSA密钥(性能好)

1
2
# 生成ECDSA密钥
ssh-keygen -t ecdsa -b 521 -C "your_email@example.com"

1.3 密钥文件说明

1
2
3
4
5
6
7
8
9
# 查看密钥文件
ls -lh ~/.ssh/

# 文件说明:
# id_ed25519 - 私钥文件(绝密,权限600)
# id_ed25519.pub - 公钥文件(可以分享)
# authorized_keys - 服务器上的授权公钥列表
# known_hosts - 已知主机指纹记录
# config - SSH客户端配置文件
1
2
3
4
5
6
7
8
9
10
11
# 查看公钥内容
cat ~/.ssh/id_ed25519.pub

# 输出示例:
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJxxxxxxxxxxxxxxxxxxxxxxxxxxx your_email@example.com

# 查看私钥指纹
ssh-keygen -lf ~/.ssh/id_ed25519.pub

# 输出示例:
# 256 SHA256:xxxxxxxxxxxxx your_email@example.com (ED25519)

二、密钥部署方法

2.1 ssh-copy-id(推荐)

1
2
3
4
5
6
7
8
# 最简单的部署方式
ssh-copy-id user@server

# 指定密钥文件
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

# 指定端口
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 user@server

2.2 手动部署

1
2
3
4
5
6
7
8
# 方法1:使用cat和重定向
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# 方法2:使用scp复制(需要先有密码登录)
scp ~/.ssh/id_ed25519.pub user@server:~/.ssh/authorized_keys

# 方法3:直接追加
ssh user@server "mkdir -p ~/.ssh && echo '$(cat ~/.ssh/id_ed25519.pub)' >> ~/.ssh/authorized_keys"

2.3 多密钥部署

为不同服务器配置不同密钥

1
2
3
4
5
6
# 1. 生成多组密钥
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_server1 -C "server1"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_server2 -C "server2"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_server3 -C "server3"

# 2. 配置~/.ssh/config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# ~/.ssh/config配置示例

# 服务器1配置
Host server1
HostName 192.168.1.10
User root
IdentityFile ~/.ssh/id_ed25519_server1
Port 22

# 服务器2配置
Host server2
HostName 192.168.1.11
User deploy
IdentityFile ~/.ssh/id_ed25519_server2
Port 2222

# 服务器3配置(GitHub)
Host github
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
IdentitiesOnly yes

# 默认配置
Host *
AddKeysToAgent yes
UseKeychain yes
ServerAliveInterval 60
ServerAliveCountMax 3

三、SSH客户端配置

3.1 SSH Config配置详解

完整的SSH配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# ~/.ssh/config

# 全局配置(适用于所有主机)
Host *
# 通用设置
ServerAliveInterval 60 # 每60秒发送keepalive
ServerAliveCountMax 3 # 最多3次keepalive失败后断开
AddKeysToAgent yes # 自动添加密钥到agent
UseKeychain yes # 在macOS上使用keychain
IdentitiesOnly yes # 只使用指定密钥
ForwardAgent no # 不转发agent
ForwardX11 no # 不转发X11

# 连接设置
ControlMaster auto # 启用连接复用
ControlPath ~/.ssh/control-%r@%h:%p
ControlPersist 10m # 连接保持10分钟

# 压缩和性能
Compression yes # 启用压缩
StrictHostKeyChecking ask # 首次连接询问

# 内网服务器(不需要密码)
Host internal-*
HostName %h.example.com
User deploy
IdentityFile ~/.ssh/id_ed25519_internal
StrictHostKeyChecking no
UserKnownHostsFile /dev/null

# 生产服务器(需要密码短语)
Host prod-*
HostName %h.example.com
User deploy
IdentityFile ~/.ssh/id_ed25519_prod
IdentitiesOnly yes
AddKeysToAgent no # 每次都需要输入密码短语

# 跳板机配置
Host bastion
HostName bastion.example.com
User admin
IdentityFile ~/.ssh/id_ed25519_bastion
ForwardAgent yes # 允许agent转发到内部服务器

# 通过跳板机连接内部服务器
Host internal-*
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519_internal

# GitHub配置
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
IdentitiesOnly yes

# GitLab配置
Host gitlab.example.com
HostName gitlab.example.com
User git
IdentityFile ~/.ssh/id_ed25519_gitlab
Port 2222
IdentitiesOnly yes

3.2 SSH Agent管理

启动和管理SSH Agent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# macOS和Linux
eval "$(ssh-agent -s)"

# 添加密钥到agent
ssh-add ~/.ssh/id_ed25519

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

# 列出密钥详细信息
ssh-add -L

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

# 清空所有密钥
ssh-add -D

# macOS上使用keychain持久化
ssh-add --apple-use-keychain ~/.ssh/id_ed25519

Windows配置(PowerShell)

1
2
3
4
5
6
7
8
# 启动SSH Agent服务
Start-Service ssh-agent

# 添加到agent
ssh-add C:\Users\username\.ssh\id_ed25519

# 自动启动agent
Get-Service ssh-agent | Set-Service -StartupType Automatic

四、服务器端配置

4.1 基础SSH服务器配置

/etc/ssh/sshd_config配置

1
2
# 编辑SSH服务器配置
sudo vi /etc/ssh/sshd_config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# === SSH服务器基础配置 ===

# 端口配置
Port 22 # 默认端口
# Port 2222 # 自定义端口

# 协议配置
Protocol 2 # 只使用SSH2

# 监听地址
ListenAddress 0.0.0.0 # 监听所有地址

# === 认证配置 ===

# 启用密钥认证
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# 禁用密码认证(生产环境推荐)
# PasswordAuthentication no

# Root登录控制
PermitRootLogin prohibit-password # 只允许密钥登录
# PermitRootLogin no # 完全禁止
# PermitRootLogin yes # 允许(不推荐)

# === 其他配置 ===

# 空闲超时
ClientAliveInterval 300 # 300秒
ClientAliveCountMax 2 # 最多2次

# 并发连接限制
MaxStartups 10:30:100

# 禁用X11转发
X11Forwarding no

# 允许的认证方法
AuthenticationMethods publickey

# 日志级别
LogLevel INFO

重启SSH服务

1
2
3
4
5
6
7
8
9
10
11
# 检查配置语法
sudo sshd -t

# 重启SSH服务
sudo systemctl restart sshd

# 或者重新加载配置(不中断现有连接)
sudo systemctl reload sshd

# 查看状态
sudo systemctl status sshd

4.2 authorized_keys管理

设置正确的权限

1
2
3
4
5
6
7
8
9
# 设置.ssh目录权限
chmod 700 ~/.ssh

# 设置authorized_keys权限
chmod 600 ~/.ssh/authorized_keys

# 设置目录所有者
chown user:user ~/.ssh
chown user:user ~/.ssh/authorized_keys

authorized_keys文件内容格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 基本格式(每行一个公钥)
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJxxx your_email@example.com

# 带选项的格式
command="/usr/bin/maintenance" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJxxx admin@example.com

# 限制来源IP
from="192.168.1.0/24" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJxxx deploy@example.com

# 限制执行命令
command="/usr/bin/backup.sh",no-pty ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJxxx backup@example.com

# 组合选项
from="192.168.1.0/24",command="/usr/bin/maintenance",no-port-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJxxx operator@example.com

五、自动化配置脚本

5.1 一键配置脚本

完整的密钥部署脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/bin/bash
# deploy_ssh_key.sh - 一键部署SSH密钥

# 配置变量
SERVER="$1"
USERNAME="$2"
SSH_PORT="${3:-22}"
KEY_FILE="${4:-~/.ssh/id_ed25519.pub}"

# 检查参数
if [ -z "$SERVER" ] || [ -z "$USERNAME" ]; then
echo "用法: $0 <服务器IP> <用户名> [SSH端口] [密钥文件]"
echo "示例: $0 192.168.1.10 root 22 ~/.ssh/id_ed25519.pub"
exit 1
fi

# 检查密钥文件
if [ ! -f "$KEY_FILE" ]; then
echo "错误: 密钥文件不存在: $KEY_FILE"
exit 1
fi

echo "=== SSH密钥部署 ==="
echo "服务器: $SERVER"
echo "用户: $USERNAME"
echo "端口: $SSH_PORT"
echo "密钥文件: $KEY_FILE"
echo ""

# 读取公钥
PUBLIC_KEY=$(cat "$KEY_FILE")

# 使用ssh-copy-id部署
echo "正在部署密钥..."
if ssh-copy-id -i "$KEY_FILE" -p "$SSH_PORT" "$USERNAME@$SERVER" > /dev/null 2>&1; then
echo "✓ 密钥部署成功"
echo ""

# 测试连接
echo "测试连接..."
if ssh -i "$KEY_FILE" -p "$SSH_PORT" "$USERNAME@$SERVER" -o ConnectTimeout=5 "echo '连接成功'" > /dev/null 2>&1; then
echo "✓ SSH密钥登录测试成功"
else
echo "✗ SSH密钥登录测试失败"
fi
else
echo "✗ 密钥部署失败"
echo ""
echo "请手动执行:"
echo " ssh-copy-id -i $KEY_FILE -p $SSH_PORT $USERNAME@$SERVER"
fi

5.2 批量部署脚本

批量部署到多台服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/bash
# batch_deploy_ssh_keys.sh - 批量部署SSH密钥

# 服务器列表
declare -a SERVERS=(
"user@192.168.1.10:22"
"user@192.168.1.11:22"
"user@192.168.1.12:2222"
)

# 密钥文件
KEY_FILE="${1:-~/.ssh/id_ed25519.pub}"

echo "=== 批量部署SSH密钥 ==="
echo "密钥文件: $KEY_FILE"
echo ""

# 检查密钥文件
if [ ! -f "$KEY_FILE" ]; then
echo "错误: 密钥文件不存在: $KEY_FILE"
exit 1
fi

# 部署到每台服务器
for server_config in "${SERVERS[@]}"; do
IFS=':' read -r server port <<< "$server_config"
IFS='@' read -r user host <<< "$server"

echo "部署到: $user@$host (端口: $port)"

if ssh-copy-id -i "$KEY_FILE" -p "$port" "$user@$host" > /dev/null 2>&1; then
echo " ✓ 部署成功"

# 测试连接
if ssh -i "$KEY_FILE" -p "$port" "$user@$host" -o ConnectTimeout=3 "echo 'OK'" > /dev/null 2>&1; then
echo " ✓ 测试通过"
else
echo " ✗ 测试失败"
fi
else
echo " ✗ 部署失败"
fi
echo ""
done

echo "批量部署完成"

5.3 使用Ansible部署

Ansible Playbook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# deploy_ssh_keys.yml

---
- name: 部署SSH密钥
hosts: servers
become: yes
vars:
deploy_user: deploy

tasks:
- name: 确保.ssh目录存在
file:
path: "/home/{{ deploy_user }}/.ssh"
state: directory
mode: '0700'
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"

- name: 部署SSH公钥
authorized_key:
user: "{{ deploy_user }}"
state: present
key: "{{ lookup('file', 'keys/' + deploy_user + '.pub') }}"

- name: 设置authorized_keys权限
file:
path: "/home/{{ deploy_user }}/.ssh/authorized_keys"
mode: '0600'
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"

- name: 配置SSH服务器
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^{{ item.name }}"
line: "{{ item.config }}"
backup: yes
vars:
sshd_config:
- { name: 'PubkeyAuthentication', config: 'PubkeyAuthentication yes' }
- { name: 'PasswordAuthentication', config: 'PasswordAuthentication no' }
- { name: 'PermitRootLogin', config: 'PermitRootLogin prohibit-password' }
notify:
- restart sshd

handlers:
- name: restart sshd
systemd:
name: sshd
state: restarted

六、故障排查

6.1 常见问题

问题1: 连接仍然要求密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 检查项:
# 1. 密钥是否已部署
ls -la ~/.ssh/authorized_keys

# 2. 权限是否正确
ls -la ~/.ssh/
# .ssh目录应该是700,authorized_keys应该是600

# 3. 密钥内容是否正确
cat ~/.ssh/authorized_keys | grep "$(whoami)@"

# 4. SSH配置是否启用密钥认证
grep PubkeyAuthentication /etc/ssh/sshd_config

# 5. 查看SSH日志
sudo tail -f /var/log/auth.log

# 调试模式(查看详细信息)
ssh -vv user@server

问题2: Permission denied (publickey)

1
2
3
4
5
6
7
8
9
10
11
# 检查私钥权限
ls -l ~/.ssh/id_*

# 私钥权限应该是600
chmod 600 ~/.ssh/id_ed25519

# 检查密钥是否加载到agent
ssh-add -l

# 检查客户端配置
ssh -v user@server

问题3: Too many authentication failures

1
2
3
4
5
6
7
8
9
# 解决方案1: 指定使用的密钥
ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes user@server

# 解决方案2: 配置ssh config
# Host *
# IdentitiesOnly yes

# 解决方案3: 限制服务器端接受的密钥数量
# 在sshd_config中设置: MaxAuthTries 3

6.2 排查脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/bash
# troubleshoot_ssh_key.sh - SSH密钥故障排查

echo "=== SSH密钥故障排查 ==="
echo ""

# 1. 检查本地密钥
echo "1. 本地密钥:"
if [ -f ~/.ssh/id_ed25519.pub ]; then
echo " ✓ 公钥存在"
echo " 指纹: $(ssh-keygen -lf ~/.ssh/id_ed25519.pub)"
else
echo " ✗ 公钥不存在"
fi
echo ""

# 2. 检查SSH agent
echo "2. SSH Agent状态:"
if [ -n "$SSH_AUTH_SOCK" ]; then
echo " ✓ Agent运行中"
echo " 已加载的密钥:"
ssh-add -l
else
echo " ✗ Agent未运行"
fi
echo ""

# 3. 检查服务器配置(需要密码登录)
echo "3. 服务器SSH配置:"
# 这需要密码或已有密钥
# ssh user@server "grep -E 'PubkeyAuthentication|PasswordAuthentication' /etc/ssh/sshd_config"
echo ""

# 4. 测试连接
read -p "输入服务器地址 (user@host): " SERVER

echo ""
echo "4. 测试连接(详细信息):"
ssh -vv $SERVER 2>&1 | grep -E "(Offering|Authenticating|Authentication)"

七、安全最佳实践

7.1 密钥管理最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SSH密钥安全最佳实践:
密钥生成:
1. 使用Ed25519(优先)或4096位RSA
2. 为密钥添加有意义的注释
3. 私钥设置强密码保护
4. 定期轮换密钥

密钥保护:
1. 私钥权限设置为600
2. 不要分享私钥
3. 私钥加密存储
4. 备份私钥到安全位置

密钥部署:
1. 使用ssh-copy-id安全部署
2. 确保authorized_keys权限正确
3. 定期审查授权密钥
4. 及时撤销离职员工密钥

服务器配置:
1. 禁用密码认证
2. 更改默认SSH端口
3. 启用密钥认证
4. 定期审计SSH日志

7.2 密钥轮换流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/bin/bash
# rotate_ssh_keys.sh - 密钥轮换脚本

echo "=== SSH密钥轮换 ==="
echo ""

# 1. 生成新密钥
echo "1. 生成新密钥..."
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_new -C "$(whoami)@$(hostname)-$(date +%Y%m%d)"

# 2. 部署新密钥(保持旧密钥)
echo ""
echo "2. 部署新密钥到服务器..."
for server in "user@server1" "user@server2"; do
echo "部署到: $server"
ssh-copy-id -i ~/.ssh/id_ed25519_new.pub $server
done

# 3. 测试新密钥
echo ""
echo "3. 测试新密钥..."
for server in "user@server1" "user@server2"; do
echo "测试: $server"
ssh -i ~/.ssh/id_ed25519_new -o IdentitiesOnly=yes $server "echo '新密钥工作正常'" || echo "失败"
done

# 4. 等待验证期(例如一周)
echo ""
echo "4. 验证期结束,请确认新密钥正常工作后:"
echo " - 从服务器删除旧公钥"
echo " - 备份旧私钥"
echo " - 重命名新密钥:"
echo " mv ~/.ssh/id_ed25519_new ~/.ssh/id_ed25519"
echo " mv ~/.ssh/id_ed25519_new.pub ~/.ssh/id_ed25519.pub"

八、总结

SSH密钥登录是最简单、最安全的远程访问方式。本文提供了:

核心要点

  1. 快速配置:三步即可完成配置
  2. 多种部署方式:ssh-copy-id、手动部署、自动化脚本
  3. 客户端配置:详细Config配置和Agent管理
  4. 自动化部署:一键脚本、Ansible Playbook

快速参考

1
2
3
4
5
6
7
8
9
10
11
# 快速开始
ssh-keygen -t ed25519 # 生成密钥
ssh-copy-id user@server # 部署密钥
ssh user@server # 测试登录

# 指定密钥
ssh -i ~/.ssh/id_ed25519 user@server # 使用指定密钥
ssh-add ~/.ssh/id_ed25519 # 添加到agent

# 查看连接信息
ssh -vv user@server # 详细调试信息

实践建议

  1. 密钥生成:Ed25519或4096位RSA,加密保护
  2. 快速部署:使用ssh-copy-id,验证权限与内容
  3. 批量配置:结合Ansible/Terraform
  4. 定期轮换:至少每季度一次;定期审计authorized_keys

通过以上配置,可提升安全性并简化访问。