Linux运维16 min read

SSH 安全加固与跳板机搭建:从端口加固到审计追溯的完整方案

一、一次 SSH 爆破引发的血案

去年某客户的测试服务器被勒索病毒加密,排查日志发现攻击者用的不是什么 0day,就是最朴素的 SSH 密码爆破——22 端口暴露在公网,root 密码是 Admin@123fail2ban 也没装。/var/log/secure 里 8 小时内 12 万次失败登录尝试,最后一次成功。

那次之后我把 SSH 安全总结为一句话:端口不是护城河,认证方式才是。 但两者缺一不可——端口改了能挡掉 90% 的脚本小子,密钥认证能挡掉剩下 10% 的暴力破解,审计录屏则保证万一出了事,你能追溯每一个命令。

二、SSH 加固四层防御模型

        外部攻击者
            │
   ┌────────▼────────┐
   │  第一层:网络层   │  ← 防火墙白名单 / 安全组
   │  只允许跳板机IP   │
   └────────┬────────┘
            │
   ┌────────▼────────┐
   │  第二层:认证层   │  ← 密钥登录 + 禁密码
   │  ed25519 密钥    │
   └────────┬────────┘
            │
   ┌────────▼────────┐
   │  第三层:协议层   │  ← 改端口 + 限root + 超时
   │  sshd 精细化配置  │
   └────────┬────────┘
            │
   ┌────────▼────────┐
   │  第四层:审计层   │  ← 录屏 + 命令日志
   │  Teleport/tlog  │
   └─────────────────┘

经验法则:四层防御不是"选其中几层做",而是层层叠加。任何一层被突破,后面还有兜底。

三、第一层:网络层 —— 把门先关上

3.1 防火墙白名单

最安全的端口是不开放的端口。生产服务器 SSH 应该只允许跳板机(或运维 VPN 网段)访问:

# iptables:只允许 10.10.4.0/24 网段访问 2222 端口
iptables -A INPUT -p tcp --dport 2222 -s 10.10.4.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 2222 -j DROP

# firewalld 写法
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.10.4.0/24 port port=2222 protocol=tcp accept'
firewall-cmd --permanent --remove-port=22/tcp
firewall-cmd --reload

3.2 安全组(云服务器)

如果是阿里云 / AWS 等云服务器,在安全组里配置更可靠——在内核防火墙之前就把流量挡掉了,不消耗服务器 CPU:

入方向规则:
  协议: TCP
  端口: 2222
  源IP: <跳板机公网IP>/32
  策略: 允许
  
  (删除 22 端口的 0.0.0.0/0 规则)

四、第二层:认证层 —— 密钥替代密码

4.1 生成 ed25519 密钥

# 客户端生成密钥对(ed25519 比 RSA 更短更快更安全)
ssh-keygen -t ed25519 -C "ops@scrcx-2026" -f ~/.ssh/id_ed25519_scrcx

# 推荐加 passphrase,防止私钥泄露后直接可用
# 生成后会有两个文件:
#   ~/.ssh/id_ed25519_scrcx      (私钥,绝对不能传出去)
#   ~/.ssh/id_ed25519_scrcx.pub  (公钥,放到服务器)

4.2 推送公钥到服务器

# 方法一:ssh-copy-id(交互式,适合初次配置)
ssh-copy-id -i ~/.ssh/id_ed25519_scrcx.pub -p 2222 ops@10.10.4.17

# 方法二:手动写入(适合批量部署)
cat ~/.ssh/id_ed25519_scrcx.pub | ssh -p 2222 ops@10.10.4.17 \
  "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

4.3 密钥权限铁律

# 服务器端权限必须精确,否则 sshd 拒绝读取
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R ops:ops ~/.ssh

# 客户端私钥权限
chmod 600 ~/.ssh/id_ed25519_scrcx

踩坑提示:authorized_keys 权限是 644 时,某些 sshd 版本会静默忽略密钥,回退到密码认证——你以为密钥配好了,实际上一直在用密码。用 ssh -vvv 排错时关注 Authentications that can continue: publickey 这行。

4.4 SSH Agent 转发(跳板机场景必备)

# 客户端启动 agent 并加载密钥
eval $(ssh-agent)
ssh-add ~/.ssh/id_ed25519_scrcx

# 通过跳板机连接目标机时启用转发
ssh -A -J jump@jump.scrcx.cn -p 2222 ops@10.10.4.20

Agent 转发让你在跳板机上不需要存放任何私钥,就能跳到第三台机器——私钥永远只在你的笔记本上

五、第三层:协议层 —— sshd 精细化配置

5.1 生产级 sshd_config

# /etc/ssh/sshd_config —— 生产环境推荐配置

# === 端口与监听 ===
Port 2222                          # 改掉默认 22 端口
ListenAddress 10.10.4.17           # 只监听内网(公网走跳板机)

# === 协议版本 ===
Protocol 2                         # 禁用不安全的 Protocol 1

# === 认证 ===
PermitRootLogin no                 # 禁止 root 直接登录
PasswordAuthentication no          # 禁止密码认证(密钥登录后再关)
PubkeyAuthentication yes           # 启用密钥认证
PermitEmptyPasswords no            # 禁止空密码
MaxAuthTries 3                    # 最多尝试 3 次
LoginGraceTime 30                 # 30 秒内未认证则断开

# === 会话控制 ===
ClientAliveInterval 300           # 5 分钟无操作发心跳
ClientAliveCountMax 2             # 2 次心跳无响应则断开(=10分钟超时)
MaxSessions 10                    # 最大并发会话
MaxStartups 10:30:60              # 防并发爆破(第10个起30%丢弃,60个硬上限)

# === 转发控制 ===
AllowTcpForwarding yes            # 跳板机需要,普通服务器可关
X11Forwarding no                  # 生产环境不需要图形转发
AllowAgentForwarding yes          # 跳板机需要 agent 转发

# === 日志 ===
SyslogFacility AUTH
LogLevel VERBOSE                  # 记录密钥指纹,方便审计
                                  # 注意:不要用 DEBUG3,会记录敏感信息

# === 用户白名单 ===
AllowUsers ops deploy             # 只允许这两个用户 SSH 登录

5.2 应用配置并验证

# 先测试配置语法(不会重启 sshd,避免把自己锁外面)
sshd -t

# 关键:先保留一个已登录的 SSH 会话,再重启
systemctl restart sshd

# 新开一个终端测试密钥登录(确认能连上再关旧会话)
ssh -i ~/.ssh/id_ed25519_scrcx -p 2222 ops@10.10.4.17

血泪教训:改 sshd_config 后永远先 sshd -t,然后保留旧会话开新窗口验证。 我见过太多人在远程服务器上改完配置 systemctl restart sshd 然后把自己锁在外面,只能跑机房插显示器。

5.3 用 Match 做条件配置

# 跳板机允许特定网段密码登录(临时排障用),其他强制密钥
Match Address 10.10.4.0/24
    PasswordAuthentication no
    PermitRootLogin no

# CI/CD 机器人专用配置
Match User deploy
    ForceCommand internal-sftp     # 只允许 SFTP,不能拿 shell
    ChrootDirectory /data/deploy   # 锁定根目录
    AllowTcpForwarding no

六、Fail2ban:自动封禁爆破 IP

6.1 安装与配置

# RHEL/CentOS
yum install -y fail2ban
# Debian/Ubuntu
apt install -y fail2ban

# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 3600          # 封禁 1 小时
findtime = 600           # 10 分钟内
maxretry = 3             # 3 次失败即封
banaction = firewallcmd-ipset   # CentOS 用 firewalld
# banaction = iptables-multiport # Debian 用 iptables

[sshd]
enabled  = true
port     = 2222
logpath  = /var/log/secure
maxretry = 3
bantime  = 86400         # SSH 爆破直接封 24 小时

6.2 启动与验证

systemctl enable --now fail2ban

# 查看当前被封 IP
fail2ban-client status sshd

# 手动解封某个 IP
fail2ban-client set sshd unbanip 1.2.3.4

# 模拟失败登录测试(故意输错密码 3 次后检查是否被封)

6.3 白名单保护

# /etc/fail2ban/jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 10.10.4.0/24 60.205.129.97
# 上述 IP 永远不会被封,防止跳板机自己被封

七、跳板机搭建:所有入口收口

7.1 架构设计

    运维人员                    外部审计
       │                          │
       │ SSH (密钥+MFA)           │ 只读日志
       ▼                          ▼
  ┌────────────────────────────────────┐
  │         跳板机 (jump.scrcx.cn)      │
  │  ┌──────────┐  ┌────────────────┐  │
  │  │ sshd     │  │ tlog/audit     │  │
  │  │ (端口2222)│  │ (录屏+命令日志) │  │
  │  └──────────┘  └────────────────┘  │
  └───────────────┬────────────────────┘
                  │ SSH (内网密钥)
     ┌────────────┼────────────┐
     ▼            ▼            ▼
  生产机A      生产机B      数据库机
  10.10.4.17  10.10.4.19   10.10.4.20

核心原则:生产服务器只允许跳板机 IP 访问 SSH,所有人必须先登录跳板机再跳转。

7.2 跳板机 SSH 限制

# /etc/ssh/sshd_config (跳板机)
Port 2222
PasswordAuthentication no
AllowTcpForwarding yes       # 必须开启,用于跳转
AllowAgentForwarding yes     # 必须开启,用于密钥转发

# 限制用户只能跳到指定机器
Match User ops
    PermitOpen 10.10.4.17:2222 10.10.4.19:2222 10.10.4.20:2222

7.3 ~/.ssh/config 客户端配置

# ~/.ssh/config —— 运维人员笔记本上配置

Host jump
    HostName jump.scrcx.cn
    Port 2222
    User ops
    IdentityFile ~/.ssh/id_ed25519_scrcx
    ForwardAgent yes

Host web-01
    HostName 10.10.4.17
    Port 2222
    User ops
    ProxyJump jump              # 自动通过跳板机
    IdentityFile ~/.ssh/id_ed25519_scrcx

Host db-01
    HostName 10.10.4.20
    Port 2222
    User oracle
    ProxyJump jump
    IdentityFile ~/.ssh/id_ed25519_scrcx

配好后直接 ssh web-01 就能一跳到位,不用记端口和 IP。

八、审计层:操作录屏与命令日志

8.1 方案一:tlog(轻量级,RHEL 原生)

yum install -y tlog

# /etc/tlog/tlog-rec-session.conf
{
    "verify": true,
    "write": {
        "file": {
            "path": "/var/log/tlog/tlog.log"
        }
    }
}

# 在 /etc/profile.d/ 加入自动录制
cat > /etc/profile.d/tlog.sh << 'EOF'
if [ -n "$SSH_TTY" ] && [ "$USER" != "root" ]; then
    TLOG_REC=yes
    export TLOG_REC
fi
EOF

回放操作录屏:

# 查看录屏列表
tlog-rec --list

# 回放某次会话
tlog-play -r file -i <session-id>

8.2 方案二:bash history 增强(零依赖方案)

# /etc/profile.d/audit.sh —— 不装任何软件,纯 bash 方案
export HISTTIMEFORMAT="%F %T `who am i | awk '{print $5}'` "
export HISTSIZE=10000
export HISTFILESIZE=10000
export PROMPT_COMMAND='history -a; logger -t ssh-audit "$(history 1)"'

# 关键:PROMPT_COMMAND 把每条命令实时写入 syslog
# /var/log/messages 里会出现:
# ssh-audit: 2026-07-13 10:23:45 (10.10.4.100) rm -rf /tmp/old_data

8.3 方案三:Teleport(企业级,推荐规模较大时用)

# Teleport 自带 MFA、RBAC、录屏、审计,适合 10+ 台服务器管理
# 安装略,核心配置示意
# /etc/teleport.yaml
auth_service:
  enabled: yes
  listen_addr: 0.0.0.0:3025

# 用户通过 Web MFA 登录 → 自动获得临时证书 → SSH 到目标机
# 所有操作录屏存到 S3 / OSS,可随时回放审计

九、双因素认证(MFA):密钥之上再加一层

9.1 Google Authenticator(PAM 模块)

yum install -y google-authenticator

# 每个用户在自己环境下执行(生成 TOTP 密钥)
google-authenticator
# 选择:
#   - 时间_based: y
#   - 更新 .google_authenticator: y
#   - 禁止多次使用同一令牌: y
#   - 时间窗口: n
#   - 限速: y

# /etc/pam.d/sshd 添加
auth required pam_google_authenticator.so

# /etc/ssh/sshd_config
ChallengeResponseAuthentication yes
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

配置后登录流程:密钥认证 → 输入手机上的 6 位动态码 → 登录成功。

9.2 证书签名(大规模环境)

# CA 服务器签发用户证书(有效期 8 小时)
ssh-keygen -s ~/.ssh/ca_user_key \
  -I "ops-xuwang-20260713" \
  -V +8h \
  -n ops,deploy \
  ~/.ssh/id_ed25519_scrcx.pub

# 生成 id_ed25519_scrcx-cert.pub
# 服务器信任 CA 公钥
echo "@cert-authority * $(cat ~/.ssh/ca_user_key.pub)" >> /etc/ssh/sshd_config
# TrustedUserCAKeys /etc/ssh/ca_user_key.pub

# 用户登录时自动使用证书
ssh -i ~/.ssh/id_ed25519_scrcx -p 2222 ops@10.10.4.17

证书方案的优势:不需要在每台服务器上分发公钥,只要服务器信任 CA,签发的证书就能用。人员离职时吊销证书即可,不用逐台删 authorized_keys

十、监控与告警

10.1 关键监控指标

# SSH 登录成功事件
journalctl -u sshd | grep "Accepted"

# SSH 登录失败事件(突然暴增 = 爆破攻击)
journalctl -u sshd | grep "Failed password" | wc -l

# 当前在线用户
who | wc -l

# Fail2ban 封禁数量
fail2ban-client status sshd | grep "Banned IP"

10.2 Promtail 采集 SSH 日志(接入 Grafana)

# /etc/promtail/promtail-config.yml
scrape_configs:
  - job_name: ssh-audit
    static_configs:
      - targets: [localhost]
        labels:
          job: sshd
          __path__: /var/log/secure
    pipeline_stages:
      - regex:
          expression: '^(?P<time>\S+ \S+) (?P<host>\S+) sshd\[\d+\]: (?P<event>Accepted|Failed) (?P<method>\S+) for (?P<user>\S+) from (?P<ip>\S+)'
      - labels:
          event:
          user:
          ip:

十一、避坑清单

# 现象 解决
1 改配置后自锁 SSH 连不上了 永远保留旧会话,sshd -t 后再重启
2 authorized_keys 权限错误 密钥被静默忽略 chmod 600,目录 chmod 700
3 密钥有 passphrase 脚本卡住 cron/CI 任务挂起 ssh-agentexpect 自动输入
4 Agent 转发被中间人利用 跳板机管理员可借用私钥 只信任跳板机,跳板机不存私钥
5 fail2ban 封了自己 跳板机 IP 被误封 ignoreip 加白名单
6 known_hosts 冲突 服务器重装后连不上 ssh-keygen -R <host> 清旧指纹
7 SSH 超时断开 长任务跑到一半断了 tmux/screen 保活,或 ServerAliveInterval
8 ProxyJump 不生效 直连超时 检查跳板机 AllowTcpForwarding yes
9 证书过期无感知 突然全部连不上 监控证书有效期,提前续签
10 SELinux 阻止非标端口 改端口后 sshd 起不来 semanage port -a -t ssh_port_t -p tcp 2222

十二、小结

SSH 安全的核心不是某一条配置,而是纵深防御:网络层白名单挡住大部分流量,密钥认证挡住密码爆破,协议层配置限制攻击面,审计层兜底追溯。四层叠加后,即使某一层被突破,攻击者仍然无法直接拿到 shell。

跳板机则解决了另一个工程问题:入口收口。所有运维流量都经过一个可控的入口,既方便统一加固和审计,又避免了"每台服务器都要暴露在公网"的灾难。当你第一次通过 ssh web-01 一键穿透跳板机直达目标机,同时知道自己的每一条命令都在录屏,你就理解了"安全与便捷不矛盾"这句话。

分享:

相关文章

评论区