企业级SSH安全防护实战:基于firewall-cmd的精细化访问控制
刚接手一台裸奔的CentOS服务器时,最让人后背发凉的就是查看/var/log/secure里那些密密麻麻的SSH暴力破解尝试。上周帮某电商客户做安全审计,发现一台测试服务器竟然在24小时内收到了来自47个国家的32万次登录尝试——这还只是用了默认22端口的情况。把SSH暴露在公网而不加任何访问限制,相当于把公司大门敞开让黑客随意参观。
传统方案中,很多人第一反应是修改SSH端口或禁用密码登录。这些方法确实有效,但存在明显局限:改端口只是"安全通过 obscurity",而密钥管理对团队协作场景并不友好。相比之下,基于源IP的访问控制才是真正的网络层防护,它能从根源上切断非法访问,就像为服务器安装了智能门禁系统。而firewall-cmd作为RHEL/CentOS的标配防火墙工具,提供了比iptables更易用的富规则(rich rule)语法,特别适合实现这类精细化控制。
1. 环境准备与基础诊断
在开始配置之前,我们需要对当前防火墙状态做全面体检。很多新手容易犯的错误是直接添加新规则而不清理现有配置,导致规则冲突或意外放行。
1.1 检查现有防火墙状态
首先确认firewalld服务已启用并运行:
systemctl status firewalld如果看到active (running)表示服务正常,若未启动则需要执行:
systemctl enable --now firewalld查看当前生效的所有规则:
firewall-cmd --list-all典型输出会包含以下几个关键部分:
public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:这里需要特别关注services和rich rules部分,它们决定了当前的访问权限。
1.2 评估现有SSH规则风险
默认安装的CentOS/RHEL通常会开放SSH服务给所有IP访问,这相当于给了攻击者明确的攻击面。通过以下命令可以验证:
firewall-cmd --info-service=ssh输出会显示:
ssh ports: 22/tcp protocols: source-ports: modules: destination:这表示任何IP都可以连接22端口,是典型的高风险配置。
重要提示:在进行规则修改前,建议先通过本地控制台或带外管理方式保持一个活动会话,避免配置错误导致自己被锁在外面。
2. 构建IP白名单体系
企业环境中的服务器访问通常有明确的来源特征:办公网络有固定IP段,云服务商有已知IP范围,VPN网关有专用地址池。利用这些特征可以构建多层防护体系。
2.1 移除默认开放规则
首先清理默认的不安全配置:
firewall-cmd --permanent --remove-service=ssh--permanent参数表示将变更写入持久化配置,否则重启后会失效。但此时变更还未立即生效,需要执行:
firewall-cmd --reload验证是否生效:
firewall-cmd --list-services | grep ssh如果没有任何输出,表示ssh服务已从默认允许列表中移除。
2.2 添加精细化访问规则
假设我们需要允许以下IP段访问:
- 总部办公室:203.0.113.0/24
- 云运维跳板机:198.51.100.15/32
- 分支机构:192.0.2.0/26
使用富规则语法添加:
firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="203.0.113.0/24" port protocol="tcp" port="22" accept' firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="198.51.100.15" port protocol="tcp" port="22" accept' firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="192.0.2.0/26" port protocol="tcp" port="22" accept'使配置生效:
firewall-cmd --reload2.3 验证规则有效性
使用--list-rich-rules查看当前富规则:
firewall-cmd --list-rich-rules应该能看到类似输出:
rule family="ipv4" source address="203.0.113.0/24" port port="22" protocol="tcp" accept rule family="ipv4" source address="198.51.100.15" port port="22" protocol="tcp" accept rule family="ipv4" source address="192.0.2.0/26" port port="22" protocol="tcp" accept为全面测试,可以从允许和禁止的IP分别尝试连接:
# 从允许的IP测试 ssh user@server_ip # 从其他IP测试应被拒绝 telnet server_ip 223. 高级配置技巧
基础白名单能满足多数场景,但企业级环境往往需要更精细的控制策略。
3.1 时间维度控制
对于需要临时访问的情况,可以添加非持久化规则(不加--permanent):
firewall-cmd --add-rich-rule=' rule family="ipv4" source address="203.0.113.100" port protocol="tcp" port="22" accept'该规则会在下次reload或重启后自动失效,适合临时授权场景。
3.2 组合条件规则
富规则支持多条件组合,例如只允许特定IP在工作时间访问:
firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="203.0.113.50" port protocol="tcp" port="22" time start="09:00:00" stop="18:00:00" accept'时间格式为HH:MM:SS,支持日期范围(如weekday="mon,tue,wed")。
3.3 日志记录与监控
为安全审计考虑,可以记录被拒绝的连接尝试:
firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source not address="203.0.113.0/24" port protocol="tcp" port="22" log prefix="SSH REJECT: " level="notice" reject'日志会记录到/var/log/messages,可以通过journalctl查看:
journalctl -u firewalld --since "1 hour ago" | grep "SSH REJECT"4. 应急恢复与日常管理
再完善的配置也可能出现意外,特别是远程操作防火墙时,一个错误规则就可能锁死所有访问。
4.1 紧急恢复方案
建议提前准备本地恢复脚本/root/firewall_reset.sh:
#!/bin/bash # 清空所有富规则 firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="203.0.113.0/24" port protocol="tcp" port="22" accept' firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="198.51.100.15" port protocol="tcp" port="22" accept' firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="192.0.2.0/26" port protocol="tcp" port="22" accept' # 恢复默认SSH访问 firewall-cmd --permanent --add-service=ssh firewall-cmd --reload设置可执行权限:
chmod +x /root/firewall_reset.sh4.2 配置版本控制
防火墙规则应该纳入配置管理系统。可以定期导出完整配置:
firewall-cmd --list-all > /etc/firewalld/backups/firewall_$(date +%Y%m%d).conf或者直接备份整个zone配置:
cp /etc/firewalld/zones/public.xml /etc/firewalld/zones/public.xml.bak4.3 自动化检查脚本
创建定期运行的检查脚本/usr/local/bin/check_firewall.sh:
#!/bin/bash CURRENT=$(firewall-cmd --list-rich-rules | grep "port=\"22\"") EXPECTED='rule family="ipv4" source address="203.0.113.0/24" port port="22" protocol="tcp" accept' if [[ "$CURRENT" != *"$EXPECTED"* ]]; then echo "SSH firewall rules modified unexpectedly!" | mail -s "Firewall Alert" admin@example.com fi加入crontab每天检查:
0 3 * * * /usr/local/bin/check_firewall.sh5. 架构演进建议
随着业务规模扩大,单纯的IP白名单可能面临维护成本上升的问题。这时可以考虑以下进阶方案:
5.1 跳板机架构
设置专用的跳板机/堡垒机:
- 所有SSH访问必须通过跳板机
- 后端服务器只允许跳板机IP访问
- 跳板机配置双因素认证和会话审计
对应的防火墙规则简化为:
firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="跳板机IP" port protocol="tcp" port="22" accept'5.2 零信任网络模型
在云原生环境中,可以考虑:
- 用安全组替代主机防火墙
- 基于服务的身份认证而非IP白名单
- 每次连接都需要动态授权
例如AWS的安全组规则可以配置为:
类型:SSH 协议:TCP 端口范围:22 源:安全组ID(而非IP地址)