Appearance
RabbitMQ 防火墙配置
概述
防火墙是保护 RabbitMQ 服务器的第一道防线。正确配置防火墙规则可以有效阻止未授权访问、限制攻击面、保护敏感端口。本文档详细介绍 RabbitMQ 防火墙配置的最佳实践。
核心知识点
RabbitMQ 端口清单
┌─────────────────────────────────────────────────────────────┐
│ RabbitMQ 端口清单 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 端口 协议/服务 用途 访问策略 │
│ ───────────────────────────────────────────────────────── │
│ 4369 EPMD 节点发现 仅集群节点 │
│ 5672 AMQP 消息队列 应用服务器 │
│ 5671 AMQPS 加密消息队列 应用服务器 │
│ 15672 Management 管理界面(HTTP) 管理网络 │
│ 15671 Management 管理界面(HTTPS) 管理网络 │
│ 25672 Cluster 集群通信 仅集群节点 │
│ 35672 CLI 命令行工具 本地 │
│ 61613 STOMP STOMP 协议 应用服务器 │
│ 61614 STOMPS 加密 STOMP 应用服务器 │
│ 1883 MQTT MQTT 协议 IoT 设备 │
│ 8883 MQTTS 加密 MQTT IoT 设备 │
│ │
└─────────────────────────────────────────────────────────────┘防火墙策略原则
┌─────────────────────────────────────────────────────────────┐
│ 防火墙策略原则 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 默认拒绝原则 │
│ └── 默认拒绝所有入站连接,仅允许必要的端口 │
│ │
│ 2. 最小权限原则 │
│ └── 仅开放必需的端口,限制源 IP 范围 │
│ │
│ 3. 分层防护原则 │
│ └── 网络防火墙 + 主机防火墙双重防护 │
│ │
│ 4. 纵深防御原则 │
│ └── 防火墙 + TLS + 认证 多层安全 │
│ │
│ 5. 审计日志原则 │
│ └── 记录所有防火墙事件,便于审计和排查 │
│ │
└─────────────────────────────────────────────────────────────┘防火墙工具对比
| 工具 | 适用系统 | 特点 | 推荐场景 |
|---|---|---|---|
| iptables | Linux | 底层工具,灵活强大 | 高级配置 |
| firewalld | RHEL/CentOS | 动态管理,区域概念 | 企业环境 |
| ufw | Ubuntu | 简单易用 | 快速部署 |
| nftables | Linux | 新一代防火墙 | 现代系统 |
配置示例
iptables 配置
bash
#!/bin/bash
# /etc/iptables/rabbitmq-rules.sh
# 清除现有规则
iptables -F
iptables -X
# 设置默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# 允许本地回环
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# 允许已建立的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许 SSH(管理用)
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/24 -j ACCEPT
# 集群节点通信 - EPMD
iptables -A INPUT -p tcp --dport 4369 -s 10.0.2.0/24 -j ACCEPT
# 集群节点通信 - Cluster
iptables -A INPUT -p tcp --dport 25672 -s 10.0.2.0/24 -j ACCEPT
# 集群节点通信 - CLI 范围
iptables -A INPUT -p tcp --dport 35672:35682 -s 10.0.2.0/24 -j ACCEPT
# 应用访问 - AMQP
iptables -A INPUT -p tcp --dport 5672 -s 10.0.1.0/24 -j ACCEPT
# 应用访问 - AMQPS
iptables -A INPUT -p tcp --dport 5671 -s 10.0.1.0/24 -j ACCEPT
# 管理界面 - HTTP
iptables -A INPUT -p tcp --dport 15672 -s 10.0.0.0/24 -j ACCEPT
# 管理界面 - HTTPS
iptables -A INPUT -p tcp --dport 15671 -s 10.0.0.0/24 -j ACCEPT
# 监控访问(如需要)
iptables -A INPUT -p tcp --dport 15692 -s 10.0.3.0/24 -j ACCEPT
# 记录被拒绝的连接
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
# 保存规则
# Debian/Ubuntu: iptables-save > /etc/iptables/rules.v4
# RHEL/CentOS: service iptables savefirewalld 配置
bash
#!/bin/bash
# firewalld 配置脚本
# 创建自定义区域
firewall-cmd --permanent --new-zone=rabbitmq_cluster
firewall-cmd --permanent --new-zone=rabbitmq_application
firewall-cmd --permanent --new-zone=rabbitmq_management
# 集群区域配置
firewall-cmd --permanent --zone=rabbitmq_cluster --add-source=10.0.2.0/24
firewall-cmd --permanent --zone=rabbitmq_cluster --add-port=4369/tcp
firewall-cmd --permanent --zone=rabbitmq_cluster --add-port=25672/tcp
firewall-cmd --permanent --zone=rabbitmq_cluster --add-port=35672-35682/tcp
# 应用区域配置
firewall-cmd --permanent --zone=rabbitmq_application --add-source=10.0.1.0/24
firewall-cmd --permanent --zone=rabbitmq_application --add-port=5672/tcp
firewall-cmd --permanent --zone=rabbitmq_application --add-port=5671/tcp
# 管理区域配置
firewall-cmd --permanent --zone=rabbitmq_management --add-source=10.0.0.0/24
firewall-cmd --permanent --zone=rabbitmq_management --add-port=15672/tcp
firewall-cmd --permanent --zone=rabbitmq_management --add-port=15671/tcp
# 重载配置
firewall-cmd --reload
# 查看配置
firewall-cmd --list-all-zonesUFW 配置 (Ubuntu)
bash
#!/bin/bash
# UFW 配置脚本
# 重置 UFW
ufw --force reset
# 设置默认策略
ufw default deny incoming
ufw default allow outgoing
# 允许 SSH
ufw allow from 10.0.0.0/24 to any port 22 proto tcp
# 集群通信
ufw allow from 10.0.2.0/24 to any port 4369 proto tcp comment 'EPMD'
ufw allow from 10.0.2.0/24 to any port 25672 proto tcp comment 'Cluster'
# 应用访问
ufw allow from 10.0.1.0/24 to any port 5672 proto tcp comment 'AMQP'
ufw allow from 10.0.1.0/24 to any port 5671 proto tcp comment 'AMQPS'
# 管理界面
ufw allow from 10.0.0.0/24 to any port 15672 proto tcp comment 'Management HTTP'
ufw allow from 10.0.0.0/24 to any port 15671 proto tcp comment 'Management HTTPS'
# 启用 UFW
ufw --force enable
# 查看状态
ufw status numberednftables 配置
bash
#!/usr/sbin/nft -f
# /etc/nftables.conf
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# 允许本地回环
iif lo accept
# 允许已建立的连接
ct state established,related accept
# 无效连接丢弃
ct state invalid drop
# ICMP
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
# SSH
tcp dport 22 ip saddr 10.0.0.0/24 accept
# 集群通信
tcp dport { 4369, 25672 } ip saddr 10.0.2.0/24 accept
tcp dport 35672-35682 ip saddr 10.0.2.0/24 accept
# 应用访问
tcp dport { 5672, 5671 } ip saddr 10.0.1.0/24 accept
# 管理界面
tcp dport { 15672, 15671 } ip saddr 10.0.0.0/24 accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}PHP 代码示例
防火墙规则生成器
php
<?php
class FirewallRuleGenerator
{
private $config;
private $tool;
public function __construct(array $config, string $tool = 'iptables')
{
$this->config = $config;
$this->tool = $tool;
}
public function generate(): string
{
switch ($this->tool) {
case 'iptables':
return $this->generateIptables();
case 'firewalld':
return $this->generateFirewalld();
case 'ufw':
return $this->generateUfw();
case 'nftables':
return $this->generateNftables();
default:
throw new InvalidArgumentException("不支持的防火墙工具: {$this->tool}");
}
}
private function generateIptables(): string
{
$script = "#!/bin/bash\n";
$script .= "# RabbitMQ iptables 规则\n";
$script .= "# 生成时间: " . date('Y-m-d H:i:s') . "\n\n";
$script .= "# 清除现有规则\n";
$script .= "iptables -F\n";
$script .= "iptables -X\n\n";
$script .= "# 设置默认策略\n";
$script .= "iptables -P INPUT DROP\n";
$script .= "iptables -P FORWARD DROP\n";
$script .= "iptables -P OUTPUT ACCEPT\n\n";
$script .= "# 允许本地回环\n";
$script .= "iptables -A INPUT -i lo -j ACCEPT\n\n";
$script .= "# 允许已建立的连接\n";
$script .= "iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT\n\n";
foreach ($this->config['rules'] as $rule) {
$script .= "# {$rule['description']}\n";
foreach ($rule['ports'] as $port) {
$portStr = is_array($port) ? "{$port[0]}:{$port[1]}" : $port;
$script .= "iptables -A INPUT -p tcp --dport {$portStr} -s {$rule['source']} -j ACCEPT\n";
}
$script .= "\n";
}
$script .= "# 记录被拒绝的连接\n";
$script .= "iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix \"Dropped: \" --log-level 4\n";
return $script;
}
private function generateFirewalld(): string
{
$script = "#!/bin/bash\n";
$script .= "# RabbitMQ firewalld 规则\n";
$script .= "# 生成时间: " . date('Y-m-d H:i:s') . "\n\n";
foreach ($this->config['rules'] as $name => $rule) {
$zoneName = "rabbitmq_{$name}";
$script .= "# {$rule['description']}\n";
$script .= "firewall-cmd --permanent --new-zone={$zoneName}\n";
$script .= "firewall-cmd --permanent --zone={$zoneName} --add-source={$rule['source']}\n";
foreach ($rule['ports'] as $port) {
$portStr = is_array($port) ? "{$port[0]}-{$port[1]}" : $port;
$script .= "firewall-cmd --permanent --zone={$zoneName} --add-port={$portStr}/tcp\n";
}
$script .= "\n";
}
$script .= "# 重载配置\n";
$script .= "firewall-cmd --reload\n";
return $script;
}
private function generateUfw(): string
{
$script = "#!/bin/bash\n";
$script .= "# RabbitMQ UFW 规则\n";
$script .= "# 生成时间: " . date('Y-m-d H:i:s') . "\n\n";
$script .= "# 重置 UFW\n";
$script .= "ufw --force reset\n\n";
$script .= "# 设置默认策略\n";
$script .= "ufw default deny incoming\n";
$script .= "ufw default allow outgoing\n\n";
foreach ($this->config['rules'] as $rule) {
$script .= "# {$rule['description']}\n";
foreach ($rule['ports'] as $port) {
$portStr = is_array($port) ? "{$port[0]}:{$port[1]}" : $port;
$script .= "ufw allow from {$rule['source']} to any port {$portStr} proto tcp comment '{$rule['description']}'\n";
}
$script .= "\n";
}
$script .= "# 启用 UFW\n";
$script .= "ufw --force enable\n";
return $script;
}
private function generateNftables(): string
{
$script = "#!/usr/sbin/nft -f\n";
$script .= "# RabbitMQ nftables 规则\n";
$script .= "# 生成时间: " . date('Y-m-d H:i:s') . "\n\n";
$script .= "table inet filter {\n";
$script .= " chain input {\n";
$script .= " type filter hook input priority 0; policy drop;\n\n";
$script .= " # 允许本地回环\n";
$script .= " iif lo accept\n\n";
$script .= " # 允许已建立的连接\n";
$script .= " ct state established,related accept\n\n";
foreach ($this->config['rules'] as $rule) {
$script .= " # {$rule['description']}\n";
$ports = [];
foreach ($rule['ports'] as $port) {
if (is_array($port)) {
$ports[] = "{$port[0]}-{$port[1]}";
} else {
$ports[] = $port;
}
}
$portsStr = implode(', ', $ports);
$script .= " tcp dport { {$portsStr} } ip saddr {$rule['source']} accept\n\n";
}
$script .= " }\n\n";
$script .= " chain forward {\n";
$script .= " type filter hook forward priority 0; policy drop;\n";
$script .= " }\n\n";
$script .= " chain output {\n";
$script .= " type filter hook output priority 0; policy accept;\n";
$script .= " }\n";
$script .= "}\n";
return $script;
}
}
// 使用示例
$generator = new FirewallRuleGenerator([
'rules' => [
'cluster' => [
'source' => '10.0.2.0/24',
'ports' => [4369, 25672, [35672, 35682]],
'description' => '集群节点通信'
],
'application' => [
'source' => '10.0.1.0/24',
'ports' => [5672, 5671],
'description' => '应用访问'
],
'management' => [
'source' => '10.0.0.0/24',
'ports' => [15672, 15671],
'description' => '管理界面'
]
]
], 'iptables');
echo $generator->generate();防火墙状态检查器
php
<?php
class FirewallStatusChecker
{
private $host;
public function __construct(string $host = 'localhost')
{
$this->host = $host;
}
public function checkPortAccess(int $port, string $sourceIp = '127.0.0.1'): array
{
$socket = @fsockopen($this->host, $port, $errno, $errstr, 5);
return [
'port' => $port,
'accessible' => $socket !== false,
'error' => $socket === false ? $errstr : null
];
}
public function checkAllPorts(): array
{
$ports = [
'AMQP' => 5672,
'AMQPS' => 5671,
'Management HTTP' => 15672,
'Management HTTPS' => 15671,
'Cluster' => 25672,
'EPMD' => 4369
];
$results = [];
foreach ($ports as $name => $port) {
$results[$name] = $this->checkPortAccess($port);
}
return $results;
}
public function validateRules(array $expectedRules): array
{
$issues = [];
foreach ($expectedRules as $rule) {
$check = $this->checkPortAccess($rule['port']);
if ($check['accessible'] && !$rule['should_be_open']) {
$issues[] = [
'severity' => 'high',
'port' => $rule['port'],
'issue' => "端口 {$rule['port']} 不应该对外开放"
];
}
if (!$check['accessible'] && $rule['should_be_open']) {
$issues[] = [
'severity' => 'medium',
'port' => $rule['port'],
'issue' => "端口 {$rule['port']} 应该开放但被阻止"
];
}
}
return [
'valid' => empty($issues),
'issues' => $issues
];
}
public function generateReport(): string
{
$results = $this->checkAllPorts();
$report = "# RabbitMQ 防火墙状态报告\n\n";
$report .= "检查时间: " . date('Y-m-d H:i:s') . "\n\n";
$report .= "## 端口状态\n\n";
$report .= "| 服务 | 端口 | 状态 |\n";
$report .= "|------|------|------|\n";
foreach ($results as $name => $result) {
$status = $result['accessible'] ? '✅ 开放' : '❌ 关闭';
$report .= "| {$name} | {$result['port']} | {$status} |\n";
}
return $report;
}
}
// 使用示例
$checker = new FirewallStatusChecker('rabbitmq.example.com');
echo $checker->generateReport();防火墙规则审计
php
<?php
class FirewallAuditor
{
public function auditIptablesRules(string $rulesOutput): array
{
$issues = [];
$lines = explode("\n", $rulesOutput);
$hasDefaultDrop = false;
$managementExposed = false;
foreach ($lines as $line) {
if (preg_match('/-P INPUT (DROP|ACCEPT)/', $line, $matches)) {
$hasDefaultDrop = $matches[1] === 'DROP';
}
if (preg_match('/--dport 15672/', $line) && !preg_match('/-s \d+\.\d+\.\d+\.\d+/', $line)) {
$managementExposed = true;
}
}
if (!$hasDefaultDrop) {
$issues[] = [
'severity' => 'high',
'issue' => '默认 INPUT 策略不是 DROP'
];
}
if ($managementExposed) {
$issues[] = [
'severity' => 'critical',
'issue' => '管理端口 15672 对所有 IP 开放'
];
}
return [
'passed' => empty($issues),
'issues' => $issues
];
}
public function generateAuditReport(string $rulesOutput): string
{
$audit = $this->auditIptablesRules($rulesOutput);
$report = "# 防火墙审计报告\n\n";
$report .= "审计时间: " . date('Y-m-d H:i:s') . "\n\n";
if ($audit['passed']) {
$report .= "## 审计结果: ✅ 通过\n\n";
} else {
$report .= "## 审计结果: ❌ 未通过\n\n";
$report .= "### 发现的问题\n\n";
foreach ($audit['issues'] as $issue) {
$report .= "- **[{$issue['severity']}]** {$issue['issue']}\n";
}
}
return $report;
}
}实际应用场景
场景一:生产环境防火墙配置
php
<?php
class ProductionFirewallSetup
{
public function generateConfig(): array
{
return [
'rules' => [
'cluster' => [
'source' => '10.0.2.0/24',
'ports' => [4369, 25672, [35672, 35682]],
'description' => '集群节点通信'
],
'application' => [
'source' => '10.0.1.0/24',
'ports' => [5672, 5671],
'description' => '应用访问 AMQP'
],
'management' => [
'source' => '10.0.0.0/24',
'ports' => [15672, 15671],
'description' => '管理界面'
],
'monitoring' => [
'source' => '10.0.3.0/24',
'ports' => [15692],
'description' => 'Prometheus 监控'
],
'ssh' => [
'source' => '10.0.0.0/24',
'ports' => [22],
'description' => 'SSH 管理'
]
]
];
}
}场景二:多环境防火墙管理
php
<?php
class MultiEnvironmentFirewall
{
private $environments = [
'development' => [
'cluster_source' => '0.0.0.0/0',
'application_source' => '0.0.0.0/0',
'management_source' => '0.0.0.0/0'
],
'staging' => [
'cluster_source' => '10.10.2.0/24',
'application_source' => '10.10.1.0/24',
'management_source' => '10.10.0.0/24'
],
'production' => [
'cluster_source' => '10.0.2.0/24',
'application_source' => '10.0.1.0/24',
'management_source' => '10.0.0.0/24'
]
];
public function generateForEnvironment(string $env): string
{
if (!isset($this->environments[$env])) {
throw new InvalidArgumentException("环境不存在: {$env}");
}
$config = $this->environments[$env];
$generator = new FirewallRuleGenerator([
'rules' => [
'cluster' => [
'source' => $config['cluster_source'],
'ports' => [4369, 25672],
'description' => '集群通信'
],
'application' => [
'source' => $config['application_source'],
'ports' => [5672, 5671],
'description' => '应用访问'
],
'management' => [
'source' => $config['management_source'],
'ports' => [15672, 15671],
'description' => '管理界面'
]
]
], 'iptables');
return $generator->generate();
}
}常见问题与解决方案
问题 1:防火墙规则不生效
解决方案:
bash
# 检查规则是否正确加载
iptables -L -n -v
# 检查规则顺序(规则按顺序匹配)
iptables -L -n --line-numbers
# 确保规则持久化
# Ubuntu
netfilter-persistent save
# CentOS
service iptables save问题 2:管理界面无法访问
解决方案:
bash
# 检查端口是否开放
telnet localhost 15672
# 检查 RabbitMQ 是否监听
netstat -tlnp | grep 15672
# 添加防火墙规则
iptables -I INPUT -p tcp --dport 15672 -s 10.0.0.0/24 -j ACCEPT问题 3:集群节点无法通信
解决方案:
bash
# 检查 EPMD 端口
telnet <node-ip> 4369
# 检查集群端口
telnet <node-ip> 25672
# 添加集群规则
iptables -I INPUT -p tcp --dport 4369 -s 10.0.2.0/24 -j ACCEPT
iptables -I INPUT -p tcp --dport 25672 -s 10.0.2.0/24 -j ACCEPT最佳实践建议
1. 防火墙配置清单
php
<?php
class FirewallChecklist
{
public function validate(array $config): array
{
$checks = [
'default_deny' => $this->checkDefaultDeny($config),
'management_restricted' => $this->checkManagementRestricted($config),
'cluster_restricted' => $this->checkClusterRestricted($config),
'ssh_restricted' => $this->checkSSHRestricted($config),
'logging_enabled' => $this->checkLoggingEnabled($config)
];
return [
'passed' => !in_array(false, $checks, true),
'checks' => $checks
];
}
private function checkDefaultDeny(array $config): bool
{
return ($config['default_policy'] ?? '') === 'DROP';
}
private function checkManagementRestricted(array $config): bool
{
foreach ($config['rules'] ?? [] as $rule) {
if (in_array(15672, (array)$rule['ports'])) {
return $rule['source'] !== '0.0.0.0/0';
}
}
return true;
}
private function checkClusterRestricted(array $config): bool
{
foreach ($config['rules'] ?? [] as $rule) {
if (in_array(25672, (array)$rule['ports'])) {
return strpos($rule['source'], '10.') === 0 ||
strpos($rule['source'], '192.168.') === 0 ||
strpos($rule['source'], '172.') === 0;
}
}
return true;
}
private function checkSSHRestricted(array $config): bool
{
foreach ($config['rules'] ?? [] as $rule) {
if (in_array(22, (array)$rule['ports'])) {
return $rule['source'] !== '0.0.0.0/0';
}
}
return true;
}
private function checkLoggingEnabled(array $config): bool
{
return $config['logging_enabled'] ?? false;
}
}安全注意事项
重要警告
- 默认拒绝策略:始终使用默认 DROP 策略
- 管理端口限制:管理界面端口绝不能对公网开放
- 规则持久化:确保防火墙规则重启后仍然生效
- 定期审计:定期检查防火墙规则是否被修改
- 日志记录:启用防火墙日志记录便于审计
