Skip to content

RabbitMQ 网络隔离

概述

网络隔离是保护 RabbitMQ 集群安全的重要手段。通过网络层面的隔离,可以有效防止未授权访问、减少攻击面、限制故障影响范围。本文档详细介绍 RabbitMQ 网络隔离的策略和实现方法。

核心知识点

网络隔离架构

┌─────────────────────────────────────────────────────────────┐
│                    网络隔离架构图                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                      Internet                               │
│                         │                                   │
│                         ▼                                   │
│                  ┌─────────────┐                            │
│                  │   防火墙    │                            │
│                  │  Firewall   │                            │
│                  └──────┬──────┘                            │
│                         │                                   │
│         ┌───────────────┼───────────────┐                   │
│         │               │               │                   │
│         ▼               ▼               ▼                   │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐           │
│  │   DMZ 区    │ │  应用区     │ │  数据区     │           │
│  │  (公开服务)  │ │ (业务应用)  │ │ (数据存储)  │           │
│  └─────────────┘ └──────┬──────┘ └──────┬──────┘           │
│                         │               │                   │
│                         │               │                   │
│                         ▼               ▼                   │
│                  ┌─────────────────────────────┐            │
│                  │      RabbitMQ 集群          │            │
│                  │  ┌─────┐ ┌─────┐ ┌─────┐  │            │
│                  │  │Node1│ │Node2│ │Node3│  │            │
│                  │  └─────┘ └─────┘ └─────┘  │            │
│                  └─────────────────────────────┘            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

网络区域划分

区域网段访问权限说明
管理网络10.0.0.0/24管理员访问管理界面、监控
应用网络10.0.1.0/24应用服务器业务消息收发
集群网络10.0.2.0/24集群节点节点间通信
外部网络通过 NAT受限访问外部客户端

RabbitMQ 端口规划

┌─────────────────────────────────────────────────────────────┐
│                    RabbitMQ 端口规划                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  端口        服务           访问范围         网络策略        │
│  ─────────────────────────────────────────────────────────  │
│  5672        AMQP          应用网络          应用服务器      │
│  5671        AMQPS         应用网络          应用服务器      │
│  15672       Management    管理网络          管理员          │
│  15671       Management    管理网络          管理员          │
│  25672       Cluster       集群网络          集群节点        │
│  4369        EPMD          集群网络          集群节点        │
│  35672-35682 CLI           本地              本地管理        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

配置示例

绑定特定网络接口

conf
# /etc/rabbitmq/rabbitmq.conf

# 绑定 AMQP 到内网接口
listeners.tcp.default = 10.0.1.10:5672

# 绑定管理界面到管理网络
management.tcp.ip = 10.0.0.10
management.tcp.port = 15672

# 集群通信绑定到集群网络
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
cluster_formation.classic_config.nodes.1 = rabbit@10.0.2.10
cluster_formation.classic_config.nodes.2 = rabbit@10.0.2.11
cluster_formation.classic_config.nodes.3 = rabbit@10.0.2.12

多网卡配置

conf
# 多网卡环境配置
# 内网接口 - 应用访问
listeners.tcp.internal = 10.0.1.10:5672

# 外网接口 - 受限访问(需要防火墙配合)
listeners.tcp.external = 192.168.1.10:5672

# 管理 UI - 仅管理网络
management.tcp.ip = 10.0.0.10
management.tcp.port = 15672

# 禁用默认监听
listeners.tcp.default = none

Docker 网络隔离

yaml
# docker-compose.yml
version: '3.8'

networks:
  management:
    driver: bridge
    ipam:
      config:
        - subnet: 10.0.0.0/24
  application:
    driver: bridge
    ipam:
      config:
        - subnet: 10.0.1.0/24
  cluster:
    driver: bridge
    ipam:
      config:
        - subnet: 10.0.2.0/24

services:
  rabbitmq:
    image: rabbitmq:3-management
    networks:
      management:
        ipv4_address: 10.0.0.10
      application:
        ipv4_address: 10.0.1.10
      cluster:
        ipv4_address: 10.0.2.10
    ports:
      - "10.0.0.10:15672:15672"
      - "10.0.1.10:5672:5672"
    environment:
      - RABBITMQ_NODENAME=rabbit@10.0.2.10

Kubernetes 网络策略

yaml
# rabbitmq-network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: rabbitmq-network-policy
  namespace: messaging
spec:
  podSelector:
    matchLabels:
      app: rabbitmq
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # 允许应用网络访问 AMQP
    - from:
        - namespaceSelector:
            matchLabels:
              name: application
      ports:
        - protocol: TCP
          port: 5672
        - protocol: TCP
          port: 5671

    # 允许管理网络访问管理界面
    - from:
        - namespaceSelector:
            matchLabels:
              name: management
      ports:
        - protocol: TCP
          port: 15672
        - protocol: TCP
          port: 15671

    # 允许集群节点间通信
    - from:
        - podSelector:
            matchLabels:
              app: rabbitmq
      ports:
        - protocol: TCP
          port: 25672
        - protocol: TCP
          port: 4369
        - protocol: TCP
          port: 35672

  egress:
    # 允许集群节点间通信
    - to:
        - podSelector:
            matchLabels:
              app: rabbitmq
      ports:
        - protocol: TCP
          port: 25672
        - protocol: TCP
          port: 4369

PHP 代码示例

网络配置验证

php
<?php

class NetworkConfigValidator
{
    private $host;
    private $ports = [
        'amqp' => 5672,
        'amqps' => 5671,
        'management' => 15672,
        'management_ssl' => 15671,
        'cluster' => 25672,
        'epmd' => 4369
    ];

    public function __construct(string $host)
    {
        $this->host = $host;
    }

    public function checkAllPorts(): array
    {
        $results = [];

        foreach ($this->ports as $service => $port) {
            $results[$service] = $this->checkPort($port);
        }

        return $results;
    }

    public function checkPort(int $port): array
    {
        $socket = @fsockopen($this->host, $port, $errno, $errstr, 5);

        if ($socket) {
            fclose($socket);
            return [
                'open' => true,
                'port' => $port,
                'message' => "端口 {$port} 开放"
            ];
        }

        return [
            'open' => false,
            'port' => $port,
            'message' => "端口 {$port} 关闭或被过滤: {$errstr}"
        ];
    }

    public function checkFromNetwork(string $sourceIp): array
    {
        $originalHost = $this->host;
        $this->host = $sourceIp;
        $result = $this->checkAllPorts();
        $this->host = $originalHost;

        return $result;
    }

    public function validateNetworkIsolation(): array
    {
        $issues = [];

        $publicPorts = $this->checkPublicAccess();
        if (!empty($publicPorts)) {
            $issues[] = [
                'severity' => 'high',
                'issue' => '管理端口可从公网访问',
                'ports' => $publicPorts
            ];
        }

        return [
            'is_isolated' => empty($issues),
            'issues' => $issues
        ];
    }

    private function checkPublicAccess(): array
    {
        $exposedPorts = [];

        $managementPorts = [15672, 15671];
        foreach ($managementPorts as $port) {
            if ($this->isPubliclyAccessible($port)) {
                $exposedPorts[] = $port;
            }
        }

        return $exposedPorts;
    }

    private function isPubliclyAccessible(int $port): bool
    {
        return false;
    }

    public function generateReport(): string
    {
        $results = $this->checkAllPorts();

        $report = "# RabbitMQ 网络配置报告\n\n";
        $report .= "主机: {$this->host}\n";
        $report .= "检查时间: " . date('Y-m-d H:i:s') . "\n\n";

        $report .= "## 端口状态\n\n";
        $report .= "| 服务 | 端口 | 状态 |\n";
        $report .= "|------|------|------|\n";

        foreach ($results as $service => $result) {
            $status = $result['open'] ? '✅ 开放' : '❌ 关闭';
            $report .= "| {$service} | {$result['port']} | {$status} |\n";
        }

        return $report;
    }
}

// 使用示例
$validator = new NetworkConfigValidator('rabbitmq.example.com');
$results = $validator->checkAllPorts();
print_r($results);

echo $validator->generateReport();

网络隔离管理器

php
<?php

class NetworkIsolationManager
{
    private $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }

    public function configureFirewall(): array
    {
        $rules = [];

        $rules[] = $this->createRule('allow_cluster', [
            'source' => $this->config['cluster_network'],
            'dest_port' => [25672, 4369],
            'action' => 'ACCEPT'
        ]);

        $rules[] = $this->createRule('allow_application', [
            'source' => $this->config['application_network'],
            'dest_port' => [5672, 5671],
            'action' => 'ACCEPT'
        ]);

        $rules[] = $this->createRule('allow_management', [
            'source' => $this->config['management_network'],
            'dest_port' => [15672, 15671],
            'action' => 'ACCEPT'
        ]);

        $rules[] = $this->createRule('deny_all', [
            'source' => '0.0.0.0/0',
            'dest_port' => 'all',
            'action' => 'DROP'
        ]);

        return $rules;
    }

    private function createRule(string $name, array $params): array
    {
        return [
            'name' => $name,
            'source' => $params['source'],
            'dest_port' => $params['dest_port'],
            'action' => $params['action'],
            'created_at' => date('c')
        ];
    }

    public function generateIptablesScript(): string
    {
        $rules = $this->configureFirewall();
        $script = "#!/bin/bash\n\n";
        $script .= "# RabbitMQ 防火墙规则\n";
        $script .= "# 生成时间: " . date('Y-m-d H:i:s') . "\n\n";

        $script .= "# 清除现有规则\n";
        $script .= "iptables -F\n\n";

        foreach ($rules as $rule) {
            if ($rule['dest_port'] === 'all') {
                $script .= "iptables -A INPUT -s {$rule['source']} -j {$rule['action']}\n";
            } else {
                foreach ((array)$rule['dest_port'] as $port) {
                    $script .= "iptables -A INPUT -s {$rule['source']} -p tcp --dport {$port} -j {$rule['action']}\n";
                }
            }
        }

        return $script;
    }

    public function generateFirewalldScript(): string
    {
        $rules = $this->configureFirewall();
        $script = "#!/bin/bash\n\n";
        $script .= "# RabbitMQ firewalld 规则\n";
        $script .= "# 生成时间: " . date('Y-m-d H:i:s') . "\n\n";

        foreach ($rules as $rule) {
            if ($rule['name'] === 'allow_cluster') {
                foreach ((array)$rule['dest_port'] as $port) {
                    $script .= "firewall-cmd --permanent --zone=trusted --add-source={$rule['source']}\n";
                    $script .= "firewall-cmd --permanent --zone=trusted --add-port={$port}/tcp\n";
                }
            } elseif ($rule['name'] === 'allow_application') {
                foreach ((array)$rule['dest_port'] as $port) {
                    $script .= "firewall-cmd --permanent --zone=internal --add-source={$rule['source']}\n";
                    $script .= "firewall-cmd --permanent --zone=internal --add-port={$port}/tcp\n";
                }
            } elseif ($rule['name'] === 'allow_management') {
                foreach ((array)$rule['dest_port'] as $port) {
                    $script .= "firewall-cmd --permanent --zone=internal --add-source={$rule['source']}\n";
                    $script .= "firewall-cmd --permanent --zone=internal --add-port={$port}/tcp\n";
                }
            }
        }

        $script .= "\nfirewall-cmd --reload\n";

        return $script;
    }
}

// 使用示例
$manager = new NetworkIsolationManager([
    'cluster_network' => '10.0.2.0/24',
    'application_network' => '10.0.1.0/24',
    'management_network' => '10.0.0.0/24'
]);

echo $manager->generateIptablesScript();

多网络接口连接

php
<?php

use PhpAmqpLib\Connection\AMQPStreamConnection;

class MultiNetworkConnection
{
    private $networks;

    public function __construct(array $networks)
    {
        $this->networks = $networks;
    }

    public function connect(string $networkName = 'application'): ?AMQPStreamConnection
    {
        if (!isset($this->networks[$networkName])) {
            throw new InvalidArgumentException("网络配置不存在: {$networkName}");
        }

        $config = $this->networks[$networkName];

        try {
            return new AMQPStreamConnection(
                $config['host'],
                $config['port'],
                $config['username'],
                $config['password'],
                $config['vhost'] ?? '/',
                false,
                'AMQPLAIN',
                null,
                'en_US',
                $config['connection_timeout'] ?? 3.0,
                $config['read_write_timeout'] ?? 3.0
            );
        } catch (Exception $e) {
            error_log("连接 {$networkName} 网络失败: " . $e->getMessage());
            return null;
        }
    }

    public function connectWithFailover(array $preferredOrder = ['application', 'management']): ?AMQPStreamConnection
    {
        foreach ($preferredOrder as $network) {
            $connection = $this->connect($network);
            if ($connection) {
                return $connection;
            }
        }

        throw new RuntimeException("所有网络连接均失败");
    }

    public function testAllNetworks(): array
    {
        $results = [];

        foreach ($this->networks as $name => $config) {
            $results[$name] = $this->testNetwork($name);
        }

        return $results;
    }

    private function testNetwork(string $name): array
    {
        $config = $this->networks[$name];
        $start = microtime(true);

        try {
            $connection = $this->connect($name);
            $connected = $connection && $connection->isConnected();

            if ($connection) {
                $connection->close();
            }

            return [
                'name' => $name,
                'host' => $config['host'],
                'port' => $config['port'],
                'connected' => $connected,
                'latency_ms' => round((microtime(true) - $start) * 1000, 2)
            ];
        } catch (Exception $e) {
            return [
                'name' => $name,
                'host' => $config['host'],
                'port' => $config['port'],
                'connected' => false,
                'error' => $e->getMessage(),
                'latency_ms' => round((microtime(true) - $start) * 1000, 2)
            ];
        }
    }
}

// 使用示例
$multiNet = new MultiNetworkConnection([
    'application' => [
        'host' => '10.0.1.10',
        'port' => 5672,
        'username' => 'app_user',
        'password' => 'password',
        'vhost' => '/app'
    ],
    'management' => [
        'host' => '10.0.0.10',
        'port' => 5672,
        'username' => 'admin',
        'password' => 'admin_password',
        'vhost' => '/'
    ]
]);

$connection = $multiNet->connect('application');
$testResults = $multiNet->testAllNetworks();
print_r($testResults);

实际应用场景

场景一:生产环境网络架构

php
<?php

class ProductionNetworkSetup
{
    private $networks = [
        'management' => [
            'cidr' => '10.0.0.0/24',
            'description' => '管理网络 - 管理员访问'
        ],
        'application' => [
            'cidr' => '10.0.1.0/24',
            'description' => '应用网络 - 业务应用'
        ],
        'cluster' => [
            'cidr' => '10.0.2.0/24',
            'description' => '集群网络 - 节点通信'
        ],
        'monitoring' => [
            'cidr' => '10.0.3.0/24',
            'description' => '监控网络 - 监控系统'
        ]
    ];

    public function generateNetworkConfig(): array
    {
        return [
            'rabbitmq' => [
                'listeners' => [
                    'amqp' => [
                        'interface' => '10.0.1.10',
                        'port' => 5672,
                        'allowed_sources' => ['10.0.1.0/24']
                    ],
                    'amqps' => [
                        'interface' => '10.0.1.10',
                        'port' => 5671,
                        'allowed_sources' => ['10.0.1.0/24']
                    ],
                    'management' => [
                        'interface' => '10.0.0.10',
                        'port' => 15672,
                        'allowed_sources' => ['10.0.0.0/24']
                    ],
                    'cluster' => [
                        'interface' => '10.0.2.10',
                        'port' => 25672,
                        'allowed_sources' => ['10.0.2.0/24']
                    ]
                ]
            ]
        ];
    }
}

场景二:跨数据中心网络隔离

php
<?php

class CrossDatacenterNetwork
{
    private $datacenters;

    public function __construct(array $datacenters)
    {
        $this->datacenters = $datacenters;
    }

    public function getFederationConfig(): array
    {
        $config = [];

        foreach ($this->datacenters as $dcName => $dcConfig) {
            $config[$dcName] = [
                'upstream' => $dcConfig['upstream'],
                'uri' => "amqps://{$dcConfig['host']}:5671",
                'network' => $dcConfig['network']
            ];
        }

        return $config;
    }
}

常见问题与解决方案

问题 1:无法从应用网络连接

解决方案

bash
# 检查监听地址
netstat -tlnp | grep beam

# 检查防火墙规则
iptables -L -n | grep 5672

# 确认绑定到正确的接口
# rabbitmq.conf
listeners.tcp.default = 10.0.1.10:5672

问题 2:集群节点无法通信

解决方案

bash
# 检查 EPMD
epmd -names

# 检查集群端口
telnet <node-ip> 25672

# 检查防火墙
iptables -L -n | grep 25672

最佳实践建议

1. 网络分段清单

php
<?php

class NetworkSegmentationChecklist
{
    public function validate(array $config): array
    {
        $checks = [
            'management_isolated' => $this->checkManagementIsolated($config),
            'cluster_isolated' => $this->checkClusterIsolated($config),
            'application_limited' => $this->checkApplicationLimited($config),
            'no_public_access' => $this->checkNoPublicAccess($config)
        ];

        return [
            'passed' => !in_array(false, $checks, true),
            'checks' => $checks
        ];
    }

    private function checkManagementIsolated(array $config): bool
    {
        return isset($config['management_network']) &&
               $config['management_network'] !== '0.0.0.0/0';
    }

    private function checkClusterIsolated(array $config): bool
    {
        return isset($config['cluster_network']) &&
               strpos($config['cluster_network'], '10.') === 0;
    }

    private function checkApplicationLimited(array $config): bool
    {
        return isset($config['application_network']) &&
               $config['application_network'] !== '0.0.0.0/0';
    }

    private function checkNoPublicAccess(array $config): bool
    {
        foreach (['management', 'cluster'] as $network) {
            if (($config[$network . '_network'] ?? '') === '0.0.0.0/0') {
                return false;
            }
        }
        return true;
    }
}

安全注意事项

重要警告

  1. 管理端口隔离:管理界面绝不能暴露到公网
  2. 集群端口限制:集群端口仅允许节点间访问
  3. 默认拒绝策略:防火墙采用默认拒绝策略
  4. 定期审计:定期检查网络配置和防火墙规则
  5. 监控告警:监控异常的网络连接

相关链接