概述
SSH(Secure Shell)是 Linux 运维的核心通道,也是攻击者的主要目标。一个配置不当的 SSH 服务可能导致服务器被完全接管。从认证机制、服务端硬化、跳板机架构、隧道技术、审计日志到暴力破解防护,全面覆盖 SSH 安全的好的实践。
密钥认证
生成密钥对
# 生成 Ed25519 密钥(推荐)
$ ssh-keygen -t ed25519 -C "admin@sre.wang" -f ~/.ssh/id_ed25519
# 生成 RSA 密钥(兼容性需求,至少 4096 位)
$ ssh-keygen -t rsa -b 4096 -C "admin@sre.wang" -f ~/.ssh/id_rsa
# 生成带密码保护的密钥
$ ssh-keygen -t ed25519 -N "strong-passphrase" -f ~/.ssh/id_ed25519
# 查看密钥指纹
$ ssh-keygen -lf ~/.ssh/id_ed25519.pub
256 SHA256:abc123... admin@sre.wang (ED25519)
密钥算法对比
| 算法 | 密钥长度 | 安全性 | 性能 | 推荐 |
|---|---|---|---|---|
| Ed25519 | 256 位 | 极高 | 极快 | 首选 |
| RSA-4096 | 4096 位 | 高 | 中 | 兼容场景 |
| RSA-2048 | 2048 位 | 中 | 快 | 不推荐 |
| ECDSA | 256/384/521 | 高 | 快 | 有争议(NIST 曲线) |
| DSA | 1024 位 | 低 | - | 已废弃 |
部署公钥
# 方式 1:ssh-copy-id(推荐)
$ ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# 方式 2:手动部署
$ cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# 方式 3:批量部署
$ for host in web-{01..10}; do
ssh-copy-id -i ~/.ssh/id_ed25519.pub admin@$host
done
authorized_keys 权限控制
# 正确权限
~/.ssh/ → 700
~/.ssh/authorized_keys → 600
私钥文件 → 600
# authorized_keys 中可限制公钥的权限
# 限制来源 IP
from="10.0.0.0/8" ssh-ed25519 AAAAC3... admin@sre.wang
# 限制命令
command="/usr/bin/rsync --server" ssh-ed25519 AAAAC3... backup@sre.wang
# 限制端口转发
no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAAC3... user@sre.wang
# 组合限制
from="10.0.0.0/8",command="/usr/bin/backup.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAAC3... backup@sre.wang
证书认证
传统密钥认证的问题
- 每台服务器需要部署用户的公钥
- 密钥撤销困难(需要逐台删除)
- 无法设置密钥有效期
- 密钥管理缺乏审计
SSH 证书认证架构
[CA 私钥]
/ \
[签发用户证书] [签发主机证书]
| |
[用户持有证书] [服务器配置可信CA]
| |
[SSH 连接] → [服务器验证证书签名] → [登录成功]
搭建 SSH CA
# 1. 在 CA 服务器上生成 CA 密钥对
$ ssh-keygen -t ed25519 -f ~/.ssh/ca_user_key -C "SSH User CA"
# 不要设置 passphrase(自动化签发需要)
# 2. 签发用户证书
$ ssh-keygen -s ~/.ssh/ca_user_key \
-I "admin_user" \
-n admin,root \
-V +1d \
~/.ssh/id_ed25519.pub
# -I: 证书标识(用于审计)
# -n: 允许登录的用户名
# -V: 有效期(+1d = 1 天)
# 生成证书文件: ~/.ssh/id_ed25519-cert.pub
# 3. 在目标服务器配置信任 CA
$ cat ~/.ssh/ca_user_key.pub >> /etc/ssh/user_ca.pub
# 在 /etc/ssh/sshd_config 中添加:
# TrustedUserCAKeys /etc/ssh/user_ca.pub
# 4. 重启 sshd
$ systemctl restart sshd
主机证书(免 known_hosts 确认)
# 1. 在服务器上生成主机密钥对(如果没有)
$ ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
# 2. 用 CA 签发主机证书
$ ssh-keygen -s ~/.ssh/ca_user_key \
-I "web01.sre.wang" \
-h \
-n web01.sre.wang,web01 \
-V +52w \
/etc/ssh/ssh_host_ed25519_key.pub
# 3. 配置 sshd 使用主机证书
# /etc/ssh/sshd_config
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
# 4. 客户端配置信任 CA
# ~/.ssh/known_hosts 或 /etc/ssh/ssh_known_hosts
@cert-authority *.sre.wang ssh-ed25519 AAAAC3...
证书撤销
# 创建撤销列表
$ cat > /etc/ssh/revoked_keys << 'EOF'
ssh-ed25519 AAAAC3... revoked-key-1
ssh-ed25519 AAAAC3... revoked-key-2
EOF
# 在 sshd_config 中配置
RevokedKeys /etc/ssh/revoked_keys
# 或使用 KRL(Key Revocation List)
$ ssh-keygen -k -f revoked_krl -s ~/.ssh/ca_user_key ~/.ssh/id_ed25519.pub
# 在 sshd_config 中配置
RevokedKeys /etc/ssh/revoked_krl
sshd_config 硬化
安全基线配置
# /etc/ssh/sshd_config
# === 协议与加密 ===
Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
# 禁用弱密钥
# HostKey /etc/ssh/ssh_host_rsa_key
# HostKey /etc/ssh/ssh_host_ecdsa_key
# 加密算法(仅允许强算法)
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman16-sha512
# === 认证 ===
PermitRootLogin no # 禁止 root 直接登录
PasswordAuthentication no # 禁用密码认证
KbdInteractiveAuthentication no # 禁用键盘交互认证
ChallengeResponseAuthentication no
PubkeyAuthentication yes # 启用密钥认证
PermitEmptyPasswords no # 禁止空密码
# CA 证书认证
TrustedUserCAKeys /etc/ssh/user_ca.pub
# === 访问控制 ===
AllowUsers admin deploy # 白名单用户
AllowGroups ssh-users # 白名单用户组
DenyUsers nobody guest # 黑名单用户
# 来源限制(通过 Match)
Match Address 10.0.0.0/8
AllowUsers admin root
PermitRootLogin yes
# === 会话控制 ===
MaxAuthTries 3 # 最大认证尝试次数
MaxSessions 10 # 最大会话数
MaxStartups 10:30:60 # 并发未认证连接限制
LoginGraceTime 30 # 认证超时(秒)
# === 超时设置 ===
ClientAliveInterval 300 # 活跃检查间隔(秒)
ClientAliveCountMax 2 # 最多检查次数
# 300 × 2 = 600 秒后断开空闲连接
# === 日志 ===
LogLevel VERBOSE # 详细日志
SyslogFacility AUTHPRIV
PrintMotd no # 不打印 MOTD
PrintLastLog yes # 显示上次登录时间
# === 转发 ===
AllowTcpForwarding yes # 根据需求配置
X11Forwarding no # 禁用 X11 转发
AllowAgentForwarding no # 禁用 Agent 转发
PermitTunnel no # 禁用隧道
# === 其他 ===
UseDNS no # 禁用 DNS 反查(加速登录)
GSSAPIAuthentication no # 禁用 GSSAPI(加速登录)
Banner /etc/ssh/banner # 登录前提示
配置验证与重载
# 验证配置语法(重要!)
$ sshd -t
# 重载配置(不断开现有连接)
$ systemctl reload sshd
# 或
$ systemctl reload ssh
# 验证当前生效配置
$ sshd -T | grep -E "permitroot|passwordauth|maxauth"
安全操作流程:修改 sshd_config 后,务必保持当前 SSH 会话不断开,另开一个终端测试新配置是否可以正常登录。如果配置有误,可以用原会话恢复。
各参数安全影响
| 参数 | 默认值 | 安全值 | 风险说明 |
|---|---|---|---|
PermitRootLogin | yes | no | root 直接登录被攻破即获最高权限 |
PasswordAuthentication | yes | no | 密码可被暴力破解 |
MaxAuthTries | 6 | 3 | 降低暴力破解窗口 |
ClientAliveInterval | 0 | 300 | 空闲连接被劫持 |
X11Forwarding | yes | no | X11 协议有安全漏洞 |
AllowTcpForwarding | yes | 按需 | 可用于构建隧道绕过防火墙 |
UseDNS | yes | no | DNS 反查延迟 + DNS 欺骗风险 |
SSH 跳板机
跳板机架构
[运维人员] → [跳板机/Bastion] → [内网服务器]
SSH SSH
(公网可达) (仅内网可达)
ProxyJump 方式(推荐)
# ~/.ssh/config
Host bastion
HostName bastion.sre.wang
User admin
Port 2222
IdentityFile ~/.ssh/id_ed25519
Host web-*
User deploy
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion # 通过跳板机连接
# 或使用旧语法
# ProxyCommand ssh -W %h:%p bastion
Host web-01
HostName 10.0.1.10
Host web-02
HostName 10.0.1.11
Host web-03
HostName 10.0.1.12
# 使用:直接连接内网服务器
$ ssh web-01
# 实际路径: 运维人员 → bastion → web-01
多级跳板
# ~/.ssh/config
Host bastion-1
HostName bastion1.sre.wang
User admin
Host bastion-2
HostName 10.0.0.2
User admin
ProxyJump bastion-1 # 通过第一级跳板
Host internal-db
HostName 192.168.1.100
User dba
ProxyJump bastion-2 # 通过第二级跳板
# 使用
$ ssh internal-db
# 路径: 运维 → bastion-1 → bastion-2 → internal-db
跳板机安全配置
# 跳板机 sshd_config 特殊配置
# /etc/ssh/sshd_config
# 限制跳板机只能转发,不能执行命令
Match Group jump-users
AllowTcpForwarding yes
PermitTTY no
ForceCommand /bin/false # 禁止执行命令
X11Forwarding no
AllowAgentForwarding no
# 或使用受限 shell
Match Group jump-users
ForceCommand /usr/local/bin/ssh-jump-menu
录制跳板机会话
# 使用 tlog 录制会话
$ dnf install tlog
# /etc/sshd_config
ForceCommand /usr/bin/tlog-rec-session
# 或使用 script 命令
# /etc/profile.d/audit.sh
if [ -n "$SSH_CONNECTION" ]; then
LOGDIR=/var/log/ssh-session
mkdir -p $LOGDIR
script -qf $LOGDIR/${USER}_$(date +%Y%m%d_%H%M%S).log
fi
端口转发与反向隧道
本地端口转发
# 将本地 8080 端口转发到远程服务器的 80 端口
$ ssh -L 8080:localhost:80 user@server
# 访问 localhost:8080 = 访问 server:80
# 转发到远程服务器能访问的第三台机器
$ ssh -L 8080:10.0.0.10:80 user@jump-server
# 通过 jump-server 访问 10.0.0.10:80
# 后台运行
$ ssh -fNL 8080:localhost:80 user@server
# 在 ~/.ssh/config 中配置
Host tunnel
HostName server.sre.wang
User admin
LocalForward 8080 localhost:80
远程端口转发(反向隧道)
# 将远程服务器的 9090 端口转发到本地的 80 端口
$ ssh -R 9090:localhost:80 user@remote-server
# 在 remote-server 上访问 localhost:9090 = 访问本地 80
# 典型场景:内网穿透
# 内网机器 → 公网服务器(反向隧道)
$ ssh -fNR 2222:localhost:22 user@public-server
# 在公网服务器上 ssh -p 2222 user@localhost 即可连接内网机器
# 允许远程端口转发绑定到所有接口
# /etc/ssh/sshd_config (在公网服务器上)
GatewayPorts yes
动态端口转发(SOCKS 代理)
# 创建 SOCKS5 代理
$ ssh -D 1080 user@server
# 本地 1080 端口作为 SOCKS5 代理,流量通过 server 转发
# 使用代理
$ curl --socks5 127.0.0.1:1080 http://internal-service:8080
# 浏览器配置 SOCKS5 代理: 127.0.0.1:1080
# 后台运行
$ ssh -fND 1080 user@server
隧道保活
# ~/.ssh/config
Host tunnel
HostName server.sre.wang
User admin
RemoteForward 2222 localhost:22
ServerAliveInterval 60 # 每 60 秒发送心跳
ServerAliveCountMax 3 # 3 次无响应则断开
ExitOnForwardFailure yes # 转发失败则断开
ControlMaster auto # 复用连接
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 600 # 连接保持 10 分钟
# 使用 autossh 自动重连
$ autossh -M 0 -fN tunnel
# -M 0: 禁用监控端口,依赖 ServerAliveInterval
隧道使用场景速查
| 场景 | 命令 | 说明 |
|---|---|---|
| 访问远程数据库 | ssh -L 3306:db:3306 jump | 通过跳板机访问数据库 |
| 内网穿透 | ssh -R 2222:localhost:22 public | 从公网访问内网 |
| SOCKS 代理 | ssh -D 1080 server | 全局代理 |
| 访问内部 Web | ssh -L 8080:internal-web:80 jump | 通过跳板机访问内部 Web |
| 文件传输 | ssh -L 21:ftp:21 jump | 通过隧道访问 FTP |
SSH Agent
工作原理
[SSH Agent] ← [SSH Client] ← [Remote Server]
↑
[私钥存储在 Agent 中]
1. SSH Client 需要认证时,请求 Agent 签名
2. Agent 用私钥签名,但不导出私钥
3. Client 将签名发送给 Server
4. 私钥永远不离开 Agent
基本使用
# 启动 Agent
$ eval $(ssh-agent)
Agent pid 12345
# 添加密钥
$ ssh-add ~/.ssh/id_ed25519
# 如果密钥有 passphrase,会提示输入
# 查看已添加的密钥
$ ssh-add -l
256 SHA256:abc123... admin@sre.wang (ED25519)
# 删除密钥
$ ssh-add -d ~/.ssh/id_ed25519
# 删除所有密钥
$ ssh-add -D
Agent 转发
# 启用 Agent 转发(单次)
$ ssh -A user@jump-server
# 在 jump-server 上可以直接用本地的密钥连接第三台服务器
# 在 ~/.ssh/config 中配置
Host jump-server
ForwardAgent yes
# 安全风险:跳板机上的 root 可以使用你的 Agent
# 生产环境建议使用 ProxyJump 替代 Agent 转发
Agent 安全好的实践
# 1. 设置 Agent 超时
$ ssh-add -t 3600 ~/.ssh/id_ed25519 # 1 小时后自动删除
# 2. 确认签名请求
$ ssh-add -c ~/.ssh/id_ed25519
# 每次使用密钥时需要确认
# 3. 限制 Agent 转发
# 不要在不受信任的服务器上启用 ForwardAgent
# 4. 使用 SSH Agent 代替在服务器上存储私钥
# ❌ 不好的做法:将私钥复制到每台服务器
# ✅ 好的做法:通过 Agent 转发使用本地私钥
审计日志
SSH 日志位置
# Debian/Ubuntu
$ journalctl -u ssh
# 或
$ tail -f /var/log/auth.log
# RHEL/CentOS
$ journalctl -u sshd
# 或
$ tail -f /var/log/secure
关键日志事件
# 登录成功
$ journalctl -u sshd | grep "Accepted"
# Accepted publickey for admin from 10.0.0.1 port 54321 ssh2: ED25519 SHA256:abc123
# 登录失败
$ journalctl -u sshd | grep "Failed"
# Failed password for invalid user admin from 1.2.3.4 port 54321 ssh2
# 无效用户尝试
$ journalctl -u sshd | grep "Invalid"
# Invalid user admin from 1.2.3.4 port 54321
# 连接断开
$ journalctl -u sshd | grep "Disconnected"
# Disconnected from user admin 10.0.0.1 port 54321
# 证书认证
$ journalctl -u sshd | grep "Certificate"
# Certificate ID "admin_user" (serial 0) for user admin from CA accepted
日志分析
# 统计失败登录的来源 IP
$ journalctl -u sshd --since "24 hours ago" | grep "Failed" | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20
# 统计成功登录的用户
$ journalctl -u sshd --since "24 hours ago" | grep "Accepted" | awk '{print $4, $6}' | sort | uniq -c | sort -rn
# 检测暴力破解(同一 IP 多次失败)
$ journalctl -u sshd --since "1 hour ago" | grep "Failed" | awk '{print $NF}' | sort | uniq -c | sort -rn | awk '$1 > 10 {print "ALERT:", $0}'
# 查看当前在线用户
$ who
$ w
$ last -n 20
配置详细日志
# /etc/ssh/sshd_config
LogLevel VERBOSE
# VERBOSE 级别会记录:
# - 密钥指纹
# - 证书 ID
# - 认证方法
# - 端口转发
# 审计日志
# /etc/audit/audit.rules
-w /etc/ssh/sshd_config -p wa -k ssh_config_change
-w /etc/ssh/ -p wa -k ssh_key_change
Fail2ban
工作原理
[SSH 日志] → [Fail2ban 日志解析] → [匹配失败规则] → [调用 iptables/nftables] → [封禁 IP]
↑
[jail.local 配置]
安装与配置
# 安装
$ apt install fail2ban # Debian/Ubuntu
$ dnf install fail2ban # RHEL/CentOS
# 配置(不要直接修改 jail.conf,创建 jail.local)
# /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true
port = ssh
filter = sshd
backend = systemd
maxretry = 3 # 最大失败次数
findtime = 600 # 检测窗口(秒)
bantime = 3600 # 封禁时长(秒)
bantime.increment = true # 递增封禁
bantime.maxtime = 604800 # 最大封禁 7 天
ignoreip = 127.0.0.1/8 10.0.0.0/8 # 白名单
action = iptables-allports # 封禁所有端口
Fail2ban 管理
# 启动
$ systemctl enable --now fail2ban
# 查看 SSH jail 状态
$ fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 2
| |- Total failed: 156
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 5
|- Total banned: 23
`- Banned IP list: 1.2.3.4 5.6.7.8 ...
# 手动封禁 IP
$ fail2ban-client set sshd banip 1.2.3.4
# 手动解封 IP
$ fail2ban-client set sshd unbanip 1.2.3.4
# 查看所有 jail
$ fail2ban-client status
自定义规则
# /etc/fail2ban/filter.d/sshd-aggressive.conf
[INCLUDES]
before = common.conf
[Definition]
failregex = ^%(__prefix_line)sFailed publickey for invalid user <FMT_USER>.*</FMT_USER> from <HOST> port \d+ ssh2$
^%(__prefix_line)sInvalid user <FMT_USER>.*</FMT_USER> from <HOST> port \d+$
^%(__prefix_line)sConnection closed by <HOST> port \d+ \[preauth\]$
ignoreregex =
# /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true
filter = sshd-aggressive
maxretry = 2
findtime = 300
bantime = 86400
实战案例
案例 1:生产环境 SSH 完整配置
# === 服务端配置 ===
# /etc/ssh/sshd_config
# 协议与加密
Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
# 认证
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
# 证书认证
TrustedUserCAKeys /etc/ssh/user_ca.pub
# 访问控制
AllowGroups ssh-users admin-group
MaxStartups 10:30:100
# 超时
ClientAliveInterval 300
ClientAliveCountMax 0 # 无响应立即断开
# 日志
LogLevel VERBOSE
# 转发
AllowTcpForwarding yes
X11Forwarding no
AllowAgentForwarding no
# === 客户端配置 ===
# ~/.ssh/config
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
HashKnownHosts yes
StrictHostKeyChecking ask
Host bastion
HostName bastion.sre.wang
User admin
Port 2222
IdentityFile ~/.ssh/id_ed25519
Host prod-*
User deploy
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion
StrictHostKeyChecking yes
案例 2:SSH 证书自动化签发
#!/bin/bash
# /usr/local/bin/ssh-cert-issue.sh
# 为用户签发短期有效的 SSH 证书
CA_KEY=~/.ssh/ca_user_key
USER_PUBKEY=$1
USERNAME=$2
VALIDITY=${3:-1d}
if [ $# -lt 2 ]; then
echo "Usage: $0 <user_pubkey> <username> [validity]"
exit 1
fi
# 签发证书
ssh-keygen -s $CA_KEY \
-I "$USERNAME@$(date +%Y%m%d)" \
-n $USERNAME \
-V +$VALIDITY \
-O clear \
-O permit-pty \
-O force-command="/usr/local/bin/ssh-audit-wrapper.sh" \
$USER_PUBKEY
echo "Certificate issued:"
ssh-keygen -L -f ${USER_PUBKEY%.pub}-cert.pub
案例 3:使用 SSH 隧道访问内网服务
# 场景:通过跳板机访问内网 PostgreSQL
# 内网 PostgreSQL: 192.168.1.100:5432
# 跳板机: bastion.sre.wang
# 方法 1:本地端口转发
$ ssh -fNL 15432:192.168.1.100:5432 bastion
$ psql -h localhost -p 15432 -U admin -d mydb
# 方法 2:在 ~/.ssh/config 中配置
Host db-tunnel
HostName bastion.sre.wang
User admin
LocalForward 15432 192.168.1.100:5432
$ ssh -fN db-tunnel
$ psql -h localhost -p 15432 -U admin -d mydb
# 方法 3:使用 autossh 保持隧道
$ autossh -M 0 -fN db-tunnel
# 方法 4:使用 ProxyCommand 直接连接(无需隧道)
$ psql "host=192.168.1.100 port=5432 user=admin dbname=mydb \
sslmode=disable \
hostaddr=127.0.0.1 \
port=15432"
SSH 安全检查清单
#!/bin/bash
# SSH 安全审计脚本
echo "=== SSH 安全检查 ==="
# 1. 检查 root 登录
ROOT_LOGIN=$(sshd -T | grep permitrootlogin)
echo "Root Login: $ROOT_LOGIN"
# 2. 检查密码认证
PWD_AUTH=$(sshd -T | grep passwordauthentication)
echo "Password Auth: $PWD_AUTH"
# 3. 检查密钥算法
echo "Host Keys:"
ls -la /etc/ssh/ssh_host_*
# 4. 检查加密配置
echo "Ciphers:"
sshd -T | grep ciphers
echo "MACs:"
sshd -T | grep macs
# 5. 检查 MaxAuthTries
MAX_AUTH=$(sshd -T | grep maxauthtries)
echo "Max Auth Tries: $MAX_AUTH"
# 6. 检查 Fail2ban
if systemctl is-active --quiet fail2ban; then
echo "Fail2ban: Active"
fail2ban-client status sshd
else
echo "Fail2ban: INACTIVE (WARNING)"
fi
# 7. 检查 known_hosts
echo "Known Hosts entries: $(wc -l < ~/.ssh/known_hosts 2>/dev/null || echo 0)"
# 8. 检查密钥权限
echo "SSH Directory Permissions:"
ls -ld ~/.ssh
ls -la ~/.ssh/authorized_keys 2>/dev/null
# 9. 检查最近登录
echo "Recent Logins:"
last -n 5
# 10. 检查失败登录
echo "Failed Logins (last 24h):"
journalctl -u sshd --since "24 hours ago" 2>/dev/null | grep "Failed" | wc -l
总结
SSH 是系统运维的核心通道,其安全配置直接关系到整个基础设施的安全。核心要点:
- 密钥认证是基础:Ed25519 是首选算法,密码认证必须禁用,authorized_keys 中可限制来源 IP 和命令。
- 证书认证是进阶方案:集中管理用户密钥、支持有效期、支持撤销,适合大规模团队和合规要求。
- sshd_config 硬化是必须的:禁用 root 登录、限制加密算法、设置超时和最大尝试次数。
- 跳板机是标准架构:ProxyJump 是现代方案,比 Agent 转发更安全。
- 端口转发要按需开放:AllowTcpForwarding 根据实际需求配置,X11 和 Agent 转发建议关闭。
- 审计日志是安全基石:LogLevel VERBOSE 记录密钥指纹和证书 ID,定期分析失败登录。
- Fail2ban 是防暴力破解的标配:配合递增封禁策略,有效遏制自动化攻击。
- SSH 安全是纵深防御的一环:需要配合防火墙、入侵检测、网络分段等综合防护。
SSH 安全的黄金法则:最小权限 + 多层防御。每个配置项都应遵循最小权限原则,同时配合跳板机、Fail2ban、审计日志形成多层防御体系。