Linux-sshd-实战-白名单与跳板机

Linux sshd 实战指南:从配置到白名单、跳板机代理

本文面向有运维/SRE 基础、想把 SSH 真正用"稳"和用"安全"的读者。不只讲 sshd_config 的表面选项,重点放在两个高频实战场景:sshd 白名单 (只允许受信任来源登录)和 ssh proxy / 跳板机 (如何无公网 IP 地穿透访问内网机器)。所有示例均可在生产环境直接套用。文中 IP / 端口 / 域名均为文档示例 (RFC 5737 保留地址、RFC 1918 私有段、example.com),端口、网段按你自己的环境替换即可。


目录

  1. [sshd 是什么](#sshd 是什么)
  2. [sshd_config 核心配置](#sshd_config 核心配置)
  3. [实战一:sshd 白名单(4 种方案)](#实战一:sshd 白名单(4 种方案))
  4. [实战二:SSH 代理 / 跳板机(ssh_proxy)](#实战二:SSH 代理 / 跳板机(ssh_proxy))
  5. 安全加固清单
  6. 排障速查
  7. 总结

1. sshd 是什么

sshd 是 OpenSSH 的服务端守护进程 ,监听 TCP 22(或你改的端口),负责处理客户端的 SSH 连接、身份认证、加密通道建立。客户端工具是 ssh/scp/sftp。

bash 复制代码
# 看版本(客户端和服务端一起装)
ssh -V

# systemd 系统:状态 / 启动 / 开机自启
systemctl status sshd
systemctl enable --now sshd

# 配置文件路径
#   主配置:/etc/ssh/sshd_config
#   片段目录(部分发行版):/etc/ssh/sshd_config.d/*.conf  (优先级高于主文件)
#   主机密钥:/etc/ssh/ 下 ssh_host_*_key
#   服务端日志:/var/log/secure (RHEL) 或 /var/log/auth.log (Debian)

⚠️ 改完配置务必校验语法再重启,避免把自己锁外面:

bash 复制代码
sshd -t        # 校验配置文件语法,无误则无输出

2. sshd_config 核心配置

贴一份生产可用的基线配置 (先放主文件,或在 sshd_config.d/99-hardening.conf):

bash 复制代码
# /etc/ssh/sshd_config.d/99-hardening.conf

Port 2222                      # 改非标端口,挡掉 99% 自动化扫描
AddressFamily inet              # 仅 IPv4,按需
ListenAddress 0.0.0.0

Protocol 2                      # 强制 SSHv2,杜绝 v1

# ------ 认证 ------
PermitRootLogin no              # 禁止 root 直接登录,用普通用户 + sudo
PubkeyAuthentication yes        # 开启密钥
PasswordAuthentication no       # 密钥就绪后关密码(先确认密钥能登再关!)
AuthenticationMethods publickey # 强制仅公钥(等价上一条但更硬)
PermitEmptyPasswords no

# ------ 会话 ------
LoginGraceTime 30               # 认证宽限时间
MaxAuthTries 3                  # 最多试 3 次
MaxSessions 10
ClientAliveInterval 300         # 5 分钟无活动发探测
ClientAliveCountMax 2           # 连续 2 次无响应断连

# ------ 其他 ------
X11Forwarding no                # 不需要图形就关
AllowTcpForwarding yes          # 跳板机场景需要(下面实战二要用)
PermitTunnel no
UseDNS no                       # 关反向解析,登录更快、避免 DNS 卡住

应用:

bash 复制代码
sshd -t && systemctl restart sshd

3. 实战一:sshd 白名单(4 种方案)

"白名单" = 只允许某些来源(IP/网段)登录,其余一律拒绝。下面 4 种按需组合,推荐方案 3(防火墙)做第一道闸 + 方案 1(sshd 原生)做第二道闸。

方案 1:sshd 原生 ------ AllowUsers user@host + Match Address

OpenSSH 5.6+ 支持在 user@host 里写 CIDR,这是最干净的服务端白名单:

bash 复制代码
# 只允许:
#   - 运维 alice 从 203.0.113.0/24 登录
#   - 内网 10.10.0.0/16 任意用户登录
#   - 其余来源全部拒绝
AllowUsers alice@203.0.113.0/24 *@10.10.0.0/16

注意:AllowUsers 是白名单语义 ------写了它之后,没列出的用户/来源一律拒登 。配合 DenyUsers 可叠加黑名单。

更精细地用 Match Address 按来源控制认证方式:

bash 复制代码
# 信任网段内允许密码(方便应急),公网只允许密钥
Match Address 10.10.0.0/16
    PasswordAuthentication yes

Match Address *,!10.10.0.0/16
    PasswordAuthentication no

方案 2:TCP Wrappers(hosts.allow / hosts.deny)

老派做法,很多内网环境还在用:

bash 复制代码
# /etc/hosts.deny
sshd: ALL

# /etc/hosts.allow
sshd: 203.0.113.0/24 10.10.0.0/16

⚠️ 大坑 :Debian 8 / RHEL 7 之后很多发行版编译 OpenSSH 时带了 --without-tcp-wrappers,hosts.allow 直接不生效。先验证:

bash 复制代码
ldd $(which sshd) | grep -i wrap   # 有输出才支持,无输出此法失效

不确定就别依赖它,用下面的防火墙方案。

方案 3(推荐):防火墙限制 22/端口来源

白名单放防火墙最稳,连接在最底层就被 drop:

bash 复制代码
# ------ firewalld(RHEL/CentOS 7+, Rocky, Alma)------
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" port protocol="tcp" port="2222" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.10.0.0/16" port protocol="tcp" port="2222" accept'
# 默认区域里没被 accept 的 2222 流量保持默认(建议默认 zone 设为 drop 或仅放行白名单)
firewall-cmd --reload

# ------ ufw(Ubuntu/Debian)------
ufw allow from 203.0.113.0/24 to any port 2222
ufw allow from 10.10.0.0/16 to any port 2222
ufw deny 2222            # 兜底拒绝其余来源(或 ufw default deny incoming)

# ------ iptables(裸机/老系统)------
iptables -A INPUT -p tcp -s 203.0.113.0/24 --dport 2222 -j ACCEPT
iptables -A INPUT -p tcp -s 10.10.0.0/16 --dport 2222 -j ACCEPT
iptables -A INPUT -p tcp --dport 2222 -j DROP

方案 4:fail2ban(动态黑名单,防爆破)

白名单是"允许谁",fail2ban 是"谁乱试就封谁",两者互补:

bash 复制代码
# /etc/fail2ban/jail.local
[sshd]
enabled  = true
port     = 2222
filter   = sshd
logpath  = /var/log/secure      # Debian 改成 /var/log/auth.log
maxretry = 3
bantime  = 1h
findtime = 10m
bash 复制代码
systemctl enable --now fail2ban
fail2ban-client status sshd      # 看被封 IP

组合建议:防火墙白名单(方案3)拦来源 + sshd 原生限制(方案1)兜底 + fail2ban(方案4)防白名单内也有肉鸡乱试。


4. 实战二:SSH 代理 / 跳板机(ssh_proxy)

真实场景:内网机器 10.10.20.141:2222 没有公网 IP ,你只能先登录一台有公网的跳板机 jump.example.com:2222,再跳进去。这就是 ssh proxy。

4.1 ProxyJump(最推荐,OpenSSH 7.3+)

-J 一行搞定多级跳板:

bash 复制代码
# 单级跳板
ssh -J jumpuser@jump.example.com:2222 inneruser@10.10.20.141 -p 2222

# 多级跳板(A -> B -> C)
ssh -J user@A,user@B user@C

4.2 ProxyCommand + nc(老版本兼容)

没有 -J 时用 ProxyCommand 调 nc/ncat/socat:

bash 复制代码
ssh -o ProxyCommand="ssh -p 2222 jumpuser@jump.example.com -W %h:%p" \
    -p 2222 inneruser@10.10.20.141

%h:%p 会被替换成最终目标主机和端口,-W 在跳板机上建立到目标的明文隧道(加密在两端 ssh 之间,跳板机看不到内容)。

4.3 ~/.ssh/config 完整示例(一劳永逸)

把跳板逻辑写进客户端配置,之后直接 ssh inner:

bash 复制代码
# ~/.ssh/config

# 跳板机(有公网)
Host jump
    HostName jump.example.com
    Port 2222
    User jumpuser
    IdentityFile ~/.ssh/id_ed25519

# 内网目标机(无公网,经 jump 跳)
Host inner
    HostName 10.10.20.141
    Port 2222
    User inneruser
    IdentityFile ~/.ssh/id_ed25519
    ProxyJump jump
    # 老版本无 ProxyJump 时改用:
    # ProxyCommand ssh -p 2222 jumpuser@jump.example.com -W %h:%p

# 通配:所有 10.10.* 内网机器统一走跳板
Host 10.10.*
    ProxyJump jump
    Port 2222
bash 复制代码
chmod 600 ~/.ssh/config
ssh inner          # 自动走跳板,无需手动 -J
scp file.txt inner:/tmp/   # scp 同样走跳板

4.4 动态 SOCKS 代理(-D,浏览器翻内网)

把跳板机当 SOCKS5 出口,浏览器配 127.0.0.1:1080 即可访问内网 Web:

bash 复制代码
ssh -D 1080 -N -f jump     # -N 不执行命令 -f 后台

4.5 端口转发(-L / -R)

bash 复制代码
# 本地转发:把内网 10.10.20.141:3306 映射到本机 13306,经跳板穿透
ssh -L 13306:10.10.20.141:3306 -N -f jump

# 远程转发:把本机 8080 暴露到跳板机 18080(临时对外暴露内网服务时用)
ssh -R 18080:localhost:8080 -N -f jump

跳板机要支持转发,记得把第 2 节的 AllowTcpForwarding yes 打开。


5. 安全加固清单

项 建议 优先级
改端口 Port 2222 挡扫描 高
禁 root 直登 PermitRootLogin no 高
关密码 PasswordAuthentication no + 仅公钥 高
白名单 防火墙 + sshd AllowUsers 双闸 高
fail2ban 防白名单内爆破 中
密钥算法 用 ed25519:ssh-keygen -t ed25519 中
会话超时 ClientAlive* 配置 中
双因素 AuthenticationMethods publickey,keyboard-interactive + Google Authenticator 高安全场景

生成密钥并分发(记住:先确认能密钥登录,再关密码):

bash 复制代码
ssh-keygen -t ed25519 -C "$(whoami)@$(hostname)" -f ~/.ssh/id_ed25519
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 inneruser@10.10.20.141

6. 排障速查

bash 复制代码
# 详细调试(看卡在哪一步:DNS / 认证 / 转发)
ssh -v  内网目标          # -vvv 更细
ssh -G inner              # 打印 inner 最终生效的全部配置(排查 config 冲突神器)

# 配置改崩了连不上?用控制台/VNC 进机器后:
sshd -t                   # 先查语法
# 临时开个救援端口(必须用与主端口不同的端口,别撞车):
/usr/sbin/sshd -p 22222 -o PasswordAuthentication=yes

# 看谁在暴力试
journalctl -u sshd -n 50 --no-pager
grep "Failed password" /var/log/secure | awk '{print $11}' | sort | uniq -c | sort -rn

# 跳板连不通时,分层验证:
ssh jump                 # 1. 跳板本身能登吗
ssh inner               # 2. 走 config 的跳板能登吗
ssh -J jump inner -v    # 3. 加 -v 看 ProxyJump 在哪断

7. 总结

  • sshd 不是"开了就行":把密码认证关掉、改非标端口、禁 root,是基础三件套。
  • 白名单要分层 :防火墙(方案3)做第一道物理闸 + sshd 原生 AllowUsers/Match Address(方案1)做逻辑闸,fail2ban 兜底防内部爆破。别迷信 TCP Wrappers------先 ldd 确认它到底编进去了没有。
  • 跳板机首选 ProxyJump :-J 一条命令穿透内网,配合 ~/.ssh/config 把 10.10.* 全量走跳板,日常 ssh inner 就跟直连一样顺手。-D 给浏览器开 SOCKS,-L/-R 做端口转发,覆盖 90% 内网访问需求。
  • 改配置铁律 :sshd -t 校验 → 保留一个已验证的救援会话/端口 → 再重启。别把自己锁门外。

把这篇里 203.0.113.0/24(办公/信任来源段)、10.10.0.0/16(内网段)、2222(SSH 端口)、jump.example.com(跳板机)换成你自己的网段、端口和跳板域名,即可直接落地。

相关推荐
气质、小青年!1 小时前
进程1学习
linux·学习
强哥聊算力1 小时前
《算力江湖·国产GPU突围:摩尔线程故事》第四集:从图形到AI:摩尔线程为什么必须冲进大模型赛道?
运维·服务器·人工智能·ai·gpu算力
blueSatchel1 小时前
framebuffer注册源码解读
linux·嵌入式
2401_862880822 小时前
嵌入式Linux系统移植与驱动开发完整指南
linux·c语言·驱动开发
坤坤子吖2 小时前
Linux 线程同步与互斥——互斥锁
linux·服务器·c++·笔记·学习
a5986522 小时前
ARM服务器部署Docker云手机,多开实例性能实测
服务器·arm开发·docker·云手机
TDTC_XQ2 小时前
Linux网络编程accept的讲解
linux·服务器·c++
梅梅绵绵冰2 小时前
Nginx反向代理
运维·nginx
Python自动化直播2 小时前
自动化笔记:素材管理、命名、轮换的几条土办法
linux·运维·数据库