>

适用场景:全新 VPS / 重装系统后的首批操作
> 环境:Debian 12 / Ubuntu 22.04+(其它 systemd 发行版同理)
> 核心目标:密码登录彻底关闭、暴力破解自动封禁、威胁情报联动封禁


0. 先看一张“加固前后对比”

指标加固前加固后
SSH 端口扫描存活✅✅(端口不变,但只有证书能进)
密码爆破成功率取决于密码强度0%(密码认证已禁用)
证书私钥泄露风险N/A仅持有私钥的机器可登录,配合 ssh-agent 落地无痕
自动封禁维度无IP 维度(fail2ban)+ 威胁情报维度(CrowdSec)
运维成本低一次配置,终身受益

1. SSH 证书登录(彻底禁用密码)

1.1 生成 CA 与签发用户证书(仅在受信任管理机上做一次)

# 1) 生成 CA 密钥(妥善保管,离线最佳)
ssh-keygen -t ed25519 -f ~/.ssh/ca -C "vps-ca-$(date +%Y%m%d)"
# 生成:ca(私钥)、ca.pub(公钥)

# 2) 为每台 VPS 签发主机证书(主机证书用于客户端验证服务端,防中间人)
ssh-keygen -s ~/.ssh/ca -I "vps-host-$(hostname)" -h -n "$(hostname),$(curl -s ifconfig.me)" -V +365d /etc/ssh/ssh_host_ed25519_key.pub
# 生成:ssh_host_ed25519_key-cert.pub → 拷回 VPS /etc/ssh/

# 3) 为每位运维人员签发用户证书(每人一份,设定有效期)
ssh-keygen -s ~/.ssh/ca -I "admin-alice" -n "root,alice" -V +90d ~/.ssh/id_ed25519.pub
# 生成:id_ed25519-cert.pub → 发给 Alice,她放 ~/.ssh/ 同目录即可
>

关键点:-V +90d 限制有效期,到期自动失效,无需手动吊销;-n 指定允许登录的远程用户名。

1.2 VPS 端配置(/etc/ssh/sshd_config.d/99-hardening.conf)

# === 仅保留现代加密套件 ===
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]
KexAlgorithms curve25519-sha256,[email protected]

# === 证书认证 ===
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
TrustedUserCAKeys /etc/ssh/ca.pub   # 只需 CA 公钥,无需分发每个用户公钥
AuthenticationMethods publickey
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin prohibit-password   # root 仅证书
AuthorizedKeysFile none             # 彻底忽略 ~/.ssh/authorized_keys

# === 其它收敛 ===
Port 22
PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 20
ClientAliveInterval 300
ClientAliveCountMax 2
DisableForwarding yes
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PrintMotd no
# 部署 CA 公钥
sudo install -m 644 ca.pub /etc/ssh/ca.pub
sudo systemctl reload sshd
>

验证:ssh -vvv [email protected] 2>&1 | grep -E "Offering|Authenticated" 应显示 Authenticated with certificate。


2. fail2ban:把“试密码/试证书失败”的 IP 自动关小黑屋

2.1 安装与核心配置

sudo apt update && sudo apt install -y fail2ban

/etc/fail2ban/jail.d/sshd-hardening.local:

[sshd]
enabled  = true
port     = ssh
filter   = sshd
logpath  = %(sshd_log)s
backend  = systemd
maxretry = 3
findtime = 600
bantime  = 86400
banaction = iptables-multiport
action   = %(action_mwl)s
>

action_mwl = 封禁 + 发邮件通知(需配置 destemail/sender),不想收邮件改 %(action_)s。

2.2 启用并验证

sudo systemctl enable --now fail2ban
fail2ban-client status sshd
# 手动测试:故意输错 3 次密码/证书 → fail2ban-client status sshd 应显示 Banned IP

3. CrowdSec:把全网威胁情报变成你的防火墙规则

>

CrowdSec = “众包版 fail2ban”,社区共享恶意 IP,本地决策引擎自动拉取并封禁。

3.1 一键安装(官方脚本自动适配发行版)

curl -s https://install.crowdsec.net | sudo bash
# 安装完成后会提示注册控制台(可选,注册后能看仪表盘)

3.2 关键采集器 & 决策

# 采集 SSH / nginx / docker 日志
sudo cscli collections install crowdsecurity/sshd crowdsecurity/nginx crowdsecurity/docker

# 查看已加载的场景
cscli scenarios list

3.3 配置 bouncer(真正落地封禁的组件)

# 推荐 iptables bouncer(无依赖、内核级生效)
sudo apt install -y crowdsec-firewall-bouncer-iptables
# 或 nftables 版:crowdsec-firewall-bouncer-nftables

验证:

cscli decisions list
# 应显示来自社区的恶意 IP + 本地 fail2ban 触发的决策
>

联动:fail2ban 封本地日志里的坏人,CrowdSec 封全网已知的坏人,双重保险。


4. 一条命令自检(加完建议跑一次)

cat <<'EOF' | sudo bash
echo "=== SSH 仅证书登录 ===" && sshd -T | grep -E 'passwordauthentication|pubkeyauthentication|authenticationmethods'
echo -e "\n=== fail2ban 状态 ===" && fail2ban-client status sshd
echo -e "\n=== CrowdSec 决策 ===" && cscli decisions list -o table
echo -e "\n=== 当前防火墙规则 ===" && sudo iptables -L -n -v | grep -E 'f2b|crowdsec' | head -20
EOF

5. 常见坑 & 避坑指南

现象原因修正
证书登录提示 Permission denied (publickey)客户端没带 -i 或证书未放在同目录ssh -i ~/.ssh/id_ed25519 root@ip;证书文件名必须为 id_ed25519-cert.pub
fail2ban 不封禁日志路径/后端不对journalctl -u sshd -f 确认日志格式,backend = systemd
CrowdSec 决策不生效bouncer 未启动 / 冲突systemctl status crowdsec-firewall-bouncer-iptables;检查 iptables -L 有无 crowdsec 链
误封自己管理机 IP 变动cscli decisions delete -i <your-ip> 或加白名单 cscli decisions add --ip <your-ip> --type whitelist

6. 维护清单(建议加入定期巡检)

# 每周
cscli hub update && cscli hub upgrade   # 更新场景/采集器
fail2ban-client status                  # 确认服务存活

# 每月
cscli decisions list --since 30d | wc -l   # 统计封禁量
ssh-keygen -Lf ~/.ssh/ca.pub               # 检查 CA 有效期

7. 一键部署脚本(可选,放 GitHub Gist 供以后复用)

#!/usr/bin/env bash
# vps-harden.sh — 仅供参考,生产环境建议逐步执行并确认
set -euo pipefail
# ... 把上面所有步骤串成函数,按需调用
— 感谢阅读 —

一起交流

分享你的思考,让讨论更进一步。