Skip to content

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. 审计日志原则                                            │
│     └── 记录所有防火墙事件,便于审计和排查                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

防火墙工具对比

工具适用系统特点推荐场景
iptablesLinux底层工具,灵活强大高级配置
firewalldRHEL/CentOS动态管理,区域概念企业环境
ufwUbuntu简单易用快速部署
nftablesLinux新一代防火墙现代系统

配置示例

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 save

firewalld 配置

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-zones

UFW 配置 (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 numbered

nftables 配置

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;
    }
}

安全注意事项

重要警告

  1. 默认拒绝策略:始终使用默认 DROP 策略
  2. 管理端口限制:管理界面端口绝不能对公网开放
  3. 规则持久化:确保防火墙规则重启后仍然生效
  4. 定期审计:定期检查防火墙规则是否被修改
  5. 日志记录:启用防火墙日志记录便于审计

相关链接