SSH密钥认证架构实战:禁用密码登录、密钥管理与企业级安全访问控制

一、SSH密钥认证概述

1.1 SSH认证方式对比

SSH支持多种认证方式,各有优缺点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SSH认证方式对比:
密码认证 (Password Authentication):
优点: 设置简单、使用方便
缺点: 容易被暴力破解、不安全
建议: 生产环境禁用

密钥认证 (Public Key Authentication):
优点: 安全性高、可免密登录
缺点: 密钥管理复杂
建议: 生产环境优先使用

多因素认证 (MFA):
优点: 安全性极高
缺点: 配置复杂、用户体验稍差
建议: 关键系统使用

1.2 SSH密钥认证架构

SSH密钥认证优势

  • 安全性高:非对称加密,私钥不出服务器
  • 自动化:免密登录,适合自动化运维
  • 可审计:每把密钥可追溯
  • 管理灵活:支持密钥撤销、轮换

二、SSH密钥生成与管理

2.1 密钥对生成

生成SSH密钥对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 基本生成命令
ssh-keygen -t rsa -b 4096 -C "user@example.com"

# 参数说明:
# -t rsa: 密钥类型(rsa/ed25519/ecdsa)
# -b 4096: 密钥长度
# -C: 注释(通常是邮箱)
# -f: 指定密钥文件名

# 生成ed25519密钥(推荐,更安全更快)
ssh-keygen -t ed25519 -C "user@example.com"

# 生成特定文件名的密钥
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_server1 -C "user@server1"

# 生成不带密码保护的密钥(用于自动化)
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519_auto

密钥类型对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SSH密钥类型对比:
RSA:
长度: 2048, 3072, 4096
兼容性: 最好
性能: 较慢
安全: 良好(4096位推荐)
推荐场景: 兼容性要求高

ECDSA:
长度: 256, 384, 521
兼容性: 一般
性能: 较快
安全: 良好
推荐场景: 性能要求高

Ed25519 (推荐):
长度: 256
兼容性: 现代系统支持
性能: 最快
安全: 最强
推荐场景: 新系统优先使用

2.2 密钥查看与管理

密钥文件说明

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

# 输出示例:
# -rw------- id_ed25519 # 私钥(绝密)
# -rw-r--r-- id_ed25519.pub # 公钥(可分享)
# -rw-r--r-- authorized_keys # 服务器授权密钥
# -rw-r--r-- known_hosts # 已知主机指纹

密钥内容查看

1
2
3
4
5
6
7
8
9
10
11
# 查看公钥内容
cat ~/.ssh/id_ed25519.pub

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

# 查看私钥指纹(用于验证)
ssh-keygen -lf ~/.ssh/id_ed25519.pub

# 查看服务器上的授权密钥
cat ~/.ssh/authorized_keys

2.3 多密钥管理

配置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
# ~/.ssh/config - SSH客户端配置

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

# 服务器2配置
Host server2
HostName prod-server.example.com
User deploy
IdentityFile ~/.ssh/id_ed25519_prod
Port 22

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

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

# 通用配置
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3
Compression yes

三、配置SSH服务器

3.1 服务器端配置

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
44
# 编辑SSH服务器配置
sudo vi /etc/ssh/sshd_config

# 关键配置项:

# 1. 禁用密码认证(启用密钥认证)
PasswordAuthentication no
PubkeyAuthentication yes

# 2. 允许root登录(仅通过密钥)
PermitRootLogin prohibit-password

# 3. 修改SSH端口(可选,增加安全性)
Port 2222

# 4. 禁用其他认证方式
ChallengeResponseAuthentication no
UsePAM no

# 5. 密钥文件路径
AuthorizedKeysFile .ssh/authorized_keys

# 6. 强制用户使用正确的权限
StrictModes yes

# 7. 限制登录尝试
MaxAuthTries 3

# 8. 启用日志
SyslogFacility AUTH
LogLevel INFO

# 9. 会话保活
ClientAliveInterval 300
ClientAliveCountMax 2

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

# 11. 仅允许特定用户
AllowUsers user1 user2

# 12. 或允许特定组
AllowGroups developers operators

重启SSH服务

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

# 重启SSH服务
sudo systemctl restart sshd

# 保持当前SSH连接的情况下重新加载配置(推荐)
sudo systemctl reload sshd

3.2 authorized_keys管理

添加公钥到服务器

1
2
3
4
5
6
7
8
9
10
11
12
# 方法1: 直接追加
cat id_ed25519.pub >> ~/.ssh/authorized_keys

# 方法2: 使用ssh-copy-id(推荐)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

# 方法3: 手动复制
scp id_ed25519.pub user@server:~/.ssh/authorized_keys

# 设置正确的权限
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

authorized_keys文件格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# authorized_keys文件格式
# 每行一个公钥,可选选项

# 基本格式
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxx user@example.com

# 带选项
command="/usr/bin/backup.sh" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxx user@example.com

# 多个选项
from="192.168.1.0/24",no-agent-forwarding,no-port-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxx user@example.com

# 限制用户身份
command="/usr/bin/maintenance.sh",no-pty ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxx maintenance@example.com

authorized_keys选项说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
authorized_keys选项:
command: 执行指定命令而非shell
示例: command="/usr/bin/backup.sh"

from: 限制来源IP
示例: from="192.168.1.0/24,10.0.0.0/8"

no-port-forwarding: 禁止端口转发
示例: no-port-forwarding

no-agent-forwarding: 禁止agent转发
示例: no-agent-forwarding

no-pty: 禁止TTY分配
示例: no-pty

no-X11-forwarding: 禁止X11转发
示例: no-X11-forwarding

permit-open: 允许端口转发到指定地址
示例: permit-open="localhost:8080"

expires-on: 密钥过期时间
示例: expires-on="2025-12-31"

3.3 密钥分发脚本

批量密钥分发脚本

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
#!/bin/bash
# deploy_keys.sh - 批量部署SSH密钥

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

# 服务器列表
SERVERS=(
"user@192.168.1.10"
"user@192.168.1.11"
"user@192.168.1.12"
)

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

PUBLIC_KEY=$(cat "$KEY_FILE")

echo "=== 批量部署SSH密钥 ==="
echo ""

for server in "${SERVERS[@]}"; do
echo "部署到: $server"

# 使用ssh-copy-id部署
if ssh-copy-id -i "$KEY_FILE" "$server" > /dev/null 2>&1; then
echo " ✓ 部署成功"
else
echo " ✗ 部署失败"
echo " 手动命令: ssh $server 'echo \"$PUBLIC_KEY\" >> ~/.ssh/authorized_keys'"
fi
echo ""
done

echo "部署完成"

四、禁用密码登录配置

4.1 完整安全配置

生产环境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
# /etc/ssh/sshd_config

# 基本配置
Port 2222 # 修改默认端口
Protocol 2 # 只使用SSH2

# 认证配置
PermitRootLogin prohibit-password # 禁止root密码登录
PasswordAuthentication no # 禁用密码认证
PubkeyAuthentication yes # 启用密钥认证
AuthorizedKeysFile .ssh/authorized_keys # 密钥文件路径
AuthorizedPrincipalsFile none # 禁用principals文件

# 禁用其他认证方式
ChallengeResponseAuthentication no
UsePAM no
KerberosAuthentication no
GSSAPIAuthentication no

# 安全配置
StrictModes yes # 严格检查文件权限
MaxAuthTries 3 # 最大认证尝试次数
LoginGraceTime 60 # 登录宽限期60秒

# 会话配置
ClientAliveInterval 300 # 客户端保活300秒
ClientAliveCountMax 2 # 最大保活次数2
MaxStartups 10:30:100 # 并发连接限制

# 日志配置
SyslogFacility AUTH
LogLevel INFO
VerboseLogging no

# 限制配置
AllowUsers user1 user2 # 只允许特定用户
# AllowGroups developers operators # 允许特定组

# 禁用功能
X11Forwarding no # 禁用X11转发
AllowAgentForwarding no # 禁用agent转发
PermitTunnel no # 禁用tunnel

# TCP Wrappers(可选)
# hosts.deny 和 hosts.allow 配置

4.2 渐进式禁用密码登录

过渡期配置

在完全禁用密码登录前,建议逐步过渡:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 阶段1: 同时允许密码和密钥
PasswordAuthentication yes
PubkeyAuthentication yes

# 阶段2: 禁止root密码登录,普通用户仍可密码登录
PermitRootLogin prohibit-password
PasswordAuthentication yes

# 阶段3: 限制密码登录的尝试次数
PasswordAuthentication yes
MaxAuthTries 3

# 阶段4: 完全禁用密码(最终目标)
PasswordAuthentication no
PubkeyAuthentication yes

测试配置

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
#!/bin/bash
# test_ssh_config.sh - 测试SSH配置

echo "=== SSH配置测试 ==="

# 1. 检查配置语法
echo "1. 检查SSH配置语法:"
if sudo sshd -t 2>/dev/null; then
echo " ✓ 配置语法正确"
else
echo " ✗ 配置有语法错误"
exit 1
fi
echo ""

# 2. 测试密码登录(应该失败)
echo "2. 测试密码登录(应该失败):"
if ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no test@localhost -n -q exit; then
echo " ✗ 密码登录未禁用,存在安全风险!"
else
echo " ✓ 密码登录已正确禁用"
fi
echo ""

# 3. 测试密钥登录
echo "3. 测试密钥登录:"
if ssh -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes test@localhost -n -q exit; then
echo " ✓ 密钥登录正常"
else
echo " ✗ 密钥登录失败,检查密钥配置"
fi
echo ""

# 4. 检查当前配置
echo "4. 当前SSH配置:"
echo " 端口: $(grep ^Port /etc/ssh/sshd_config | awk '{print $2}')"
echo " 密码认证: $(grep ^PasswordAuthentication /etc/ssh/sshd_config | awk '{print $2}')"
echo " 密钥认证: $(grep ^PubkeyAuthentication /etc/ssh/sshd_config | awk '{print $2}')"
echo " Root登录: $(grep ^PermitRootLogin /etc/ssh/sshd_config | awk '{print $2}')"
echo ""

echo "测试完成"

五、企业级密钥管理

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
# 环境隔离的密钥配置
# ~/.ssh/config

# 开发环境
Host dev-*
IdentityFile ~/.ssh/id_ed25519_dev
StrictHostKeyChecking yes
UserKnownHostsFile ~/.ssh/known_hosts_dev

Host dev-web
HostName dev-web.example.com
User deploy

Host dev-db
HostName dev-db.example.com
User admin

# 测试环境
Host test-*
IdentityFile ~/.ssh/id_ed25519_test
StrictHostKeyChecking yes
UserKnownHostsFile ~/.ssh/known_hosts_test

Host test-web
HostName test-web.example.com
User deploy

# 生产环境(需要密码)
Host prod-*
IdentityFile ~/.ssh/id_ed25519_prod
StrictHostKeyChecking yes
UserKnownHostsFile ~/.ssh/known_hosts_prod
# 强制使用密码短语
IdentitiesOnly yes
AddKeysToAgent no

Host prod-web
HostName prod-web.example.com
User deploy

Host prod-db
HostName prod-db.example.com
User admin

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
#!/bin/bash
# rotate_keys.sh - 密钥轮换脚本

KEY_DIR=~/.ssh
BACKUP_DIR=~/.ssh/backup/$(date +%Y%m%d)

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

# 1. 备份旧密钥
echo "1. 备份旧密钥:"
mkdir -p "$BACKUP_DIR"
cp "$KEY_DIR"/*.pub "$KEY_DIR"/*_pub "$BACKUP_DIR/" 2>/dev/null
echo " 备份目录: $BACKUP_DIR"
echo ""

# 2. 生成新密钥对
echo "2. 生成新密钥对:"
for env in dev test prod; do
NEW_KEY="$KEY_DIR/id_ed25519_${env}_new"
ssh-keygen -t ed25519 -f "$NEW_KEY" -N "" -C "${env}-$(date +%Y%m%d)"

echo " 生成: $NEW_KEY"
echo " 公钥: $NEW_KEY.pub"

# 显示公钥
echo " 公钥内容:"
cat "$NEW_KEY.pub"
echo ""
done

echo "新密钥已生成,请手动部署到服务器"

5.3 密钥审计与监控

密钥使用审计

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
#!/bin/bash
# audit_ssh_keys.sh - SSH密钥审计

echo "=== SSH密钥使用审计 ==="
echo "审计时间: $(date)"
echo ""

# 1. 列出所有授权密钥
echo "1. 服务器上的授权密钥:"
for user in $(cut -d: -f1 /etc/passwd); do
auth_keys="/home/$user/.ssh/authorized_keys"
if [ -f "$auth_keys" ]; then
echo "用户: $user"
echo " 密钥数量: $(grep -c "^ssh-" "$auth_keys" 2>/dev/null || echo 0)"
echo " 密钥列表:"
grep "^ssh-" "$auth_keys" 2>/dev/null | while read key; do
echo " $(echo $key | awk '{print $NF}')"
done
echo ""
fi
done

# 2. 检查最近的SSH登录
echo "2. 最近的SSH登录记录:"
if [ -f /var/log/auth.log ]; then
grep "Accepted publickey" /var/log/auth.log | tail -20
elif [ -f /var/log/secure ]; then
grep "Accepted publickey" /var/log/secure | tail -20
fi
echo ""

# 3. 检查权限问题
echo "3. 检查文件权限:"
for user in $(cut -d: -f1 /etc/passwd); do
ssh_dir="/home/$user/.ssh"
if [ -d "$ssh_dir" ]; then
perms=$(stat -c "%a" "$ssh_dir" 2>/dev/null)
if [ "$perms" != "700" ]; then
echo " 警告: $ssh_dir 权限不正确: $perms (应该是700)"
fi

auth_keys="$ssh_dir/authorized_keys"
if [ -f "$auth_keys" ]; then
perms=$(stat -c "%a" "$auth_keys" 2>/dev/null)
if [ "$perms" != "600" ]; then
echo " 警告: $auth_keys 权限不正确: $perms (应该是600)"
fi
fi
fi
done
echo ""

# 4. 检查未使用的密钥
echo "4. 最近使用的SSH密钥:"
lastlog -t 7 | awk '{print $1}' | while read user; do
auth_keys="/home/$user/.ssh/authorized_keys"
if [ -f "$auth_keys" ]; then
echo "用户 $user 最近登录: $(lastlog -u $user | tail -1)"
fi
done
echo ""

echo "审计完成"

六、多因素认证(MFA)

6.1 SSH MFA配置

使用Google Authenticator

1
2
3
4
5
6
7
8
9
10
# 安装Google Authenticator
sudo yum install google-authenticator
# 或
sudo apt-get install libpam-google-authenticator

# 运行配置
google-authenticator

# 配置PAM
sudo vi /etc/pam.d/sshd
1
2
# 添加到PAM配置
auth required pam_google_authenticator.so nullok
1
2
# 修改sshd_config
sudo vi /etc/ssh/sshd_config
1
2
# 启用MFA
AuthenticationMethods publickey,keyboard-interactive

6.2 SSH证书认证

使用SSH CA

1
2
3
4
5
6
7
8
# 1. 生成CA密钥对
ssh-keygen -f ssh_ca_key -t rsa -b 4096

# 2. 签发用户证书
ssh-keygen -s ssh_ca_key -I user_id -n user1 id_ed25519.pub

# 3. 配置服务器信任CA
sudo vi /etc/ssh/sshd_config
1
2
# SSH CA配置
TrustedUserCAKeys /etc/ssh/ca_key.pub

七、密钥管理系统

7.1 企业级密钥管理

密钥管理系统架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
企业级密钥管理:
集中式存储:
- Git仓库管理公钥
- 加密存储私钥
- 版本控制密钥变更

自动化分发:
- Ansible/Terraform部署
- Puppet自动化配置
- 配置即代码

权限管控:
- RBAC权限模型
- 基于角色的访问控制
- 临时权限授予

审计追踪:
- 所有操作记录日志
- 密钥使用审计
- 异常行为检测

使用Ansible管理密钥

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
# roles/ssh_keys/tasks/main.yml

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

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

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

使用Terraform管理密钥

1
2
3
4
5
6
7
8
9
10
11
# ssh_keys.tf

resource "local_file" "authorized_keys" {
count = length(var.servers)
content = file("keys/${var.servers[count.index]}.pub")
filename = "/home/deploy/.ssh/authorized_keys_${var.servers[count.index]}"

provisioner "local-exec" {
command = "scp ${self.filename} deploy@${var.servers[count.index]}:~/.ssh/authorized_keys"
}
}

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
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python
# key_manager.py - 企业级密钥管理系统

import os
import sys
import hashlib
from datetime import datetime
from dataclasses import dataclass
from typing import List, Optional

@dataclass
class SSHKey:
"""SSH密钥实体"""
user: str
public_key: str
key_type: str
fingerprint: str
created_at: datetime
expires_at: Optional[datetime]
servers: List[str]
permissions: str

def is_expired(self) -> bool:
"""检查密钥是否过期"""
if self.expires_at:
return datetime.now() > self.expires_at
return False

class SSHKeyManager:
"""SSH密钥管理器"""

def __init__(self, key_store_path: str):
self.key_store_path = key_store_path
self.keys: List[SSHKey] = []

def add_key(self, user: str, public_key: str, servers: List[str], expires_days: int = 90):
"""添加密钥"""
# 解析密钥
key_parts = public_key.split()
if len(key_parts) < 2:
raise ValueError("Invalid key format")

key_type = key_parts[0]
key_content = key_parts[1]

# 计算指纹
fingerprint = hashlib.md5(key_content.encode()).hexdigest()

# 创建密钥对象
key = SSHKey(
user=user,
public_key=public_key,
key_type=key_type,
fingerprint=fingerprint,
created_at=datetime.now(),
expires_at=datetime.now().timestamp() + (expires_days * 86400) if expires_days else None,
servers=servers,
permissions="user"
)

self.keys.append(key)
return key

def deploy_key(self, key: SSHKey, server: str):
"""部署密钥到服务器"""
cmd = f'ssh {server} "echo \'{key.public_key}\' >> ~/.ssh/authorized_keys"'
os.system(cmd)
print(f"✓ 密钥已部署到 {server}")

def revoke_key(self, fingerprint: str):
"""撤销密钥"""
for i, key in enumerate(self.keys):
if key.fingerprint == fingerprint:
# 从所有服务器撤销
for server in key.servers:
cmd = f'ssh {server} "sed -i \'/{fingerprint}/d\' ~/.ssh/authorized_keys"'
os.system(cmd)
print(f"✓ 密钥已从 {server} 撤销")

self.keys.pop(i)
print(f"✓ 密钥已撤销: {key.user}")
return True
return False

def list_keys(self):
"""列出所有密钥"""
for key in self.keys:
status = "过期" if key.is_expired() else "有效"
print(f"用户: {key.user}")
print(f" 指纹: {key.fingerprint}")
print(f" 类型: {key.key_type}")
print(f" 状态: {status}")
print(f" 服务器: {', '.join(key.servers)}")
print("")

def audit(self):
"""密钥审计"""
print("=== SSH密钥审计 ===")
print(f"总密钥数: {len(self.keys)}")
print(f"过期密钥数: {sum(1 for k in self.keys if k.is_expired())}")
print("")

# 使用示例
if __name__ == "__main__":
manager = SSHKeyManager("/etc/ssh/keys")

# 添加密钥
public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxx user@example.com"
key = manager.add_key("dev1", public_key, ["192.168.1.10", "192.168.1.11"], 90)

# 部署密钥
for server in key.servers:
manager.deploy_key(key, server)

# 列出密钥
manager.list_keys()

# 审计
manager.audit()

八、故障排查

8.1 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
#!/bin/bash
# troubleshoot_ssh.sh - SSH密钥认证故障排查

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

# 1. 检查SSH配置
echo "1. SSH服务器配置:"
echo " 密码认证: $(sudo grep ^PasswordAuthentication /etc/ssh/sshd_config | awk '{print $2}')"
echo " 密钥认证: $(sudo grep ^PubkeyAuthentication /etc/ssh/sshd_config | awk '{print $2}')"
echo ""

# 2. 检查密钥权限
echo "2. 检查密钥文件权限:"
echo " ~/.ssh 目录权限: $(stat -c "%a" ~/.ssh 2>/dev/null)"
echo " authorized_keys 权限: $(stat -c "%a" ~/.ssh/authorized_keys 2>/dev/null)"
echo ""

# 3. 检查SSH日志
echo "3. 检查SSH认证日志:"
if sudo journalctl -u sshd -n 50 | grep -i "key"; then
echo " 发现密钥相关日志"
else
echo " 未发现密钥日志"
fi
echo ""

# 4. 测试密钥连接
echo "4. 测试密钥连接:"
if ssh -vv user@localhost -o PubkeyAuthentication=yes -o PreferredAuthentications=publickey 2>&1 | grep -i "authentication succeeded"; then
echo " ✓ 密钥认证成功"
else
echo " ✗ 密钥认证失败"
fi
echo ""

# 5. 检查authorized_keys
echo "5. 检查authorized_keys文件:"
if [ -f ~/.ssh/authorized_keys ]; then
echo " 密钥数量: $(grep -c ^ssh- ~/.ssh/authorized_keys)"
echo " 最近修改: $(stat -c "%y" ~/.ssh/authorized_keys)"
else
echo " ✗ authorized_keys文件不存在"
fi
echo ""

echo "排查完成"

九、安全最佳实践

9.1 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
SSH密钥安全最佳实践:
密钥生成:
1. 使用Ed25519密钥(推荐)
2. 密钥长度4096位(RSA)
3. 添加有意义的注释

密钥保护:
1. 私钥设置密码保护
2. 私钥权限600
3. 不要分享私钥
4. 定期轮换密钥

服务器配置:
1. 禁用密码登录
2. 启用密钥认证
3. 设置正确的文件权限
4. 使用非默认端口
5. 启用日志审计

密钥管理:
1. 集中式密钥存储
2. 版本控制公钥
3. 自动化密钥部署
4. 定期审计密钥使用

访问控制:
1. 基于角色的权限
2. 最小权限原则
3. 临时权限授予
4. 及时撤销离职员工密钥

9.2 自动化安全加固

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
65
66
67
68
69
70
71
72
#!/bin/bash
# secure_ssh.sh - SSH安全加固脚本

echo "=== SSH安全加固 ==="
echo ""

# 1. 备份SSH配置
echo "1. 备份SSH配置:"
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d)
echo " 备份完成: /etc/ssh/sshd_config.backup.$(date +%Y%m%d)"
echo ""

# 2. 配置SSH
echo "2. 配置SSH安全选项:"

# 禁用密码认证
sudo sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config

# 启用密钥认证
sudo sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/^PubkeyAuthentication no/PubkeyAuthentication yes/' /etc/ssh/sshd_config

# 禁止root密码登录
sudo sed -i 's/^#PermitRootLogin yes/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config

# 设置最大认证次数
sudo sed -i 's/^#MaxAuthTries 6/MaxAuthTries 3/' /etc/ssh/sshd_config

# 设置会话超时
sudo sed -i 's/^#ClientAliveInterval 0/ClientAliveInterval 300/' /etc/ssh/sshd_config
sudo sed -i 's/^#ClientAliveCountMax 3/ClientAliveCountMax 2/' /etc/ssh/sshd_config

echo " ✓ SSH配置已更新"
echo ""

# 3. 创建部署密钥的用户
echo "3. 创建部署用户:"
if ! id deploy &>/dev/null; then
sudo useradd -m -s /bin/bash deploy
sudo mkdir -p /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chown deploy:deploy /home/deploy/.ssh
echo " ✓ 已创建deploy用户"
else
echo " ✓ deploy用户已存在"
fi
echo ""

# 4. 重启SSH服务
echo "4. 重启SSH服务:"
if sudo sshd -t; then
echo " ✓ 配置语法正确"
sudo systemctl restart sshd
echo " ✓ SSH服务已重启"
else
echo " ✗ 配置语法错误,请检查"
exit 1
fi
echo ""

# 5. 显示新配置
echo "5. 当前配置:"
echo " 密码认证: $(sudo grep ^PasswordAuthentication /etc/ssh/sshd_config | awk '{print $2}')"
echo " 密钥认证: $(sudo grep ^PubkeyAuthentication /etc/ssh/sshd_config | awk '{print $2}')"
echo " Root登录: $(sudo grep ^PermitRootLogin /etc/ssh/sshd_config | awk '{print $2}')"
echo ""

echo "加固完成"
echo ""
echo "⚠️ 重要提示:确保已将公钥添加到服务器,否则将被锁定!"
echo " 现在可以使用当前SSH会话测试新配置"

十、总结

SSH密钥认证是提升服务器安全的重要手段。本文探讨了:

核心要点

  1. 密钥管理:生成、分发、轮换
  2. 禁用密码登录:配置与测试
  3. 企业级管理:集中化、自动化、审计
  4. 安全最佳实践:密钥保护、权限控制、访问审计

技术栈

  • 密钥生成:ed25519、RSA、ECDSA
  • 服务器配置:sshd_config配置
  • 密钥管理:Git、Ansible、Terraform
  • 安全整合:MFA、auditd、Fail2ban

实践建议

  1. 禁用密码登录,仅使用密钥认证
  2. 采用最小权限与定期轮换
  3. 集中管理和审计追踪
  4. 自动化部署与撤销
  5. 监控异常登录行为

通过密钥认证架构,平衡操作便利性与服务器安全。