1. 项目概述为什么RHEL 9的防火墙与SSH配置如此关键在任何一个企业级Linux服务器的运维工作中有两项基础配置是绕不开的那就是防火墙和SSH。听起来可能有点老生常谈但恰恰是这些基础配置决定了你服务器的大门是坚不可摧还是形同虚设。我见过太多因为一个疏忽的防火墙规则或者一个弱口令的SSH账户导致整个内网被渗透的案例。RHEL 9作为红帽企业级Linux的最新长期支持版本在安全机制上又向前迈进了一步其内置的firewalld防火墙和默认更严格的SSH配置需要我们重新审视和掌握。简单来说这个配置指南要解决的核心问题就是如何在RHEL 9上既保证服务器自身的安全通过防火墙精确控制流量又确保我们管理员能安全、便捷地远程管理它通过SSH密钥认证替代危险的密码登录。这不仅仅是两个独立功能的堆砌而是一套组合拳。防火墙是城堡的围墙和卫兵决定了谁可以进来、从哪个门进来、进来后能去哪里而SSH密钥认证则是你作为城堡主人独一无二的、无法伪造的令牌确保只有你能通过密道安全地进入指挥室。无论你是刚接触RHEL的新手运维还是从CentOS 7/8迁移过来的老手理解RHEL 9在这两方面的变化和最佳实践都至关重要。接下来我会带你从设计思路开始一步步拆解配置的每一个细节分享我踩过的坑和验证过的技巧目标是让你配置完后心里有底服务器安全。2. 核心思路与方案选型为什么是firewalld SSH密钥在开始动手前我们先理清思路。RHEL 9默认的安全栈选择背后有其深意。2.1 防火墙告别iptables拥抱firewalld的动态管理很多从早期Linux版本过来的朋友可能更熟悉iptables它直接操作内核的Netfilter框架非常强大但也非常复杂。RHEL 7开始引入firewalld作为前端到了RHEL 9它已经是绝对的主力。为什么选它动态管理无需重启服务这是最大的优点。传统的iptables规则一旦修改需要重新加载整个规则集会导致现有连接短暂中断。而firewalld运行在D-Bus上任何规则变更都是实时、动态生效的对业务影响极小。想象一下你正在通过SSH维护一台生产服务器突然需要临时开放一个端口给合作伙伴测试用firewalld你可以瞬间完成且不断开现有SSH连接这太重要了。区域Zone概念更符合现实场景firewalld引入了“区域”的概念比如public公共区域用于不信任的网络、internal内部区域用于信任的网络、dmz非军事区等。你可以将不同的网络接口绑定到不同的区域每个区域有预定义的一套规则。这种抽象让安全策略的管理变得直观。你的服务器网卡连接公司内网那就放到internal区默认允许SSH。另一块网卡面向互联网放到public区只开放必要的HTTP/HTTPS端口。服务Service抽象简化配置你不用再死记硬背“要开Web服务得放行TCP的80和443端口”。firewalld预定义了“http”、“https”、“ssh”等服务一个服务名背后就对应了协议和端口。直接放行服务即可既减少了出错概率也提高了可读性。丰富的客户端支持除了命令行工具firewall-cmd还有图形化工具firewall-config并且能很好地与Cockpit Web管理界面集成满足不同用户的操作习惯。所以我们的防火墙配置将完全基于firewalld不再回头折腾iptables。2.2 SSH认证坚决摒弃密码全面转向密钥对SSHSecure Shell是我们管理Linux服务器的生命线。但默认的密码认证方式在当今的网络安全环境下显得异常脆弱。暴力破解、密码泄露、中间人攻击等风险时刻存在。SSH密钥认证的原理与优势它采用非对称加密体系。你本地生成一对密钥私钥private key和公钥public key。私钥好比是你家的门钥匙必须绝对保密存放在本地公钥好比是贴在门锁上的、特定形状的锁芯模具可以公开需要把它放到服务器上你账户的~/.ssh/authorized_keys文件里。当你连接服务器时服务器用你事先放好的公钥“锁芯”发起一个挑战。你的本地SSH客户端用私钥“钥匙”解开这个挑战证明你是钥匙的主人从而完成认证。这个过程完全不需要在网络上传输密码。这样做的好处是颠覆性的免疫暴力破解攻击者无法再通过穷举密码的方式来尝试登录。避免密码泄露网络上不传输密码从根本上杜绝了密码被嗅探的风险。便于自动化很多自动化工具如Ansible、CI/CD流水线都需要免密登录密钥认证是唯一安全、可靠的方式。可结合强制策略你可以在服务器端完全禁用密码登录只允许密钥登录这是最彻底的安全加固。因此本指南将SSH配置的核心定为在服务器端启用并优化密钥认证同时彻底禁用密码认证。这是提升服务器安全性的单点最重要措施没有之一。3. 实操准备与环境确认在开始配置之前我们需要先确保环境正确并理解一些前置条件。3.1 系统与权限要求操作系统本文基于纯净安装的RHEL 9.0及以上版本。如果你是从旧版本升级而来建议检查firewalld和openssh-server的配置是否被覆盖或存在冲突。权限本文涉及的所有操作除了生成本地密钥对都需要在服务器上拥有root权限或通过sudo提权。因为修改防火墙规则和SSH主配置/etc/ssh/sshd_config都是系统级操作。初始访问假设你已经通过某种方式如云服务商的控制台、本地物理终端、或者初始密码登录到了服务器。我们的最终目标就是替换掉这种不安全的初始访问方式。3.2 关键服务状态检查首先让我们确认两个核心服务是否已经安装并运行# 1. 检查firewalld服务状态 sudo systemctl status firewalld # 你应该看到类似这样的输出状态为 active (running) # ● firewalld.service - firewalld - dynamic firewall daemon # Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled) # Active: active (running) since ... # 2. 检查SSH服务状态 sudo systemctl status sshd # 同样状态应为 active (running)如果firewalld没有运行使用sudo systemctl start firewalld sudo systemctl enable firewalld启动并设置开机自启。sshd服务通常默认是开启的。注意在配置SSH密钥认证并成功测试之前绝对不要在远程会话中重启sshd服务或应用过于严格的防火墙规则。你可能会把自己锁在服务器外面。最佳实践是在服务器本地控制台或通过有保障的后备连接如云平台VNC进行这些高风险操作或者至少开启两个独立的SSH会话在一个会话中测试配置用另一个会话作为恢复通道。4. 防火墙firewalld配置详解现在我们开始深入配置防火墙。我们的目标是设置一个既安全又不妨碍必要管理的策略。4.1 理解默认区域与接口绑定首先查看当前的默认区域和各个网络接口所属的区域sudo firewall-cmd --get-default-zone # 输出通常是 public sudo firewall-cmd --get-active-zones # 输出会列出所有活跃的网络接口如ens160, eth0及其绑定的区域。 # 例如 # public # interfaces: ens160这意味着所有流量通过ens160网卡进入目前都遵循public区域的规则。public区域默认只允许SSH服务端口22和DHCPv6-client等少数服务。这是一个比较保守的起点。4.2 放行必要的服务以Web服务为例假设你的服务器需要提供Web服务HTTP/HTTPS和数据库服务如MySQL端口3306。我们需要将这些服务添加到当前区域public的规则中。方法一放行预定义的服务推荐# 添加http和https服务永久生效--permanent参数 sudo firewall-cmd --permanent --add-servicehttp sudo firewall-cmd --permanent --add-servicehttps # 重载防火墙配置使永久规则立即生效不会中断现有连接 sudo firewall-cmd --reload # 验证服务是否已添加 sudo firewall-cmd --list-services # 输出应包含 ssh dhcpv6-client http https--permanent参数表示将规则写入永久配置否则重启firewalld后规则会丢失。--reload是应用永久配置的标准安全方式。方法二放行特定端口如果firewalld没有预定义你需要的服务比如自定义端口可以直接放行端口。# 放行TCP 3306端口MySQL sudo firewall-cmd --permanent --add-port3306/tcp sudo firewall-cmd --reload # 验证端口 sudo firewall-cmd --list-ports4.3 高级规则限制SSH访问源IP默认情况下放行ssh服务意味着全世界的IP都可以尝试连接你的22端口。这虽然方便但也会招来大量的扫描和攻击尝试。一个更安全的做法是只允许来自特定信任IP地址的SSH连接。我们可以使用firewalld的“富规则”Rich Rules功能来实现。富规则提供了更细粒度的控制可以指定源/目标IP、端口、协议甚至时间。例如假设你的办公网络公网IP是203.0.113.100家庭网络IP是198.51.100.200你只想允许这两个地址连接SSH# 首先移除默认的、允许所有源的ssh服务规则谨慎操作 # 确保你在本地控制台或有其他备用连接方式时执行此步骤 sudo firewall-cmd --permanent --remove-servicessh # 添加富规则只允许特定IP访问22端口 sudo firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.100 service namessh accept sudo firewall-cmd --permanent --add-rich-rulerule familyipv4 source address198.51.100.200 service namessh accept # 应用更改 sudo firewall-cmd --reload # 验证富规则 sudo firewall-cmd --list-rich-rules重要警告在执行--remove-servicessh之前务必确保你已经通过其他方式如本地控制台或云平台的VNC保留了访问权限并且即将添加的允许IP地址是正确的、你当前正在使用的。否则你会立刻失去SSH连接能力这是一个常见的“自杀式”操作失误。4.4 防火墙配置的持久化与备份firewalld的永久配置存储在/etc/firewalld/目录下主要是zones/子目录里的XML文件如public.xml。--permanent参数就是修改这些文件。备份配置在对防火墙进行重大修改前备份相关区域文件是个好习惯。sudo cp /etc/firewalld/zones/public.xml /etc/firewalld/zones/public.xml.backup.$(date %Y%m%d)故障恢复如果不慎锁死了自己最快的方法是通过本地控制台登录将防火墙规则重置为默认并重载。# 在服务器本地执行 sudo firewall-cmd --set-default-zonepublic sudo firewall-cmd --reload # 或者更彻底地重启firewalld服务会中断所有网络连接瞬间 sudo systemctl restart firewalld5. SSH服务端配置强化安全与启用密钥认证防火墙配置妥当后我们开始加固SSH服务本身。主配置文件是/etc/ssh/sshd_config。修改前请先备份。sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date %Y%m%d)5.1 关键安全参数详解用文本编辑器如vim或nano打开配置文件我们需要关注并修改以下几项sudo vim /etc/ssh/sshd_config修改默认端口可选但推荐 将#Port 22的注释去掉并修改为一个大于1024的非知名端口例如2345。Port 2345为什么这么做这能有效减少自动化脚本的扫描和攻击。但请注意修改后你所有的SSH客户端连接时都需要指定端口ssh -p 2345 userhost并且别忘了在防火墙中放行这个新端口sudo firewall-cmd --permanent --add-port2345/tcp。禁用root用户直接登录 找到#PermitRootLogin yes修改为PermitRootLogin no理由即使使用密钥直接以root身份登录也是高风险行为。任何私钥泄露都意味着服务器完全沦陷。应该使用普通用户登录然后通过sudo提权。禁用密码认证启用密钥认证 这是核心步骤。PubkeyAuthentication yes # 确保此项为yes默认通常是 PasswordAuthentication no # 将此项改为no在修改此项并重启服务之前你必须已经将公钥部署到服务器对应用户的~/.ssh/authorized_keys文件中并且用密钥登录测试成功。否则你会永久失去通过SSH登录该账户的能力。其他推荐加固选项PermitEmptyPasswords no # 禁止空密码默认 ChallengeResponseAuthentication no # 禁用挑战应答认证通常与PAM相关 UsePAM yes # 如果你使用了其他PAM模块保持yes否则可考虑no以简化 # 限制最大认证尝试次数防止暴力破解即使对密钥认证也有用 MaxAuthTries 3 # 限制同时登录的会话数 MaxSessions 5 # 使用更现代的、更安全的密钥交换算法和加密算法RHEL 9默认已较好 # 可以保持默认或参考最新安全建议调整KexAlgorithms, Ciphers, MACs5.2 应用配置并测试修改完成后保存文件。在重启sshd服务前至关重要的一步是测试配置文件语法sudo sshd -t如果没有任何输出表示配置文件语法正确。如果有错误它会明确指出错误行和原因必须修正后才能继续。现在在一个保持连接的现有SSH会话中重启sshd服务。这样即使新配置有问题你还可以通过旧会话恢复。sudo systemctl restart sshd重启后不要关闭当前会话。打开一个新的终端窗口使用密钥尝试连接服务器如果改了端口记得加-p参数。确保能够成功登录。实操心得我习惯在修改sshd_config并重启服务后立即在新窗口发起连接测试。同时我会在旧的“保险”会话里用tail -f /var/log/secure命令实时查看认证日志观察新连接的尝试是成功还是被拒绝。日志是排错的最佳伙伴。6. 客户端SSH密钥对生成与部署服务器端配置好了现在轮到客户端也就是你的本地电脑生成密钥对并把公钥“送”到服务器上。6.1 生成更安全的Ed25519密钥对早期我们常用RSA算法比如ssh-keygen -t rsa -b 4096。现在更推荐使用Ed25519算法它更安全、更快并且生成的密钥更短。在你的本地机器Windows可用Git Bash或WSLmacOS和Linux直接用终端上执行ssh-keygen -t ed25519 -C your_emailexample.com -f ~/.ssh/id_ed2559_rhel9-t ed25519指定密钥类型。-C添加一个注释通常用邮箱方便标识密钥所有者。-f指定密钥文件的保存路径和名称。这里我建议起一个有意义的名字而不是覆盖默认的id_ed25519方便管理多台服务器。接下来它会提示你输入密钥的密码passphraseEnter passphrase (empty for no passphrase): Enter same passphrase again:强烈建议设置一个强密码这为你的私钥增加了第二层保护。即使私钥文件被盗没有密码也无法使用。当然这意味每次使用密钥时都需要输入密码可通过ssh-agent管理来避免每次输入。生成成功后在~/.ssh/目录下会得到两个文件id_ed2559_rhel9私钥文件。权限必须是600-rw-------且绝不能泄露给任何人。id_ed2559_rhel9.pub公钥文件。内容是一长串字符串可以放心地交给服务器。6.2 部署公钥到服务器将公钥部署到服务器用户家目录下的~/.ssh/authorized_keys文件中。有几种方法方法一使用ssh-copy-id命令最方便如果你的本地客户端也有ssh-copy-id命令且当前还能用密码登录服务器因为我们还没禁用密码那么这是最佳选择。# 如果服务器SSH端口是22 ssh-copy-id -i ~/.ssh/id_ed2559_rhel9.pub usernameserver_ip # 如果服务器修改了SSH端口比如2345 ssh-copy-id -i ~/.ssh/id_ed2559_rhel9.pub -p 2345 usernameserver_ip这个命令会自动处理目录创建、权限设置和文件追加。方法二手动复制通用方法如果ssh-copy-id不可用或者已经禁用了密码登录你需要通过其他方式如之前的SSH会话手动操作。在本地查看公钥内容cat ~/.ssh/id_ed2559_rhel9.pub复制全部输出。在服务器上登录到对应用户比如youruser确保~/.ssh目录存在且权限正确mkdir -p ~/.ssh chmod 700 ~/.ssh将复制的公钥内容追加到authorized_keys文件末尾echo “粘贴你的公钥内容” ~/.ssh/authorized_keys设置authorized_keys文件的权限chmod 600 ~/.ssh/authorized_keys权限错误是密钥登录失败的最常见原因必须保证.ssh目录权限是700authorized_keys文件权限是600。6.3 测试密钥登录公钥部署后在本地新开一个终端进行测试# 如果没改端口 ssh -i ~/.ssh/id_ed2559_rhel9 usernameserver_ip # 如果改了端口例如2345 ssh -i ~/.ssh/id_ed2559_rhel9 -p 2345 usernameserver_ip-i参数指定使用的私钥文件。第一次连接时如果私钥有密码会提示你输入。如果成功登录恭喜你现在可以回到服务器放心地将sshd_config中的PasswordAuthentication改为no并重启sshd服务了。7. 高级配置与优化技巧基础配置完成后还有一些优化技巧可以让你用得更顺手、更安全。7.1 使用SSH Config文件简化连接每次连接都要输入-i、-p、用户名和IP很麻烦。可以在本地~/.ssh/config文件中创建别名。编辑或创建~/.ssh/config文件Host rhel9-prod # 自定义一个别名 HostName 192.168.1.100 # 服务器IP或域名 Port 2345 # SSH端口 User yourusername # 登录用户名 IdentityFile ~/.ssh/id_ed2559_rhel9 # 私钥路径 # 可选禁用密码认证强制使用密钥 PasswordAuthentication no保存后以后只需要输入ssh rhel9-prod就可以连接了所有参数自动应用。7.2 配置SSH Agent管理私钥密码如果你为私钥设置了密码又不希望每次连接都输入可以使用ssh-agent。# 启动ssh-agent并设置环境变量现代桌面环境通常自动启动 eval $(ssh-agent -s) # 将私钥添加到agent ssh-add ~/.ssh/id_ed2559_rhel9 # 此时会提示输入一次私钥密码之后在当前会话中再使用该密钥就无需密码了。 # 查看已添加的密钥 ssh-add -l7.3 服务器端SSH连接日志与监控密切关注SSH日志/var/log/secure或/var/log/auth.log取决于系统可以及时发现异常。# 查看最近的失败登录尝试 sudo grep “Failed password” /var/log/secure # 查看成功的登录 sudo grep “Accepted publickey” /var/log/secure对于频繁的暴力破解尝试可以考虑使用fail2ban这类工具自动将多次失败登录的IP地址加入防火墙黑名单。8. 故障排查与常见问题实录即使按照指南操作也可能会遇到问题。这里记录了几个最常见的问题和排查思路。8.1 密钥登录失败Permission denied (publickey)这是最常遇到的问题。请按照以下顺序排查服务器端公钥文件确认公钥是否准确无误地追加到了服务器对应用户的~/.ssh/authorized_keys文件中。检查文件末尾是否有换行。文件权限这是头号杀手。在服务器上检查ls -la ~/.ssh/ # 必须保证 # .ssh 目录权限是 700 (drwx------) # authorized_keys 文件权限是 600 (-rw-------) # 文件所有者是正确的用户错误的权限如755或644会导致SSH出于安全考虑直接拒绝使用密钥。SELinux上下文如果服务器启用了SELinuxRHEL默认启用需要确保相关文件有正确的上下文。# 恢复.ssh目录的默认SELinux上下文 restorecon -Rv ~/.sshSSH服务配置确认/etc/ssh/sshd_config中PubkeyAuthentication yes没有被注释或设为no。客户端指定密钥确认连接命令使用了正确的-i参数或~/.ssh/config文件配置正确。详细日志在客户端连接时添加-vvv参数查看详细调试信息。ssh -vvv -i ~/.ssh/your_key userhost在服务器端查看/var/log/secure日志过滤你的IP地址看具体的拒绝原因。8.2 修改SSH端口后无法连接防火墙未放行新端口这是最常见的原因。务必用firewall-cmd --permanent --add-port新端口/tcp添加规则并--reload。SELinux阻止新端口SELinux默认只允许少数端口用于SSH服务。你需要告诉SELinux新端口是合法的。sudo semanage port -a -t ssh_port_t -p tcp 新端口号 # 如果提示命令不存在安装policycoreutils-python-utils包 # 检查当前SSH相关端口 sudo semanage port -l | grep ssh连接命令未指定端口客户端连接时必须使用-p 新端口参数。8.3 防火墙配置错误导致连接被拒检查默认区域确认你的网卡接口在正确的区域并且该区域允许了SSH服务或端口。sudo firewall-cmd --list-all检查富规则如果你设置了限制源IP的富规则确认当前客户端的公网IP是否在允许列表中。你的公网IP可能发生变化尤其是家庭宽带。临时放行所有流量进行测试在本地控制台可以临时将接口区域设为trusted信任所有流量来快速判断是否是防火墙问题。# 危险操作仅在测试环境或排错时短暂使用并记下原区域以便恢复。 sudo firewall-cmd --zonetrusted --change-interfaceens160 # 测试连接... # 恢复原区域 sudo firewall-cmd --zonepublic --change-interfaceens1608.4 禁用密码登录后忘记部署公钥这是最糟糕的情况你把自己锁在外面了。解决方法取决于你对服务器的物理或带外访问权限云服务器通过云服务商提供的控制台如AWS EC2的Instance Connect阿里云的VNC登录。物理服务器直接连接显示器和键盘。虚拟机通过Hypervisor的管理界面登录控制台。通过控制台登录后你可以重新编辑/etc/ssh/sshd_config将PasswordAuthentication暂时改回yes。或者直接将你的公钥手动添加到对应用户的authorized_keys文件中。然后重启sshd服务即可恢复远程访问。最后的忠告在进行任何可能断开远程连接的操作尤其是防火墙和SSH配置前永远保持一个有效的备用连接通道本地控制台、云VNC、或另一个独立的SSH会话并先进行充分的测试。安全加固的每一步都要确保自己不会把门关上。